2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
40 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
41 static BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
42 static BOOL (WINAPI
*pGetCharABCWidthsA
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
43 static BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
44 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
45 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
46 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
47 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
48 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDV
*);
49 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
50 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
51 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
52 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
54 static HMODULE hgdi32
= 0;
55 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
57 static void init(void)
59 hgdi32
= GetModuleHandleA("gdi32.dll");
61 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
62 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
63 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
64 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
65 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
66 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
67 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
68 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
69 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
70 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
71 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
72 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
73 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
74 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
77 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
79 if (type
!= TRUETYPE_FONTTYPE
) return 1;
84 static BOOL
is_truetype_font_installed(const char *name
)
89 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
96 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
101 static BOOL
is_font_installed(const char *name
)
106 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
113 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
121 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
122 /* NT4 tries to be clever and only returns the minimum length */
123 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
125 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
126 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
127 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
128 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
129 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
130 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
131 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
132 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
133 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
134 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
135 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
136 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
137 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
138 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
139 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
140 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
141 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
142 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
143 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
144 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
145 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
146 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
147 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
148 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
149 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
150 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
151 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
152 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
155 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
157 HFONT hfont
= CreateFontIndirectA(lf
);
158 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
160 check_font(test
, lf
, hfont
);
164 static void test_logfont(void)
169 memset(&lf
, 0, sizeof lf
);
171 lf
.lfCharSet
= ANSI_CHARSET
;
172 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
173 lf
.lfWeight
= FW_DONTCARE
;
176 lf
.lfQuality
= DEFAULT_QUALITY
;
178 lstrcpyA(lf
.lfFaceName
, "Arial");
179 hfont
= create_font("Arial", &lf
);
182 memset(&lf
, 'A', sizeof(lf
));
183 hfont
= CreateFontIndirectA(&lf
);
184 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
186 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
187 check_font("AAA...", &lf
, hfont
);
191 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
193 if (type
& RASTER_FONTTYPE
)
195 LOGFONT
*lf
= (LOGFONT
*)lParam
;
197 return 0; /* stop enumeration */
200 return 1; /* continue enumeration */
203 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
205 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
206 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
207 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
208 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
209 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
210 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
211 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
212 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
213 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
214 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
215 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
216 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
217 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
218 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
219 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
220 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
221 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
222 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
223 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
224 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
227 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
228 LONG lfWidth
, const char *test_str
,
229 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
230 const SIZE
*size_orig
, INT width_of_A_orig
,
231 INT scale_x
, INT scale_y
)
234 OUTLINETEXTMETRIC otm
;
237 INT width_of_A
, cx
, cy
;
243 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
245 GetObjectA(hfont
, sizeof(lf
), &lf
);
247 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
249 otm
.otmSize
= sizeof(otm
) / 2;
250 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
251 ok(ret
== sizeof(otm
)/2 /* XP */ ||
252 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
254 memset(&otm
, 0x1, sizeof(otm
));
255 otm
.otmSize
= sizeof(otm
);
256 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
257 ok(ret
== sizeof(otm
) /* XP */ ||
258 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
260 memset(&tm
, 0x2, sizeof(tm
));
261 ret
= GetTextMetricsA(hdc
, &tm
);
262 ok(ret
, "GetTextMetricsA failed\n");
263 /* the structure size is aligned */
264 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
266 ok(0, "tm != otm\n");
267 compare_tm(&tm
, &otm
.otmTextMetrics
);
270 tm
= otm
.otmTextMetrics
;
271 if (0) /* these metrics are scaled too, but with rounding errors */
273 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
274 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
276 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
277 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
278 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
279 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
280 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
281 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
285 ret
= GetTextMetricsA(hdc
, &tm
);
286 ok(ret
, "GetTextMetricsA failed\n");
289 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
290 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
291 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
292 lfHeight
, scale_x
, scale_y
, cx
, cy
);
293 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
294 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
295 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
296 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
297 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
299 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
303 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
306 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
308 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
310 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
311 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
313 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
315 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
);
318 /* Test how GDI scales bitmap font metrics */
319 static void test_bitmap_font(void)
321 static const char test_str
[11] = "Test String";
324 HFONT hfont
, old_hfont
;
327 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
331 /* "System" has only 1 pixel size defined, otherwise the test breaks */
332 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
336 trace("no bitmap fonts were found, skipping the test\n");
340 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
342 height_orig
= bitmap_lf
.lfHeight
;
343 lfWidth
= bitmap_lf
.lfWidth
;
345 hfont
= create_font("bitmap", &bitmap_lf
);
346 old_hfont
= SelectObject(hdc
, hfont
);
347 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
348 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
349 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
350 SelectObject(hdc
, old_hfont
);
353 bitmap_lf
.lfHeight
= 0;
354 bitmap_lf
.lfWidth
= 4;
355 hfont
= create_font("bitmap", &bitmap_lf
);
356 old_hfont
= SelectObject(hdc
, hfont
);
357 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
358 SelectObject(hdc
, old_hfont
);
361 bitmap_lf
.lfHeight
= height_orig
;
362 bitmap_lf
.lfWidth
= lfWidth
;
364 /* test fractional scaling */
365 for (i
= 1; i
<= height_orig
* 6; i
++)
369 bitmap_lf
.lfHeight
= i
;
370 hfont
= create_font("fractional", &bitmap_lf
);
371 scale
= (i
+ height_orig
- 1) / height_orig
;
372 nearest_height
= scale
* height_orig
;
373 /* Only jump to the next height if the difference <= 25% original height */
374 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
375 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
376 so we'll not test this particular height. */
377 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
378 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
379 old_hfont
= SelectObject(hdc
, hfont
);
380 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
381 SelectObject(hdc
, old_hfont
);
385 /* test integer scaling 3x2 */
386 bitmap_lf
.lfHeight
= height_orig
* 2;
387 bitmap_lf
.lfWidth
*= 3;
388 hfont
= create_font("3x2", &bitmap_lf
);
389 old_hfont
= SelectObject(hdc
, hfont
);
390 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
391 SelectObject(hdc
, old_hfont
);
394 /* test integer scaling 3x3 */
395 bitmap_lf
.lfHeight
= height_orig
* 3;
396 bitmap_lf
.lfWidth
= 0;
397 hfont
= create_font("3x3", &bitmap_lf
);
398 old_hfont
= SelectObject(hdc
, hfont
);
399 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
400 SelectObject(hdc
, old_hfont
);
406 /* Test how GDI scales outline font metrics */
407 static void test_outline_font(void)
409 static const char test_str
[11] = "Test String";
412 HFONT hfont
, old_hfont
, old_hfont_2
;
413 OUTLINETEXTMETRICA otm
;
415 INT width_orig
, height_orig
, lfWidth
;
418 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
422 if (!is_truetype_font_installed("Arial"))
424 skip("Arial is not installed\n");
428 hdc
= CreateCompatibleDC(0);
430 memset(&lf
, 0, sizeof(lf
));
431 strcpy(lf
.lfFaceName
, "Arial");
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");
440 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
441 SelectObject(hdc
, old_hfont
);
444 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
445 lf
.lfHeight
= otm
.otmEMSquare
;
446 lf
.lfHeight
= -lf
.lfHeight
;
447 hfont
= create_font("outline", &lf
);
448 old_hfont
= SelectObject(hdc
, hfont
);
449 otm
.otmSize
= sizeof(otm
);
450 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
451 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
452 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
453 SelectObject(hdc
, old_hfont
);
456 height_orig
= otm
.otmTextMetrics
.tmHeight
;
457 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
459 /* test integer scaling 3x2 */
460 lf
.lfHeight
= height_orig
* 2;
461 lf
.lfWidth
= lfWidth
* 3;
462 hfont
= create_font("3x2", &lf
);
463 old_hfont
= SelectObject(hdc
, hfont
);
464 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
465 SelectObject(hdc
, old_hfont
);
468 /* test integer scaling 3x3 */
469 lf
.lfHeight
= height_orig
* 3;
470 lf
.lfWidth
= lfWidth
* 3;
471 hfont
= create_font("3x3", &lf
);
472 old_hfont
= SelectObject(hdc
, hfont
);
473 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
474 SelectObject(hdc
, old_hfont
);
477 /* test integer scaling 1x1 */
478 lf
.lfHeight
= height_orig
* 1;
479 lf
.lfWidth
= lfWidth
* 1;
480 hfont
= create_font("1x1", &lf
);
481 old_hfont
= SelectObject(hdc
, hfont
);
482 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
483 SelectObject(hdc
, old_hfont
);
486 /* test integer scaling 1x1 */
487 lf
.lfHeight
= height_orig
;
489 hfont
= create_font("1x1", &lf
);
490 old_hfont
= SelectObject(hdc
, hfont
);
491 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
493 /* with an identity matrix */
494 memset(&gm
, 0, sizeof(gm
));
495 SetLastError(0xdeadbeef);
496 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
497 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
498 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
499 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
500 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
501 /* with a custom matrix */
502 memset(&gm
, 0, sizeof(gm
));
503 SetLastError(0xdeadbeef);
504 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
505 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
506 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
507 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
508 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
510 /* Test that changing the DC transformation affects only the font
511 * selected on this DC and doesn't affect the same font selected on
514 hdc_2
= CreateCompatibleDC(0);
515 old_hfont_2
= SelectObject(hdc_2
, hfont
);
516 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
518 SetMapMode(hdc
, MM_ANISOTROPIC
);
520 /* font metrics on another DC should be unchanged */
521 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
523 /* test restrictions of compatibility mode GM_COMPATIBLE */
524 /* part 1: rescaling only X should not change font scaling on screen.
525 So compressing the X axis by 2 is not done, and this
526 appears as X scaling of 2 that no one requested. */
527 SetWindowExtEx(hdc
, 100, 100, NULL
);
528 SetViewportExtEx(hdc
, 50, 100, NULL
);
529 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
530 /* font metrics on another DC should be unchanged */
531 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
533 /* part 2: rescaling only Y should change font scaling.
534 As also X is scaled by a factor of 2, but this is not
535 requested by the DC transformation, we get a scaling factor
536 of 2 in the X coordinate. */
537 SetViewportExtEx(hdc
, 100, 200, NULL
);
538 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
539 /* font metrics on another DC should be unchanged */
540 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
542 /* restore scaling */
543 SetMapMode(hdc
, MM_TEXT
);
545 /* font metrics on another DC should be unchanged */
546 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
548 SelectObject(hdc_2
, old_hfont_2
);
551 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
553 SelectObject(hdc
, old_hfont
);
556 skip("GM_ADVANCED is not supported on this platform\n");
567 SetLastError(0xdeadbeef);
568 ret
= SetWorldTransform(hdc
, &xform
);
569 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
571 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
573 /* with an identity matrix */
574 memset(&gm
, 0, sizeof(gm
));
575 SetLastError(0xdeadbeef);
576 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
577 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
578 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
579 pt
.x
= width_orig
; pt
.y
= 0;
581 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
582 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
583 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
584 /* with a custom matrix */
585 memset(&gm
, 0, sizeof(gm
));
586 SetLastError(0xdeadbeef);
587 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
588 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
589 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
590 pt
.x
= width_orig
; pt
.y
= 0;
592 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
593 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
594 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
596 SetLastError(0xdeadbeef);
597 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
598 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
600 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
602 /* with an identity matrix */
603 memset(&gm
, 0, sizeof(gm
));
604 SetLastError(0xdeadbeef);
605 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
606 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
607 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
608 pt
.x
= width_orig
; pt
.y
= 0;
610 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
611 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
612 /* with a custom matrix */
613 memset(&gm
, 0, sizeof(gm
));
614 SetLastError(0xdeadbeef);
615 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
616 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
617 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
618 pt
.x
= width_orig
; pt
.y
= 0;
620 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
621 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
623 SetLastError(0xdeadbeef);
624 ret
= SetMapMode(hdc
, MM_TEXT
);
625 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
627 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
629 /* with an identity matrix */
630 memset(&gm
, 0, sizeof(gm
));
631 SetLastError(0xdeadbeef);
632 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
633 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
634 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
635 pt
.x
= width_orig
; pt
.y
= 0;
637 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
638 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
639 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
640 /* with a custom matrix */
641 memset(&gm
, 0, sizeof(gm
));
642 SetLastError(0xdeadbeef);
643 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
644 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
645 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
646 pt
.x
= width_orig
; pt
.y
= 0;
648 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
649 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
650 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
652 SelectObject(hdc
, old_hfont
);
657 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
659 LOGFONT
*lf
= (LOGFONT
*)lParam
;
661 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
664 return 0; /* stop enumeration */
666 return 1; /* continue enumeration */
669 static void test_bitmap_font_metrics(void)
671 static const struct font_data
673 const char face_name
[LF_FACESIZE
];
674 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
675 int ave_char_width
, max_char_width
, dpi
;
680 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
681 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
682 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1
| FS_CYRILLIC
},
683 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2
},
684 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1
},
685 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2
},
686 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC
},
687 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1
},
688 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2
},
689 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC
},
690 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
692 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
693 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_LATIN2
},
694 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC
},
695 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
696 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1
| FS_LATIN2
},
697 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC
},
698 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
699 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
701 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
702 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
703 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
704 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
},
705 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2
| FS_CYRILLIC
},
706 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1
| FS_LATIN2
},
707 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC
},
708 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1
| FS_LATIN2
},
709 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC
},
710 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1
},
711 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2
},
712 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC
},
713 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1
},
714 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2
},
715 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC
},
716 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1
| FS_LATIN2
},
717 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC
},
719 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1
| FS_CYRILLIC
},
720 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2
},
721 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_CYRILLIC
},
722 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2
},
723 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1
| FS_CYRILLIC
},
724 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2
},
725 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1
| FS_LATIN2
},
726 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC
},
727 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1
| FS_LATIN2
},
728 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC
},
729 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
731 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
732 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
733 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
735 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
736 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
737 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
739 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
},
740 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2
| FS_CYRILLIC
},
741 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN
},
743 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1
},
744 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2
| FS_CYRILLIC
},
746 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1
},
747 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
748 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN
},
749 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1
, LANG_ARABIC
},
750 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
751 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN
},
752 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1
, LANG_ARABIC
},
753 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
754 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, FS_ARABIC
},
755 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN
},
756 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1
, LANG_ARABIC
},
757 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
758 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, FS_ARABIC
},
759 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN
},
760 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
761 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
762 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, FS_ARABIC
},
763 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN
},
764 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
765 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, FS_ARABIC
},
766 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN
},
768 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1
| FS_JISJAPAN
},
769 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
770 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1
| FS_JISJAPAN
},
771 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
772 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1
| FS_JISJAPAN
},
773 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
774 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
775 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC
},
776 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
777 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC
},
778 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
779 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC
},
781 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
},
782 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC
},
783 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN
},
785 /* The 120dpi version still has its dpi marked as 96 */
786 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
788 /* FIXME: add "Terminal" */
792 HFONT hfont
, old_hfont
;
797 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
799 hdc
= CreateCompatibleDC(0);
802 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
806 memset(&lf
, 0, sizeof(lf
));
808 lf
.lfHeight
= fd
[i
].height
;
809 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
811 for(bit
= 0; bit
< 32; bit
++)
819 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
820 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
822 lf
.lfCharSet
= csi
.ciCharset
;
823 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
826 hfont
= create_font(lf
.lfFaceName
, &lf
);
827 old_hfont
= SelectObject(hdc
, hfont
);
828 bRet
= GetTextMetrics(hdc
, &tm
);
829 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
830 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
832 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
833 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
835 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
);
836 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
);
837 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
);
838 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
);
839 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
);
840 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
);
841 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
);
843 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
844 that make the max width bigger */
845 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
846 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
);
849 skip("Skipping font metrics test for system langid 0x%x\n",
852 SelectObject(hdc
, old_hfont
);
860 static void test_GdiGetCharDimensions(void)
866 LONG avgwidth
, height
;
867 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
869 if (!pGdiGetCharDimensions
)
871 win_skip("GdiGetCharDimensions not available on this platform\n");
875 hdc
= CreateCompatibleDC(NULL
);
877 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
878 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
880 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
881 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
882 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
884 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
885 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
887 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
888 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
891 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
892 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
893 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
898 static int CALLBACK
create_font_proc(const LOGFONT
*lpelfe
,
899 const TEXTMETRIC
*lpntme
,
900 DWORD FontType
, LPARAM lParam
)
902 if (FontType
& TRUETYPE_FONTTYPE
)
906 hfont
= CreateFontIndirect(lpelfe
);
909 *(HFONT
*)lParam
= hfont
;
917 static void test_GetCharABCWidths(void)
919 static const WCHAR str
[] = {'a',0};
940 {0xffffff, 0xffffff},
941 {0x1000000, 0x1000000},
942 {0xffffff, 0x1000000},
943 {0xffffffff, 0xffffffff}
950 BOOL r
[sizeof range
/ sizeof range
[0]];
953 {ANSI_CHARSET
, 0x30, 0x30, {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
954 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
955 {HANGEUL_CHARSET
, 0x8141, 0xac02, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
956 {JOHAB_CHARSET
, 0x8446, 0x3135, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
957 {GB2312_CHARSET
, 0x8141, 0x4e04, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
958 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}}
962 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsI
)
964 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
968 memset(&lf
, 0, sizeof(lf
));
969 strcpy(lf
.lfFaceName
, "System");
972 hfont
= CreateFontIndirectA(&lf
);
974 hfont
= SelectObject(hdc
, hfont
);
976 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
977 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
979 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
980 ok(!ret
, "GetCharABCWidthsI should have failed\n");
982 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
983 ok(!ret
, "GetCharABCWidthsI should have failed\n");
985 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
986 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
988 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
989 ok(!ret
, "GetCharABCWidthsW should have failed\n");
991 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
992 ok(!ret
, "GetCharABCWidthsW should have failed\n");
994 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
995 ok(!ret
, "GetCharABCWidthsW should have failed\n");
997 hfont
= SelectObject(hdc
, hfont
);
1000 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1004 UINT code
= 0x41, j
;
1006 lf
.lfFaceName
[0] = '\0';
1007 lf
.lfCharSet
= c
[i
].cs
;
1008 lf
.lfPitchAndFamily
= 0;
1009 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1011 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1015 memset(a
, 0, sizeof a
);
1016 memset(w
, 0, sizeof w
);
1017 hfont
= SelectObject(hdc
, hfont
);
1018 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1019 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1020 memcmp(a
, w
, sizeof a
) == 0,
1021 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1023 memset(a
, 0xbb, sizeof a
);
1024 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1025 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1026 memset(full
, 0xcc, sizeof full
);
1027 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1028 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1029 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1030 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1032 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1034 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1035 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1036 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1039 hfont
= SelectObject(hdc
, hfont
);
1040 DeleteObject(hfont
);
1043 ReleaseDC(NULL
, hdc
);
1046 static void test_text_extents(void)
1048 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1050 INT i
, len
, fit1
, fit2
;
1058 memset(&lf
, 0, sizeof(lf
));
1059 strcpy(lf
.lfFaceName
, "Arial");
1062 hfont
= CreateFontIndirectA(&lf
);
1064 hfont
= SelectObject(hdc
, hfont
);
1065 GetTextMetricsA(hdc
, &tm
);
1066 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1067 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1069 SetLastError(0xdeadbeef);
1070 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1071 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1073 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1074 hfont
= SelectObject(hdc
, hfont
);
1075 DeleteObject(hfont
);
1081 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1082 extents
[0] = 1; /* So that the increasing sequence test will fail
1083 if the extents array is untouched. */
1084 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1085 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1086 ok(sz1
.cy
== sz2
.cy
,
1087 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1088 /* Because of the '\n' in the string GetTextExtentExPoint and
1089 GetTextExtentPoint return different widths under Win2k, but
1090 under WinXP they return the same width. So we don't test that
1093 for (i
= 1; i
< len
; ++i
)
1094 ok(extents
[i
-1] <= extents
[i
],
1095 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1097 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1098 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1099 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1100 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1101 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1102 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1103 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1104 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1105 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1106 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1107 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1108 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1109 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1110 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1111 HeapFree(GetProcessHeap(), 0, extents
);
1113 hfont
= SelectObject(hdc
, hfont
);
1114 DeleteObject(hfont
);
1115 ReleaseDC(NULL
, hdc
);
1118 static void test_GetGlyphIndices(void)
1125 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1126 WORD glyphs
[(sizeof(testtext
)/2)-1];
1130 if (!pGetGlyphIndicesW
) {
1131 win_skip("GetGlyphIndicesW not available on platform\n");
1137 memset(&lf
, 0, sizeof(lf
));
1138 strcpy(lf
.lfFaceName
, "System");
1140 lf
.lfCharSet
= ANSI_CHARSET
;
1142 hfont
= CreateFontIndirectA(&lf
);
1143 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1144 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1145 if (textm
.tmCharSet
== ANSI_CHARSET
)
1147 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1148 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1149 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1150 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1152 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1153 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1154 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1155 textm
.tmDefaultChar
, glyphs
[4]);
1158 /* FIXME: Write tests for non-ANSI charsets. */
1159 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1161 if(!is_font_installed("Tahoma"))
1163 skip("Tahoma is not installed so skipping this test\n");
1166 memset(&lf
, 0, sizeof(lf
));
1167 strcpy(lf
.lfFaceName
, "Tahoma");
1170 hfont
= CreateFontIndirectA(&lf
);
1171 hOldFont
= SelectObject(hdc
, hfont
);
1172 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1173 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1174 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1175 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1176 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1178 testtext
[0] = textm
.tmDefaultChar
;
1179 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1180 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1181 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1182 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1183 DeleteObject(SelectObject(hdc
, hOldFont
));
1186 static void test_GetKerningPairs(void)
1188 static const struct kerning_data
1190 const char face_name
[LF_FACESIZE
];
1192 /* some interesting fields from OUTLINETEXTMETRIC */
1193 LONG tmHeight
, tmAscent
, tmDescent
;
1198 UINT otmsCapEmHeight
;
1203 UINT otmusMinimumPPEM
;
1204 /* small subset of kerning pairs to test */
1205 DWORD total_kern_pairs
;
1206 const KERNINGPAIR kern_pair
[26];
1209 {"Arial", 12, 12, 9, 3,
1210 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1213 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1214 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1215 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1216 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1217 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1218 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1219 {933,970,+1},{933,972,-1}
1222 {"Arial", -34, 39, 32, 7,
1223 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1226 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1227 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1228 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1229 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1230 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1231 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1232 {933,970,+2},{933,972,-3}
1235 { "Arial", 120, 120, 97, 23,
1236 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1239 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1240 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1241 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1242 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1243 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1244 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1245 {933,970,+6},{933,972,-10}
1248 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1249 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1250 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1253 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1254 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1255 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1256 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1257 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1258 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1259 {933,970,+54},{933,972,-83}
1265 HFONT hfont
, hfont_old
;
1266 KERNINGPAIR
*kern_pair
;
1268 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1272 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1273 * which may render this test unusable, so we're trying to avoid that.
1275 SetLastError(0xdeadbeef);
1276 GetKerningPairsW(hdc
, 0, NULL
);
1277 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1279 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1284 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1286 OUTLINETEXTMETRICW otm
;
1289 if (!is_font_installed(kd
[i
].face_name
))
1291 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1295 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1297 memset(&lf
, 0, sizeof(lf
));
1298 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1299 lf
.lfHeight
= kd
[i
].height
;
1300 hfont
= CreateFontIndirect(&lf
);
1303 hfont_old
= SelectObject(hdc
, hfont
);
1305 SetLastError(0xdeadbeef);
1306 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1307 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1308 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1310 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
), "expected %d, got %d\n",
1311 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1312 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
), "expected %d, got %d\n",
1313 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1314 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1315 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1317 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1318 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1319 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1320 kd
[i
].otmAscent
, otm
.otmAscent
);
1321 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1322 kd
[i
].otmDescent
, otm
.otmDescent
);
1323 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1324 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1325 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1326 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1327 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1328 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1330 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1331 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1332 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1333 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1334 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1335 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1336 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1337 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1338 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1341 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1342 trace("total_kern_pairs %u\n", total_kern_pairs
);
1343 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1345 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1348 SetLastError(0xdeadbeef);
1349 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1350 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1351 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1352 ok(ret
== 0, "got %u, expected 0\n", ret
);
1354 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1355 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1357 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1358 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1360 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1361 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1365 for (n
= 0; n
< ret
; n
++)
1368 /* Disabled to limit console spam */
1369 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1370 trace("{'%c','%c',%d},\n",
1371 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1372 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1374 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1375 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1377 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1378 "pair %d:%d got %d, expected %d\n",
1379 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1380 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1386 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1387 matches
, kd
[i
].total_kern_pairs
);
1389 HeapFree(GetProcessHeap(), 0, kern_pair
);
1391 SelectObject(hdc
, hfont_old
);
1392 DeleteObject(hfont
);
1398 static void test_height_selection(void)
1400 static const struct font_data
1402 const char face_name
[LF_FACESIZE
];
1403 int requested_height
;
1404 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1407 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96 },
1408 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96 },
1409 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96 },
1410 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96 },
1411 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96 },
1412 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96 },
1413 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96 },
1414 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96 },
1415 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96 },
1416 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96 }
1420 HFONT hfont
, old_hfont
;
1424 hdc
= CreateCompatibleDC(0);
1427 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
1429 if (!is_truetype_font_installed(fd
[i
].face_name
))
1431 skip("%s is not installed\n", fd
[i
].face_name
);
1435 memset(&lf
, 0, sizeof(lf
));
1436 lf
.lfHeight
= fd
[i
].requested_height
;
1437 lf
.lfWeight
= fd
[i
].weight
;
1438 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1440 hfont
= CreateFontIndirect(&lf
);
1443 old_hfont
= SelectObject(hdc
, hfont
);
1444 ret
= GetTextMetrics(hdc
, &tm
);
1445 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1446 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1448 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1449 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmWeight
, fd
[i
].weight
);
1450 ok(match_off_by_1(tm
.tmHeight
, fd
[i
].height
), "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmHeight
, fd
[i
].height
);
1451 ok(match_off_by_1(tm
.tmAscent
, fd
[i
].ascent
), "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmAscent
, fd
[i
].ascent
);
1452 ok(match_off_by_1(tm
.tmDescent
, fd
[i
].descent
), "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmDescent
, fd
[i
].descent
);
1453 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1454 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1456 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1459 SelectObject(hdc
, old_hfont
);
1460 DeleteObject(hfont
);
1466 static void test_GetOutlineTextMetrics(void)
1468 OUTLINETEXTMETRIC
*otm
;
1470 HFONT hfont
, hfont_old
;
1472 DWORD ret
, otm_size
;
1475 if (!is_font_installed("Arial"))
1477 skip("Arial is not installed\n");
1483 memset(&lf
, 0, sizeof(lf
));
1484 strcpy(lf
.lfFaceName
, "Arial");
1486 lf
.lfWeight
= FW_NORMAL
;
1487 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1488 lf
.lfQuality
= PROOF_QUALITY
;
1489 hfont
= CreateFontIndirect(&lf
);
1492 hfont_old
= SelectObject(hdc
, hfont
);
1493 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1494 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1496 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1498 memset(otm
, 0xAA, otm_size
);
1499 SetLastError(0xdeadbeef);
1500 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1501 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1502 ok(ret
== 1 /* Win9x */ ||
1503 ret
== otm
->otmSize
/* XP*/,
1504 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1505 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1507 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1508 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1509 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1510 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1513 memset(otm
, 0xAA, otm_size
);
1514 SetLastError(0xdeadbeef);
1515 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1516 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1517 ok(ret
== 1 /* Win9x */ ||
1518 ret
== otm
->otmSize
/* XP*/,
1519 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1520 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1522 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1523 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1524 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1525 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1528 /* ask about truncated data */
1529 memset(otm
, 0xAA, otm_size
);
1530 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1531 SetLastError(0xdeadbeef);
1532 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1533 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1534 ok(ret
== 1 /* Win9x */ ||
1535 ret
== otm
->otmSize
/* XP*/,
1536 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1537 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1539 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1540 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1541 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1543 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1545 HeapFree(GetProcessHeap(), 0, otm
);
1547 SelectObject(hdc
, hfont_old
);
1548 DeleteObject(hfont
);
1553 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1557 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
1558 areaWidth
= clientArea
->right
- clientArea
->left
,
1560 BOOL lastExtent
= FALSE
;
1561 PSTR pFirstChar
, pLastChar
;
1567 int GetTextExtentExPointWWidth
;
1570 GetTextMetricsA(hdc
, &tm
);
1571 y
= clientArea
->top
;
1574 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1580 /* if not at the end of the string, ... */
1581 if (*str
== '\0') break;
1582 /* ... add the next word to the current extent */
1583 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1585 SetTextJustification(hdc
, 0, 0);
1586 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1587 } while ((int) size
.cx
< areaWidth
);
1589 /* ignore trailing break chars */
1591 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1597 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1599 SetTextJustification(hdc
, 0, 0);
1600 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1602 /* do not justify the last extent */
1603 if (*str
!= '\0' && breakCount
> 0)
1605 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1606 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1607 justifiedWidth
= size
.cx
;
1609 else lastExtent
= TRUE
;
1611 /* catch errors and report them */
1612 if (!lastExtent
&& (justifiedWidth
!= areaWidth
))
1614 memset(error
[nErrors
].extent
, 0, 100);
1615 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
1616 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
1622 } while (*str
&& y
< clientArea
->bottom
);
1624 for (e
= 0; e
< nErrors
; e
++)
1626 /* The width returned by GetTextExtentPoint32() is exactly the same
1627 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1628 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1629 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1630 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1634 static void test_SetTextJustification(void)
1641 static char testText
[] =
1642 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1643 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1644 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1645 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1646 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1647 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1648 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1650 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1651 GetClientRect( hwnd
, &clientArea
);
1652 hdc
= GetDC( hwnd
);
1654 memset(&lf
, 0, sizeof lf
);
1655 lf
.lfCharSet
= ANSI_CHARSET
;
1656 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1657 lf
.lfWeight
= FW_DONTCARE
;
1659 lf
.lfQuality
= DEFAULT_QUALITY
;
1660 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1661 hfont
= create_font("Times New Roman", &lf
);
1662 SelectObject(hdc
, hfont
);
1664 testJustification(hdc
, testText
, &clientArea
);
1666 DeleteObject(hfont
);
1667 ReleaseDC(hwnd
, hdc
);
1668 DestroyWindow(hwnd
);
1671 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1675 HFONT hfont
, hfont_old
;
1682 assert(count
<= 128);
1684 memset(&lf
, 0, sizeof(lf
));
1686 lf
.lfCharSet
= charset
;
1688 lstrcpyA(lf
.lfFaceName
, "Arial");
1689 SetLastError(0xdeadbeef);
1690 hfont
= CreateFontIndirectA(&lf
);
1691 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1694 hfont_old
= SelectObject(hdc
, hfont
);
1696 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1697 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1699 SetLastError(0xdeadbeef);
1700 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1701 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1703 if (charset
== SYMBOL_CHARSET
)
1705 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1706 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1710 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1711 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1714 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1716 trace("Can't find codepage for charset %d\n", cs
);
1720 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1722 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
1724 skip("Font code page %d, looking for code page %d\n",
1725 pGdiGetCodePage(hdc
), code_page
);
1733 WCHAR unicode_buf
[128];
1735 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1737 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1739 SetLastError(0xdeadbeef);
1740 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1741 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
1742 count
, ret
, GetLastError());
1748 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1750 SetLastError(0xdeadbeef);
1751 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1752 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
1753 count
, ret
, GetLastError());
1756 SelectObject(hdc
, hfont_old
);
1757 DeleteObject(hfont
);
1764 static void test_font_charset(void)
1766 static struct charset_data
1770 WORD font_idxA
[128], font_idxW
[128];
1773 { ANSI_CHARSET
, 1252 },
1774 { RUSSIAN_CHARSET
, 1251 },
1775 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1779 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1781 win_skip("Skipping the font charset test on a Win9x platform\n");
1785 if (!is_font_installed("Arial"))
1787 skip("Arial is not installed\n");
1791 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1793 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1795 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1797 skip("Symbol or Wingdings is not installed\n");
1801 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
1802 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
1803 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1806 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1809 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1810 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1813 skip("Symbol or Wingdings is not installed\n");
1816 static void test_GetFontUnicodeRanges(void)
1820 HFONT hfont
, hfont_old
;
1825 if (!pGetFontUnicodeRanges
)
1827 win_skip("GetFontUnicodeRanges not available before W2K\n");
1831 memset(&lf
, 0, sizeof(lf
));
1832 lstrcpyA(lf
.lfFaceName
, "Arial");
1833 hfont
= create_font("Arial", &lf
);
1836 hfont_old
= SelectObject(hdc
, hfont
);
1838 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1839 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1841 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1842 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1844 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1846 size
= pGetFontUnicodeRanges(hdc
, gs
);
1847 ok(size
, "GetFontUnicodeRanges failed\n");
1849 if (0) /* Disabled to limit console spam */
1850 for (i
= 0; i
< gs
->cRanges
; i
++)
1851 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1852 trace("found %u ranges\n", gs
->cRanges
);
1854 HeapFree(GetProcessHeap(), 0, gs
);
1856 SelectObject(hdc
, hfont_old
);
1857 DeleteObject(hfont
);
1858 ReleaseDC(NULL
, hdc
);
1861 #define MAX_ENUM_FONTS 4096
1863 struct enum_font_data
1866 LOGFONT lf
[MAX_ENUM_FONTS
];
1869 struct enum_font_dataW
1872 LOGFONTW lf
[MAX_ENUM_FONTS
];
1875 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1877 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1879 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1881 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1882 if (0) /* Disabled to limit console spam */
1883 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1884 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1885 if (efd
->total
< MAX_ENUM_FONTS
)
1886 efd
->lf
[efd
->total
++] = *lf
;
1888 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1893 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
1895 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
1897 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1899 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1900 if (0) /* Disabled to limit console spam */
1901 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1902 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1903 if (efd
->total
< MAX_ENUM_FONTS
)
1904 efd
->lf
[efd
->total
++] = *lf
;
1906 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1911 static void get_charset_stats(struct enum_font_data
*efd
,
1912 int *ansi_charset
, int *symbol_charset
,
1913 int *russian_charset
)
1918 *symbol_charset
= 0;
1919 *russian_charset
= 0;
1921 for (i
= 0; i
< efd
->total
; i
++)
1923 switch (efd
->lf
[i
].lfCharSet
)
1928 case SYMBOL_CHARSET
:
1929 (*symbol_charset
)++;
1931 case RUSSIAN_CHARSET
:
1932 (*russian_charset
)++;
1938 static void get_charset_statsW(struct enum_font_dataW
*efd
,
1939 int *ansi_charset
, int *symbol_charset
,
1940 int *russian_charset
)
1945 *symbol_charset
= 0;
1946 *russian_charset
= 0;
1948 for (i
= 0; i
< efd
->total
; i
++)
1950 switch (efd
->lf
[i
].lfCharSet
)
1955 case SYMBOL_CHARSET
:
1956 (*symbol_charset
)++;
1958 case RUSSIAN_CHARSET
:
1959 (*russian_charset
)++;
1965 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1967 struct enum_font_data efd
;
1968 struct enum_font_dataW efdw
;
1971 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1973 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1975 if (*font_name
&& !is_truetype_font_installed(font_name
))
1977 skip("%s is not installed\n", font_name
);
1983 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1984 * while EnumFontFamiliesEx doesn't.
1986 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1989 * Use EnumFontFamiliesW since win98 crashes when the
1990 * second parameter is NULL using EnumFontFamilies
1993 SetLastError(0xdeadbeef);
1994 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
1995 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
1998 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1999 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2000 ansi_charset
, symbol_charset
, russian_charset
);
2001 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2002 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2003 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2004 ok(russian_charset
> 0 ||
2005 broken(russian_charset
== 0), /* NT4 */
2006 "NULL family should enumerate RUSSIAN_CHARSET\n");
2010 SetLastError(0xdeadbeef);
2011 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2012 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2015 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2016 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2017 ansi_charset
, symbol_charset
, russian_charset
);
2018 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2019 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2020 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2021 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2026 SetLastError(0xdeadbeef);
2027 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2028 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2029 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2030 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2031 ansi_charset
, symbol_charset
, russian_charset
,
2032 *font_name
? font_name
: "<empty>");
2034 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2036 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2037 for (i
= 0; i
< efd
.total
; i
++)
2039 /* FIXME: remove completely once Wine is fixed */
2040 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2043 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2046 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2047 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2048 font_name
, efd
.lf
[i
].lfFaceName
);
2051 memset(&lf
, 0, sizeof(lf
));
2052 lf
.lfCharSet
= ANSI_CHARSET
;
2053 lstrcpy(lf
.lfFaceName
, font_name
);
2055 SetLastError(0xdeadbeef);
2056 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2057 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2058 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2059 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2060 ansi_charset
, symbol_charset
, russian_charset
,
2061 *font_name
? font_name
: "<empty>");
2062 if (font_charset
== SYMBOL_CHARSET
)
2065 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2067 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2071 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2072 for (i
= 0; i
< efd
.total
; i
++)
2074 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2076 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2077 font_name
, efd
.lf
[i
].lfFaceName
);
2081 /* DEFAULT_CHARSET should enumerate all available charsets */
2082 memset(&lf
, 0, sizeof(lf
));
2083 lf
.lfCharSet
= DEFAULT_CHARSET
;
2084 lstrcpy(lf
.lfFaceName
, font_name
);
2086 SetLastError(0xdeadbeef);
2087 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2088 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2089 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2090 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2091 ansi_charset
, symbol_charset
, russian_charset
,
2092 *font_name
? font_name
: "<empty>");
2093 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2094 for (i
= 0; i
< efd
.total
; i
++)
2097 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2098 font_name
, efd
.lf
[i
].lfFaceName
);
2102 switch (font_charset
)
2105 ok(ansi_charset
> 0,
2106 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2108 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2109 ok(russian_charset
> 0,
2110 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2112 case SYMBOL_CHARSET
:
2114 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2116 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2117 ok(!russian_charset
,
2118 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2120 case DEFAULT_CHARSET
:
2121 ok(ansi_charset
> 0,
2122 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2123 ok(symbol_charset
> 0,
2124 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2125 ok(russian_charset
> 0,
2126 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2132 ok(ansi_charset
> 0,
2133 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2134 ok(symbol_charset
> 0,
2135 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2136 ok(russian_charset
> 0,
2137 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2140 memset(&lf
, 0, sizeof(lf
));
2141 lf
.lfCharSet
= SYMBOL_CHARSET
;
2142 lstrcpy(lf
.lfFaceName
, font_name
);
2144 SetLastError(0xdeadbeef);
2145 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2146 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2147 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2148 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2149 ansi_charset
, symbol_charset
, russian_charset
,
2150 *font_name
? font_name
: "<empty>");
2151 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2152 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2155 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2156 for (i
= 0; i
< efd
.total
; i
++)
2158 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2160 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2161 font_name
, efd
.lf
[i
].lfFaceName
);
2165 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2166 ok(symbol_charset
> 0,
2167 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2168 ok(!russian_charset
,
2169 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2175 static INT CALLBACK
enum_font_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2177 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2179 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2181 if (efd
->total
< MAX_ENUM_FONTS
)
2182 efd
->lf
[efd
->total
++] = *lf
;
2184 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2189 static void test_EnumFontFamiliesEx_default_charset(void)
2191 struct enum_font_data efd
;
2192 LOGFONT gui_font
, enum_font
;
2196 ret
= GetObject(GetStockObject(DEFAULT_GUI_FONT
), sizeof(gui_font
), &gui_font
);
2197 ok(ret
, "GetObject failed.\n");
2204 memset(&enum_font
, 0, sizeof(enum_font
));
2205 lstrcpy(enum_font
.lfFaceName
, gui_font
.lfFaceName
);
2206 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
2207 EnumFontFamiliesEx(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
2210 if (efd
.total
== 0) {
2211 skip("'%s' is not found or not a TrueType font.\n", gui_font
.lfFaceName
);
2214 trace("'%s' has %d charsets.\n", gui_font
.lfFaceName
, efd
.total
);
2216 ok(efd
.lf
[0].lfCharSet
== gui_font
.lfCharSet
,
2217 "(%s) got charset %d expected %d\n",
2218 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, gui_font
.lfCharSet
);
2223 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2225 HFONT hfont
, hfont_prev
;
2227 GLYPHMETRICS gm1
, gm2
;
2231 if(!pGetGlyphIndicesA
)
2234 /* negative widths are handled just as positive ones */
2235 lf2
.lfWidth
= -lf
->lfWidth
;
2237 SetLastError(0xdeadbeef);
2238 hfont
= CreateFontIndirectA(lf
);
2239 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2240 check_font("original", lf
, hfont
);
2242 hfont_prev
= SelectObject(hdc
, hfont
);
2244 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2245 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2247 SelectObject(hdc
, hfont_prev
);
2248 DeleteObject(hfont
);
2249 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2253 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2254 memset(&gm1
, 0xab, sizeof(gm1
));
2255 SetLastError(0xdeadbeef);
2256 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2257 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2259 SelectObject(hdc
, hfont_prev
);
2260 DeleteObject(hfont
);
2262 SetLastError(0xdeadbeef);
2263 hfont
= CreateFontIndirectA(&lf2
);
2264 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2265 check_font("negative width", &lf2
, hfont
);
2267 hfont_prev
= SelectObject(hdc
, hfont
);
2269 memset(&gm2
, 0xbb, sizeof(gm2
));
2270 SetLastError(0xdeadbeef);
2271 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2272 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2274 SelectObject(hdc
, hfont_prev
);
2275 DeleteObject(hfont
);
2277 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2278 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2279 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2280 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2281 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2282 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2283 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2284 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2285 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2286 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2287 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2290 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2291 #include "pshpack2.h"
2295 SHORT xAvgCharWidth
;
2296 USHORT usWeightClass
;
2297 USHORT usWidthClass
;
2299 SHORT ySubscriptXSize
;
2300 SHORT ySubscriptYSize
;
2301 SHORT ySubscriptXOffset
;
2302 SHORT ySubscriptYOffset
;
2303 SHORT ySuperscriptXSize
;
2304 SHORT ySuperscriptYSize
;
2305 SHORT ySuperscriptXOffset
;
2306 SHORT ySuperscriptYOffset
;
2307 SHORT yStrikeoutSize
;
2308 SHORT yStrikeoutPosition
;
2311 ULONG ulUnicodeRange1
;
2312 ULONG ulUnicodeRange2
;
2313 ULONG ulUnicodeRange3
;
2314 ULONG ulUnicodeRange4
;
2317 USHORT usFirstCharIndex
;
2318 USHORT usLastCharIndex
;
2319 /* According to the Apple spec, original version didn't have the below fields,
2320 * version numbers were taken from the OpenType spec.
2322 /* version 0 (TrueType 1.5) */
2323 USHORT sTypoAscender
;
2324 USHORT sTypoDescender
;
2325 USHORT sTypoLineGap
;
2327 USHORT usWinDescent
;
2328 /* version 1 (TrueType 1.66) */
2329 ULONG ulCodePageRange1
;
2330 ULONG ulCodePageRange2
;
2331 /* version 2 (OpenType 1.2) */
2334 USHORT usDefaultChar
;
2336 USHORT usMaxContext
;
2338 #include "poppack.h"
2340 #ifdef WORDS_BIGENDIAN
2341 #define GET_BE_WORD(x) (x)
2342 #define GET_BE_DWORD(x) (x)
2344 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2345 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2348 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2349 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2350 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2351 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2352 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2353 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2366 } cmap_encoding_record
;
2374 BYTE glyph_ids
[256];
2384 USHORT search_range
;
2385 USHORT entry_selector
;
2388 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2391 USHORT start_count[seg_countx2 / 2];
2392 USHORT id_delta[seg_countx2 / 2];
2393 USHORT id_range_offset[seg_countx2 / 2];
2403 USHORT id_range_offset
;
2404 } cmap_format_4_seg
;
2406 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2408 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
2409 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
2410 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2411 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2412 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2415 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2418 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2422 for(i
= 0; i
< 256; i
++)
2424 if(cmap
->glyph_ids
[i
] == 0) continue;
2426 if(*first
== 256) *first
= i
;
2428 if(*first
== 256) return FALSE
;
2432 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2434 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2435 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2436 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2437 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2438 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2441 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2444 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2445 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2446 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2450 for(i
= 0; i
< seg_count
; i
++)
2453 cmap_format_4_seg seg
;
2455 get_seg4(cmap
, i
, &seg
);
2456 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2458 if(seg
.id_range_offset
== 0)
2459 index
= (seg
.id_delta
+ code
) & 0xffff;
2462 index
= seg
.id_range_offset
/ 2
2463 + code
- seg
.start_count
2466 /* some fonts have broken last segment */
2467 if ((char *)(glyph_ids
+ index
+ sizeof(*glyph_ids
)) < (char *)ptr
+ limit
)
2468 index
= GET_BE_WORD(glyph_ids
[index
]);
2471 trace("segment %04x/%04x index %04x points to nowhere\n",
2472 seg
.start_count
, seg
.end_count
, index
);
2475 if(index
) index
+= seg
.id_delta
;
2477 if(*first
== 0x10000)
2478 *last
= *first
= code
;
2484 if(*first
== 0x10000) return FALSE
;
2488 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2491 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2493 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2495 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2496 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2509 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2512 cmap_header
*header
;
2517 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2518 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2519 if(size
== GDI_ERROR
) return FALSE
;
2521 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2522 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2523 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2524 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2526 cmap
= get_cmap(header
, 3, 1);
2528 *cmap_type
= cmap_ms_unicode
;
2531 cmap
= get_cmap(header
, 3, 0);
2532 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2536 *cmap_type
= cmap_none
;
2540 format
= GET_BE_WORD(*(WORD
*)cmap
);
2544 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2547 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2550 trace("unhandled cmap format %d\n", format
);
2555 HeapFree(GetProcessHeap(), 0, header
);
2559 #define TT_PLATFORM_MICROSOFT 3
2560 #define TT_MS_ID_UNICODE_CS 1
2561 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2562 #define TT_NAME_ID_FULL_NAME 4
2564 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, char *out_buf
, SIZE_T out_size
)
2566 struct sfnt_name_header
2569 USHORT number_of_record
;
2570 USHORT storage_offset
;
2582 LONG size
, offset
, length
;
2588 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
2589 ok(size
!= GDI_ERROR
, "no name table found\n");
2590 if(size
== GDI_ERROR
) return FALSE
;
2592 data
= HeapAlloc(GetProcessHeap(), 0, size
);
2593 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
2594 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2596 header
= (void *)data
;
2597 header
->format
= GET_BE_WORD(header
->format
);
2598 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
2599 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
2600 if (header
->format
!= 0)
2602 trace("got format %u\n", header
->format
);
2605 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
2607 trace("number records out of range: %d\n", header
->number_of_record
);
2610 if (header
->storage_offset
>= size
)
2612 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
2616 entry
= (void *)&header
[1];
2617 for (i
= 0; i
< header
->number_of_record
; i
++)
2619 if (GET_BE_WORD(entry
[i
].platform_id
) != TT_PLATFORM_MICROSOFT
||
2620 GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_UNICODE_CS
||
2621 GET_BE_WORD(entry
[i
].language_id
) != TT_MS_LANGID_ENGLISH_UNITED_STATES
||
2622 GET_BE_WORD(entry
[i
].name_id
) != name_id
)
2627 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[i
].offset
);
2628 length
= GET_BE_WORD(entry
[i
].length
);
2629 if (offset
+ length
> size
)
2631 trace("entry %d is out of range\n", i
);
2634 if (length
>= out_size
)
2636 trace("buffer too small for entry %d\n", i
);
2640 name
= (WCHAR
*)(data
+ offset
);
2641 for (c
= 0; c
< length
/ 2; c
++)
2642 out_buf
[c
] = GET_BE_WORD(name
[c
]);
2650 HeapFree(GetProcessHeap(), 0, data
);
2654 static void test_text_metrics(const LOGFONTA
*lf
)
2657 HFONT hfont
, hfont_old
;
2661 const char *font_name
= lf
->lfFaceName
;
2662 DWORD cmap_first
= 0, cmap_last
= 0;
2663 cmap_type cmap_type
;
2664 BOOL sys_lang_non_english
;
2666 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
2669 SetLastError(0xdeadbeef);
2670 hfont
= CreateFontIndirectA(lf
);
2671 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2673 hfont_old
= SelectObject(hdc
, hfont
);
2675 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2676 if (size
== GDI_ERROR
)
2678 trace("OS/2 chunk was not found\n");
2681 if (size
> sizeof(tt_os2
))
2683 trace("got too large OS/2 chunk of size %u\n", size
);
2684 size
= sizeof(tt_os2
);
2687 memset(&tt_os2
, 0, sizeof(tt_os2
));
2688 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2689 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2691 SetLastError(0xdeadbeef);
2692 ret
= GetTextMetricsA(hdc
, &tmA
);
2693 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2695 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
2697 skip("Unable to retrieve first and last glyphs from cmap\n");
2701 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
2702 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
2703 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
2707 version
= GET_BE_WORD(tt_os2
.version
);
2709 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2710 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2711 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2712 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2714 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2715 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
2716 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
2718 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
2723 case 1257: /* Baltic */
2724 expect_last_W
= 0xf8fd;
2727 expect_last_W
= 0xf0ff;
2729 expect_break_W
= 0x20;
2730 expect_default_W
= expect_break_W
- 1;
2731 expect_first_A
= 0x1e;
2732 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
2736 expect_first_W
= cmap_first
;
2737 expect_last_W
= min(cmap_last
, os2_last_char
);
2738 if(os2_first_char
<= 1)
2739 expect_break_W
= os2_first_char
+ 2;
2740 else if(os2_first_char
> 0xff)
2741 expect_break_W
= 0x20;
2743 expect_break_W
= os2_first_char
;
2744 expect_default_W
= expect_break_W
- 1;
2745 expect_first_A
= expect_default_W
- 1;
2746 expect_last_A
= min(expect_last_W
, 0xff);
2748 expect_break_A
= expect_break_W
;
2749 expect_default_A
= expect_default_W
;
2751 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2752 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
2753 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
2754 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2755 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2757 ok(tmA
.tmFirstChar
== expect_first_A
||
2758 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2759 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2760 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
2761 ok(tmA
.tmLastChar
== expect_last_A
||
2762 tmA
.tmLastChar
== 0xff /* win9x */,
2763 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
2765 skip("tmLastChar is DBCS lead byte\n");
2766 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
2767 font_name
, tmA
.tmBreakChar
, expect_break_A
);
2768 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
2769 "A: tmDefaultChar for %s got %02x expected %02x\n",
2770 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
2773 SetLastError(0xdeadbeef);
2774 ret
= GetTextMetricsW(hdc
, &tmW
);
2775 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2776 "GetTextMetricsW error %u\n", GetLastError());
2779 /* Wine uses the os2 first char */
2780 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
2781 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2782 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2784 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2785 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2787 /* Wine uses the os2 last char */
2788 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
2789 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2790 font_name
, tmW
.tmLastChar
, expect_last_W
);
2792 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2793 font_name
, tmW
.tmLastChar
, expect_last_W
);
2794 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
2795 font_name
, tmW
.tmBreakChar
, expect_break_W
);
2796 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
2797 "W: tmDefaultChar for %s got %02x expected %02x\n",
2798 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
2800 /* Test the aspect ratio while we have tmW */
2801 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2802 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2803 tmW
.tmDigitizedAspectX
, ret
);
2804 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2805 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2806 tmW
.tmDigitizedAspectX
, ret
);
2810 /* test FF_ values */
2811 switch(tt_os2
.panose
.bFamilyType
)
2815 case PAN_FAMILY_TEXT_DISPLAY
:
2816 case PAN_FAMILY_PICTORIAL
:
2818 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
2819 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
2821 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
2824 switch(tt_os2
.panose
.bSerifStyle
)
2829 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
2832 case PAN_SERIF_COVE
:
2833 case PAN_SERIF_OBTUSE_COVE
:
2834 case PAN_SERIF_SQUARE_COVE
:
2835 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
2836 case PAN_SERIF_SQUARE
:
2837 case PAN_SERIF_THIN
:
2838 case PAN_SERIF_BONE
:
2839 case PAN_SERIF_EXAGGERATED
:
2840 case PAN_SERIF_TRIANGLE
:
2841 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
2844 case PAN_SERIF_NORMAL_SANS
:
2845 case PAN_SERIF_OBTUSE_SANS
:
2846 case PAN_SERIF_PERP_SANS
:
2847 case PAN_SERIF_FLARED
:
2848 case PAN_SERIF_ROUNDED
:
2849 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
2854 case PAN_FAMILY_SCRIPT
:
2855 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
2858 case PAN_FAMILY_DECORATIVE
:
2859 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
2863 test_negative_width(hdc
, lf
);
2866 SelectObject(hdc
, hfont_old
);
2867 DeleteObject(hfont
);
2872 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2874 INT
*enumed
= (INT
*)lParam
;
2876 if (type
== TRUETYPE_FONTTYPE
)
2879 test_text_metrics(lf
);
2884 static void test_GetTextMetrics(void)
2890 /* Report only once */
2891 if(!pGetGlyphIndicesA
)
2892 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2896 memset(&lf
, 0, sizeof(lf
));
2897 lf
.lfCharSet
= DEFAULT_CHARSET
;
2899 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2900 trace("Tested metrics of %d truetype fonts\n", enumed
);
2905 static void test_nonexistent_font(void)
2913 { "Times New Roman Baltic", 186 },
2914 { "Times New Roman CE", 238 },
2915 { "Times New Roman CYR", 204 },
2916 { "Times New Roman Greek", 161 },
2917 { "Times New Roman TUR", 162 }
2923 INT cs
, expected_cs
, i
;
2924 char buf
[LF_FACESIZE
];
2926 if (!is_truetype_font_installed("Arial") ||
2927 !is_truetype_font_installed("Times New Roman"))
2929 skip("Arial or Times New Roman not installed\n");
2933 expected_cs
= GetACP();
2934 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
2936 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
2939 expected_cs
= csi
.ciCharset
;
2940 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
2944 memset(&lf
, 0, sizeof(lf
));
2946 lf
.lfWeight
= FW_REGULAR
;
2947 lf
.lfCharSet
= ANSI_CHARSET
;
2948 lf
.lfPitchAndFamily
= FF_SWISS
;
2949 strcpy(lf
.lfFaceName
, "Nonexistent font");
2950 hfont
= CreateFontIndirectA(&lf
);
2951 hfont
= SelectObject(hdc
, hfont
);
2952 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2953 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
2954 cs
= GetTextCharset(hdc
);
2955 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2956 DeleteObject(SelectObject(hdc
, hfont
));
2958 memset(&lf
, 0, sizeof(lf
));
2960 lf
.lfWeight
= FW_DONTCARE
;
2961 strcpy(lf
.lfFaceName
, "Nonexistent font");
2962 hfont
= CreateFontIndirectA(&lf
);
2963 hfont
= SelectObject(hdc
, hfont
);
2964 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2965 todo_wine
/* Wine uses Arial for all substitutions */
2966 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
2967 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
2968 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2970 cs
= GetTextCharset(hdc
);
2971 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
2972 DeleteObject(SelectObject(hdc
, hfont
));
2974 memset(&lf
, 0, sizeof(lf
));
2976 lf
.lfWeight
= FW_REGULAR
;
2977 strcpy(lf
.lfFaceName
, "Nonexistent font");
2978 hfont
= CreateFontIndirectA(&lf
);
2979 hfont
= SelectObject(hdc
, hfont
);
2980 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2981 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2982 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
2983 cs
= GetTextCharset(hdc
);
2984 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2985 DeleteObject(SelectObject(hdc
, hfont
));
2987 memset(&lf
, 0, sizeof(lf
));
2989 lf
.lfWeight
= FW_DONTCARE
;
2990 strcpy(lf
.lfFaceName
, "Times New Roman");
2991 hfont
= CreateFontIndirectA(&lf
);
2992 hfont
= SelectObject(hdc
, hfont
);
2993 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2994 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
2995 cs
= GetTextCharset(hdc
);
2996 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2997 DeleteObject(SelectObject(hdc
, hfont
));
2999 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
3001 memset(&lf
, 0, sizeof(lf
));
3003 lf
.lfWeight
= FW_REGULAR
;
3004 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3005 hfont
= CreateFontIndirectA(&lf
);
3006 hfont
= SelectObject(hdc
, hfont
);
3007 cs
= GetTextCharset(hdc
);
3008 if (font_subst
[i
].charset
== expected_cs
)
3010 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3011 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3012 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
3016 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
3017 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3018 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3019 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
3021 DeleteObject(SelectObject(hdc
, hfont
));
3023 memset(&lf
, 0, sizeof(lf
));
3025 lf
.lfWeight
= FW_DONTCARE
;
3026 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3027 hfont
= CreateFontIndirectA(&lf
);
3028 hfont
= SelectObject(hdc
, hfont
);
3029 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3030 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
3031 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
3032 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
3033 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3034 "got %s for font %s\n", buf
, font_subst
[i
].name
);
3035 cs
= GetTextCharset(hdc
);
3036 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3037 DeleteObject(SelectObject(hdc
, hfont
));
3043 static void test_GdiRealizationInfo(void)
3048 HFONT hfont
, hfont_old
;
3051 if(!pGdiRealizationInfo
)
3053 win_skip("GdiRealizationInfo not available\n");
3059 memset(info
, 0xcc, sizeof(info
));
3060 r
= pGdiRealizationInfo(hdc
, info
);
3061 ok(r
!= 0, "ret 0\n");
3062 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
3063 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3065 if (!is_truetype_font_installed("Arial"))
3067 skip("skipping GdiRealizationInfo with truetype font\n");
3071 memset(&lf
, 0, sizeof(lf
));
3072 strcpy(lf
.lfFaceName
, "Arial");
3074 lf
.lfWeight
= FW_NORMAL
;
3075 hfont
= CreateFontIndirectA(&lf
);
3076 hfont_old
= SelectObject(hdc
, hfont
);
3078 memset(info
, 0xcc, sizeof(info
));
3079 r
= pGdiRealizationInfo(hdc
, info
);
3080 ok(r
!= 0, "ret 0\n");
3081 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
3082 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3084 DeleteObject(SelectObject(hdc
, hfont_old
));
3090 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3091 the nul in the count of characters copied when the face name buffer is not
3092 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3093 always includes it. */
3094 static void test_GetTextFace(void)
3096 static const char faceA
[] = "Tahoma";
3097 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
3100 char bufA
[LF_FACESIZE
];
3101 WCHAR bufW
[LF_FACESIZE
];
3106 if(!is_font_installed("Tahoma"))
3108 skip("Tahoma is not installed so skipping this test\n");
3113 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
3114 f
= CreateFontIndirectA(&fA
);
3115 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
3118 g
= SelectObject(dc
, f
);
3119 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
3120 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
3121 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
3123 /* Play with the count arg. */
3125 n
= GetTextFaceA(dc
, 0, bufA
);
3126 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3127 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3130 n
= GetTextFaceA(dc
, 1, bufA
);
3131 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3132 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3134 bufA
[0] = 'x'; bufA
[1] = 'y';
3135 n
= GetTextFaceA(dc
, 2, bufA
);
3136 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
3137 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
3139 n
= GetTextFaceA(dc
, 0, NULL
);
3140 ok(n
== sizeof faceA
||
3141 broken(n
== 0), /* win98, winMe */
3142 "GetTextFaceA returned %d\n", n
);
3144 DeleteObject(SelectObject(dc
, g
));
3145 ReleaseDC(NULL
, dc
);
3148 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3149 SetLastError(0xdeadbeef);
3150 f
= CreateFontIndirectW(&fW
);
3151 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3153 win_skip("CreateFontIndirectW is not implemented\n");
3156 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3159 g
= SelectObject(dc
, f
);
3160 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3161 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3162 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3164 /* Play with the count arg. */
3166 n
= GetTextFaceW(dc
, 0, bufW
);
3167 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3168 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3171 n
= GetTextFaceW(dc
, 1, bufW
);
3172 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3173 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3175 bufW
[0] = 'x'; bufW
[1] = 'y';
3176 n
= GetTextFaceW(dc
, 2, bufW
);
3177 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
3178 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
3180 n
= GetTextFaceW(dc
, 0, NULL
);
3181 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3183 DeleteObject(SelectObject(dc
, g
));
3184 ReleaseDC(NULL
, dc
);
3187 static void test_orientation(void)
3189 static const char test_str
[11] = "Test String";
3192 HFONT hfont
, old_hfont
;
3195 if (!is_truetype_font_installed("Arial"))
3197 skip("Arial is not installed\n");
3201 hdc
= CreateCompatibleDC(0);
3202 memset(&lf
, 0, sizeof(lf
));
3203 lstrcpyA(lf
.lfFaceName
, "Arial");
3205 lf
.lfOrientation
= lf
.lfEscapement
= 900;
3206 hfont
= create_font("orientation", &lf
);
3207 old_hfont
= SelectObject(hdc
, hfont
);
3208 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
3209 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
3210 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
3211 SelectObject(hdc
, old_hfont
);
3212 DeleteObject(hfont
);
3216 static void test_oemcharset(void)
3220 HFONT hfont
, old_hfont
;
3223 hdc
= CreateCompatibleDC(0);
3224 ZeroMemory(&lf
, sizeof(lf
));
3226 lf
.lfCharSet
= OEM_CHARSET
;
3227 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
3228 lstrcpyA(lf
.lfFaceName
, "Terminal");
3229 hfont
= CreateFontIndirectA(&lf
);
3230 old_hfont
= SelectObject(hdc
, hfont
);
3231 charset
= GetTextCharset(hdc
);
3233 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
3234 hfont
= SelectObject(hdc
, old_hfont
);
3235 GetObjectA(hfont
, sizeof(clf
), &clf
);
3236 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
3237 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
3238 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
3239 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
3240 DeleteObject(hfont
);
3244 static void test_GetGlyphOutline(void)
3247 GLYPHMETRICS gm
, gm2
;
3249 HFONT hfont
, old_hfont
;
3258 {ANSI_CHARSET
, 0x30, 0x30},
3259 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
3260 {HANGEUL_CHARSET
, 0x8141, 0xac02},
3261 {JOHAB_CHARSET
, 0x8446, 0x3135},
3262 {GB2312_CHARSET
, 0x8141, 0x4e04},
3263 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
3267 if (!is_truetype_font_installed("Tahoma"))
3269 skip("Tahoma is not installed\n");
3273 hdc
= CreateCompatibleDC(0);
3274 memset(&lf
, 0, sizeof(lf
));
3276 lstrcpyA(lf
.lfFaceName
, "Tahoma");
3277 SetLastError(0xdeadbeef);
3278 hfont
= CreateFontIndirectA(&lf
);
3279 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
3280 old_hfont
= SelectObject(hdc
, hfont
);
3282 memset(&gm
, 0, sizeof(gm
));
3283 SetLastError(0xdeadbeef);
3284 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3285 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3287 memset(&gm
, 0, sizeof(gm
));
3288 SetLastError(0xdeadbeef);
3289 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3290 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
3291 ok(GetLastError() == 0xdeadbeef ||
3292 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
3293 "expected 0xdeadbeef, got %u\n", GetLastError());
3295 memset(&gm
, 0, sizeof(gm
));
3296 SetLastError(0xdeadbeef);
3297 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3298 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3299 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
3301 memset(&gm
, 0, sizeof(gm
));
3302 SetLastError(0xdeadbeef);
3303 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3304 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3306 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
3307 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3310 /* test for needed buffer size request on space char */
3311 memset(&gm
, 0, sizeof(gm
));
3312 SetLastError(0xdeadbeef);
3313 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3314 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3315 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3317 /* requesting buffer size for space char + error */
3318 memset(&gm
, 0, sizeof(gm
));
3319 SetLastError(0xdeadbeef);
3320 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3321 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3323 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3324 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3327 SelectObject(hdc
, old_hfont
);
3328 DeleteObject(hfont
);
3330 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
3332 lf
.lfFaceName
[0] = '\0';
3333 lf
.lfCharSet
= c
[i
].cs
;
3334 lf
.lfPitchAndFamily
= 0;
3335 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
3337 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
3341 old_hfont
= SelectObject(hdc
, hfont
);
3343 /* expected to ignore superfluous bytes (sigle-byte character) */
3344 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3345 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3346 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3348 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3349 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3350 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3352 /* expected to ignore superfluous bytes (double-byte character) */
3353 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3354 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3355 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3356 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3358 /* expected to match wide-char version results */
3359 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3360 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3362 hfont
= SelectObject(hdc
, old_hfont
);
3363 DeleteObject(hfont
);
3369 /* bug #9995: there is a limit to the character width that can be specified */
3370 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3376 int ave_width
, height
, width
, ratio
, scale
;
3378 if (!is_truetype_font_installed( fontname
)) {
3379 skip("%s is not installed\n", fontname
);
3382 hdc
= CreateCompatibleDC(0);
3383 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3384 /* select width = 0 */
3385 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3386 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3387 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3389 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3390 of
= SelectObject( hdc
, hf
);
3391 ret
= GetTextMetricsA( hdc
, &tm
);
3392 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3393 height
= tm
.tmHeight
;
3394 ave_width
= tm
.tmAveCharWidth
;
3395 SelectObject( hdc
, of
);
3398 trace("height %d, ave width %d\n", height
, ave_width
);
3400 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3402 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3403 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3404 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3405 ok(hf
!= 0, "CreateFont failed\n");
3406 of
= SelectObject(hdc
, hf
);
3407 ret
= GetTextMetrics(hdc
, &tm
);
3408 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3409 SelectObject(hdc
, of
);
3412 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3418 ratio
= width
/ height
;
3419 scale
= width
/ ave_width
;
3421 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3422 width
, height
, ratio
, width
, ave_width
, scale
);
3424 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3427 static void test_CreateFontIndirect(void)
3429 LOGFONTA lf
, getobj_lf
;
3432 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3434 memset(&lf
, 0, sizeof(lf
));
3435 lf
.lfCharSet
= ANSI_CHARSET
;
3436 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3439 lf
.lfQuality
= DEFAULT_QUALITY
;
3440 lf
.lfItalic
= FALSE
;
3441 lf
.lfWeight
= FW_DONTCARE
;
3443 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3445 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3446 hfont
= CreateFontIndirectA(&lf
);
3447 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3448 SetLastError(0xdeadbeef);
3449 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3450 ok(ret
, "GetObject failed: %d\n", GetLastError());
3451 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3452 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3453 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3454 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3455 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3456 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3457 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3458 DeleteObject(hfont
);
3462 static void test_CreateFontIndirectEx(void)
3464 ENUMLOGFONTEXDVA lfex
;
3467 if (!pCreateFontIndirectExA
)
3469 win_skip("CreateFontIndirectExA is not available\n");
3473 if (!is_truetype_font_installed("Arial"))
3475 skip("Arial is not installed\n");
3479 SetLastError(0xdeadbeef);
3480 hfont
= pCreateFontIndirectExA(NULL
);
3481 ok(hfont
== NULL
, "got %p\n", hfont
);
3482 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3484 memset(&lfex
, 0, sizeof(lfex
));
3485 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3486 hfont
= pCreateFontIndirectExA(&lfex
);
3487 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3489 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3490 DeleteObject(hfont
);
3493 static void free_font(void *font
)
3495 UnmapViewOfFile(font
);
3498 static void *load_font(const char *font_name
, DWORD
*font_size
)
3500 char file_name
[MAX_PATH
];
3501 HANDLE file
, mapping
;
3504 if (!GetWindowsDirectory(file_name
, sizeof(file_name
))) return NULL
;
3505 strcat(file_name
, "\\fonts\\");
3506 strcat(file_name
, font_name
);
3508 file
= CreateFile(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3509 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
3511 *font_size
= GetFileSize(file
, NULL
);
3513 mapping
= CreateFileMapping(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
3520 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
3523 CloseHandle(mapping
);
3527 static void test_AddFontMemResource(void)
3530 DWORD font_size
, num_fonts
;
3534 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
3536 win_skip("AddFontMemResourceEx is not available on this platform\n");
3540 font
= load_font("sserife.fon", &font_size
);
3543 skip("Unable to locate and load font sserife.fon\n");
3547 SetLastError(0xdeadbeef);
3548 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
3549 ok(!ret
, "AddFontMemResourceEx should fail\n");
3550 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3551 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3554 SetLastError(0xdeadbeef);
3555 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
3556 ok(!ret
, "AddFontMemResourceEx should fail\n");
3557 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3558 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3561 SetLastError(0xdeadbeef);
3562 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
3563 ok(!ret
, "AddFontMemResourceEx should fail\n");
3564 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3565 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3568 SetLastError(0xdeadbeef);
3569 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
3570 ok(!ret
, "AddFontMemResourceEx should fail\n");
3571 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3572 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3575 SetLastError(0xdeadbeef);
3576 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
3577 ok(!ret
, "AddFontMemResourceEx should fail\n");
3578 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3579 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3582 SetLastError(0xdeadbeef);
3583 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
3584 ok(!ret
, "AddFontMemResourceEx should fail\n");
3585 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3586 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3589 num_fonts
= 0xdeadbeef;
3590 SetLastError(0xdeadbeef);
3591 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
3592 ok(!ret
, "AddFontMemResourceEx should fail\n");
3593 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3594 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3596 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3598 if (0) /* hangs under windows 2000 */
3600 num_fonts
= 0xdeadbeef;
3601 SetLastError(0xdeadbeef);
3602 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
3603 ok(!ret
, "AddFontMemResourceEx should fail\n");
3604 ok(GetLastError() == 0xdeadbeef,
3605 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3607 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3610 num_fonts
= 0xdeadbeef;
3611 SetLastError(0xdeadbeef);
3612 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
3613 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
3614 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3615 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
3619 SetLastError(0xdeadbeef);
3620 bRet
= pRemoveFontMemResourceEx(ret
);
3621 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
3623 /* test invalid pointer to number of loaded fonts */
3624 font
= load_font("sserife.fon", &font_size
);
3625 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
3627 SetLastError(0xdeadbeef);
3628 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
3629 ok(!ret
, "AddFontMemResourceEx should fail\n");
3630 ok(GetLastError() == 0xdeadbeef,
3631 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3634 SetLastError(0xdeadbeef);
3635 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
3636 ok(!ret
, "AddFontMemResourceEx should fail\n");
3637 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3638 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3644 static INT CALLBACK
enum_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3648 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3650 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3652 lf
= (LOGFONT
*)lparam
;
3657 static INT CALLBACK
enum_all_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3662 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3664 lf
= (LOGFONT
*)lparam
;
3665 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
3668 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3675 static void test_EnumFonts(void)
3681 if (!is_truetype_font_installed("Arial"))
3683 skip("Arial is not installed\n");
3687 /* Windows uses localized font face names, so Arial Bold won't be found */
3688 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
3690 skip("User locale is not English, skipping the test\n");
3694 hdc
= CreateCompatibleDC(0);
3696 ret
= EnumFontFamilies(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
3697 ok(!ret
, "font Arial is not enumerated\n");
3698 ret
= strcmp(lf
.lfFaceName
, "Arial");
3699 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3700 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
3702 lstrcpy(lf
.lfFaceName
, "Arial");
3703 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3704 ok(!ret
, "font Arial is not enumerated\n");
3705 ret
= strcmp(lf
.lfFaceName
, "Arial");
3706 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3707 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
3709 ret
= EnumFontFamilies(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
3710 ok(!ret
, "font Arial Bold is not enumerated\n");
3711 ret
= strcmp(lf
.lfFaceName
, "Arial");
3712 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3713 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
3715 lstrcpy(lf
.lfFaceName
, "Arial Bold");
3716 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3717 ok(ret
, "font Arial Bold should not be enumerated\n");
3719 ret
= EnumFontFamilies(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
3720 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
3721 ret
= strcmp(lf
.lfFaceName
, "Arial");
3722 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3723 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
3725 lstrcpy(lf
.lfFaceName
, "Arial Bold Italic");
3726 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3727 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
3729 ret
= EnumFontFamilies(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
3730 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
3732 lstrcpy(lf
.lfFaceName
, "Arial Italic Bold");
3733 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3734 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
3739 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
3741 const ENUMLOGFONT
*elf
= (const ENUMLOGFONT
*)lf
;
3742 const char *fullname
= (const char *)lParam
;
3744 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
3749 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
3754 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
3761 static void test_fullname(void)
3763 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3764 char buf
[LF_FULLFACESIZE
];
3770 hdc
= CreateCompatibleDC(0);
3771 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
3773 memset(&lf
, 0, sizeof(lf
));
3774 lf
.lfCharSet
= ANSI_CHARSET
;
3775 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3778 lf
.lfQuality
= DEFAULT_QUALITY
;
3779 lf
.lfItalic
= FALSE
;
3780 lf
.lfWeight
= FW_DONTCARE
;
3782 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
3784 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
3786 skip("%s is not installed\n", TestName
[i
]);
3790 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3791 hfont
= CreateFontIndirectA(&lf
);
3792 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3794 of
= SelectObject(hdc
, hfont
);
3796 ok(get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, buf
, sizeof(buf
)),
3797 "face full name could not be read\n");
3798 ok(!lstrcmpA(buf
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], buf
);
3799 SelectObject(hdc
, of
);
3800 DeleteObject(hfont
);
3805 static BOOL
write_ttf_file(char *tmp_name
)
3807 char tmp_path
[MAX_PATH
];
3814 SetLastError(0xdeadbeef);
3815 rsrc
= FindResource(GetModuleHandle(0), "wine_test.ttf", RT_RCDATA
);
3816 ok(rsrc
!= 0, "FindResource error %d\n", GetLastError());
3817 if (!rsrc
) return FALSE
;
3818 SetLastError(0xdeadbeef);
3819 rsrc_data
= LockResource(LoadResource(GetModuleHandle(0), rsrc
));
3820 ok(rsrc_data
!= 0, "LockResource error %d\n", GetLastError());
3821 if (!rsrc_data
) return FALSE
;
3822 SetLastError(0xdeadbeef);
3823 rsrc_size
= SizeofResource(GetModuleHandle(0), rsrc
);
3824 ok(rsrc_size
!= 0, "SizeofResource error %d\n", GetLastError());
3825 if (!rsrc_size
) return FALSE
;
3827 SetLastError(0xdeadbeef);
3828 ret
= GetTempPath(MAX_PATH
, tmp_path
);
3829 ok(ret
, "GetTempPath() error %d\n", GetLastError());
3830 SetLastError(0xdeadbeef);
3831 ret
= GetTempFileName(tmp_path
, "ttf", 0, tmp_name
);
3832 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
3834 SetLastError(0xdeadbeef);
3835 hfile
= CreateFile(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
3836 ok(hfile
!= INVALID_HANDLE_VALUE
, "CreateFile() error %d\n", GetLastError());
3837 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
3839 SetLastError(0xdeadbeef);
3840 ret
= WriteFile(hfile
, rsrc_data
, rsrc_size
, &rsrc_size
, NULL
);
3841 ok(ret
, "WriteFile() error %d\n", GetLastError());
3847 static void test_CreateScalableFontResource(void)
3849 char ttf_name
[MAX_PATH
];
3850 char tmp_path
[MAX_PATH
];
3851 char fot_name
[MAX_PATH
];
3855 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
3857 win_skip("AddFontResourceExA is not available on this platform\n");
3861 if (!write_ttf_file(ttf_name
))
3863 skip("Failed to create ttf file for testing\n");
3867 trace("created %s\n", ttf_name
);
3869 ret
= is_truetype_font_installed("wine_test");
3870 ok(!ret
, "font wine_test should not be enumerated\n");
3872 ret
= GetTempPath(MAX_PATH
, tmp_path
);
3873 ok(ret
, "GetTempPath() error %d\n", GetLastError());
3874 ret
= GetTempFileName(tmp_path
, "fot", 0, fot_name
);
3875 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
3877 ret
= GetFileAttributes(fot_name
);
3878 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
3880 SetLastError(0xdeadbeef);
3881 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
3882 ok(!ret
, "CreateScalableFontResource() should fail\n");
3883 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
3885 SetLastError(0xdeadbeef);
3886 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, "");
3887 ok(!ret
, "CreateScalableFontResource() should fail\n");
3888 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
3890 file_part
= strrchr(ttf_name
, '\\');
3891 SetLastError(0xdeadbeef);
3892 ret
= CreateScalableFontResource(0, fot_name
, file_part
, tmp_path
);
3893 ok(!ret
, "CreateScalableFontResource() should fail\n");
3894 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
3896 SetLastError(0xdeadbeef);
3897 ret
= CreateScalableFontResource(0, fot_name
, "random file name", tmp_path
);
3898 ok(!ret
, "CreateScalableFontResource() should fail\n");
3900 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
3902 SetLastError(0xdeadbeef);
3903 ret
= CreateScalableFontResource(0, fot_name
, NULL
, ttf_name
);
3904 ok(!ret
, "CreateScalableFontResource() should fail\n");
3906 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
3908 ret
= DeleteFile(fot_name
);
3909 ok(ret
, "DeleteFile() error %d\n", GetLastError());
3911 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
3913 ok(!ret
, "RemoveFontResourceEx() should fail\n");
3915 /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3918 /* test public font resource */
3919 SetLastError(0xdeadbeef);
3920 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
3921 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
3923 ret
= is_truetype_font_installed("wine_test");
3924 ok(!ret
, "font wine_test should not be enumerated\n");
3926 SetLastError(0xdeadbeef);
3927 ret
= pAddFontResourceExA(fot_name
, 0, 0);
3928 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
3930 ret
= is_truetype_font_installed("wine_test");
3931 ok(ret
, "font wine_test should be enumerated\n");
3933 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
3934 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
3936 SetLastError(0xdeadbeef);
3937 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
3939 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
3941 ret
= is_truetype_font_installed("wine_test");
3943 ok(!ret
, "font wine_test should not be enumerated\n");
3945 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
3948 /* remove once RemoveFontResource is implemented */
3949 DeleteFile(fot_name
);
3950 DeleteFile(ttf_name
);
3954 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
3955 ok(!ret
, "RemoveFontResourceEx() should fail\n");
3957 DeleteFile(fot_name
);
3959 /* test hidden font resource */
3960 SetLastError(0xdeadbeef);
3961 ret
= CreateScalableFontResource(1, fot_name
, ttf_name
, NULL
);
3962 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
3964 ret
= is_truetype_font_installed("wine_test");
3965 ok(!ret
, "font wine_test should not be enumerated\n");
3967 SetLastError(0xdeadbeef);
3968 ret
= pAddFontResourceExA(fot_name
, 0, 0);
3969 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
3971 ret
= is_truetype_font_installed("wine_test");
3972 ok(!ret
, "font wine_test should not be enumerated\n");
3974 /* XP allows removing a private font added with 0 flags */
3975 SetLastError(0xdeadbeef);
3976 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
3977 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
3979 ret
= is_truetype_font_installed("wine_test");
3980 ok(!ret
, "font wine_test should not be enumerated\n");
3982 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
3983 ok(!ret
, "RemoveFontResourceEx() should fail\n");
3985 DeleteFile(fot_name
);
3986 DeleteFile(ttf_name
);
3995 test_outline_font();
3996 test_bitmap_font_metrics();
3997 test_GdiGetCharDimensions();
3998 test_GetCharABCWidths();
3999 test_text_extents();
4000 test_GetGlyphIndices();
4001 test_GetKerningPairs();
4002 test_GetOutlineTextMetrics();
4003 test_SetTextJustification();
4004 test_font_charset();
4005 test_GetFontUnicodeRanges();
4006 test_nonexistent_font();
4008 test_height_selection();
4009 test_AddFontMemResource();
4012 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4013 * I'd like to avoid them in this test.
4015 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
4016 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
4017 if (is_truetype_font_installed("Arial Black") &&
4018 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4020 test_EnumFontFamilies("", ANSI_CHARSET
);
4021 test_EnumFontFamilies("", SYMBOL_CHARSET
);
4022 test_EnumFontFamilies("", DEFAULT_CHARSET
);
4025 skip("Arial Black or Symbol/Wingdings is not installed\n");
4026 test_EnumFontFamiliesEx_default_charset();
4027 test_GetTextMetrics();
4028 test_GdiRealizationInfo();
4030 test_GetGlyphOutline();
4031 test_GetTextMetrics2("Tahoma", -11);
4032 test_GetTextMetrics2("Tahoma", -55);
4033 test_GetTextMetrics2("Tahoma", -110);
4034 test_GetTextMetrics2("Arial", -11);
4035 test_GetTextMetrics2("Arial", -55);
4036 test_GetTextMetrics2("Arial", -110);
4037 test_CreateFontIndirect();
4038 test_CreateFontIndirectEx();
4042 /* CreateScalableFontResource should be last test until RemoveFontResource
4043 * is properly implemented.
4045 test_CreateScalableFontResource();