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
);
52 static HMODULE hgdi32
= 0;
53 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
55 static void init(void)
57 hgdi32
= GetModuleHandleA("gdi32.dll");
59 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
60 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
61 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
62 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
63 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
64 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
65 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
66 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
67 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
68 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
69 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
70 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
73 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
75 if (type
!= TRUETYPE_FONTTYPE
) return 1;
80 static BOOL
is_truetype_font_installed(const char *name
)
85 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
92 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
97 static BOOL
is_font_installed(const char *name
)
102 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
109 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
117 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
118 /* NT4 tries to be clever and only returns the minimum length */
119 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
121 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
122 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
123 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
124 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
125 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
126 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
127 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
128 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
129 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
130 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
131 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
132 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
133 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
134 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
135 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
136 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
137 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
138 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
139 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
140 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
141 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
142 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
143 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
144 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
145 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
146 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
147 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
148 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
151 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
153 HFONT hfont
= CreateFontIndirectA(lf
);
154 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
156 check_font(test
, lf
, hfont
);
160 static void test_logfont(void)
165 memset(&lf
, 0, sizeof lf
);
167 lf
.lfCharSet
= ANSI_CHARSET
;
168 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
169 lf
.lfWeight
= FW_DONTCARE
;
172 lf
.lfQuality
= DEFAULT_QUALITY
;
174 lstrcpyA(lf
.lfFaceName
, "Arial");
175 hfont
= create_font("Arial", &lf
);
178 memset(&lf
, 'A', sizeof(lf
));
179 hfont
= CreateFontIndirectA(&lf
);
180 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
182 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
183 check_font("AAA...", &lf
, hfont
);
187 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
189 if (type
& RASTER_FONTTYPE
)
191 LOGFONT
*lf
= (LOGFONT
*)lParam
;
193 return 0; /* stop enumeration */
196 return 1; /* continue enumeration */
199 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
201 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
202 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
203 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
204 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
205 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
206 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
207 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
208 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
209 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
210 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
211 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
212 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
213 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
214 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
215 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
216 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
217 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
218 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
219 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
220 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
223 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
224 LONG lfWidth
, const char *test_str
,
225 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
226 const SIZE
*size_orig
, INT width_of_A_orig
,
227 INT scale_x
, INT scale_y
)
230 OUTLINETEXTMETRIC otm
;
233 INT width_of_A
, cx
, cy
;
239 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
241 GetObjectA(hfont
, sizeof(lf
), &lf
);
243 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
245 otm
.otmSize
= sizeof(otm
) / 2;
246 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
247 ok(ret
== sizeof(otm
)/2 /* XP */ ||
248 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
250 memset(&otm
, 0x1, sizeof(otm
));
251 otm
.otmSize
= sizeof(otm
);
252 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
253 ok(ret
== sizeof(otm
) /* XP */ ||
254 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
256 memset(&tm
, 0x2, sizeof(tm
));
257 ret
= GetTextMetricsA(hdc
, &tm
);
258 ok(ret
, "GetTextMetricsA failed\n");
259 /* the structure size is aligned */
260 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
262 ok(0, "tm != otm\n");
263 compare_tm(&tm
, &otm
.otmTextMetrics
);
266 tm
= otm
.otmTextMetrics
;
267 if (0) /* these metrics are scaled too, but with rounding errors */
269 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
270 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
272 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
273 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
274 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
275 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
276 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
277 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
281 ret
= GetTextMetricsA(hdc
, &tm
);
282 ok(ret
, "GetTextMetricsA failed\n");
285 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
286 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
287 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
288 lfHeight
, scale_x
, scale_y
, cx
, cy
);
289 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
290 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
291 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
292 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
293 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
295 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
299 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
302 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
304 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
306 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
307 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
309 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
311 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
);
314 /* Test how GDI scales bitmap font metrics */
315 static void test_bitmap_font(void)
317 static const char test_str
[11] = "Test String";
320 HFONT hfont
, old_hfont
;
323 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
327 /* "System" has only 1 pixel size defined, otherwise the test breaks */
328 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
332 trace("no bitmap fonts were found, skipping the test\n");
336 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
338 height_orig
= bitmap_lf
.lfHeight
;
339 lfWidth
= bitmap_lf
.lfWidth
;
341 hfont
= create_font("bitmap", &bitmap_lf
);
342 old_hfont
= SelectObject(hdc
, hfont
);
343 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
344 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
345 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
346 SelectObject(hdc
, old_hfont
);
349 bitmap_lf
.lfHeight
= 0;
350 bitmap_lf
.lfWidth
= 4;
351 hfont
= create_font("bitmap", &bitmap_lf
);
352 old_hfont
= SelectObject(hdc
, hfont
);
353 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
354 SelectObject(hdc
, old_hfont
);
357 bitmap_lf
.lfHeight
= height_orig
;
358 bitmap_lf
.lfWidth
= lfWidth
;
360 /* test fractional scaling */
361 for (i
= 1; i
<= height_orig
* 6; i
++)
365 bitmap_lf
.lfHeight
= i
;
366 hfont
= create_font("fractional", &bitmap_lf
);
367 scale
= (i
+ height_orig
- 1) / height_orig
;
368 nearest_height
= scale
* height_orig
;
369 /* Only jump to the next height if the difference <= 25% original height */
370 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
371 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
372 so we'll not test this particular height. */
373 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
374 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
375 old_hfont
= SelectObject(hdc
, hfont
);
376 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
377 SelectObject(hdc
, old_hfont
);
381 /* test integer scaling 3x2 */
382 bitmap_lf
.lfHeight
= height_orig
* 2;
383 bitmap_lf
.lfWidth
*= 3;
384 hfont
= create_font("3x2", &bitmap_lf
);
385 old_hfont
= SelectObject(hdc
, hfont
);
386 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
387 SelectObject(hdc
, old_hfont
);
390 /* test integer scaling 3x3 */
391 bitmap_lf
.lfHeight
= height_orig
* 3;
392 bitmap_lf
.lfWidth
= 0;
393 hfont
= create_font("3x3", &bitmap_lf
);
394 old_hfont
= SelectObject(hdc
, hfont
);
395 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
396 SelectObject(hdc
, old_hfont
);
402 /* Test how GDI scales outline font metrics */
403 static void test_outline_font(void)
405 static const char test_str
[11] = "Test String";
408 HFONT hfont
, old_hfont
, old_hfont_2
;
409 OUTLINETEXTMETRICA otm
;
411 INT width_orig
, height_orig
, lfWidth
;
414 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
418 if (!is_truetype_font_installed("Arial"))
420 skip("Arial is not installed\n");
424 hdc
= CreateCompatibleDC(0);
426 memset(&lf
, 0, sizeof(lf
));
427 strcpy(lf
.lfFaceName
, "Arial");
429 hfont
= create_font("outline", &lf
);
430 old_hfont
= SelectObject(hdc
, hfont
);
431 otm
.otmSize
= sizeof(otm
);
432 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
433 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
434 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
436 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
437 SelectObject(hdc
, old_hfont
);
440 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
441 lf
.lfHeight
= otm
.otmEMSquare
;
442 lf
.lfHeight
= -lf
.lfHeight
;
443 hfont
= create_font("outline", &lf
);
444 old_hfont
= SelectObject(hdc
, hfont
);
445 otm
.otmSize
= sizeof(otm
);
446 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
447 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
448 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
449 SelectObject(hdc
, old_hfont
);
452 height_orig
= otm
.otmTextMetrics
.tmHeight
;
453 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
455 /* test integer scaling 3x2 */
456 lf
.lfHeight
= height_orig
* 2;
457 lf
.lfWidth
= lfWidth
* 3;
458 hfont
= create_font("3x2", &lf
);
459 old_hfont
= SelectObject(hdc
, hfont
);
460 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
461 SelectObject(hdc
, old_hfont
);
464 /* test integer scaling 3x3 */
465 lf
.lfHeight
= height_orig
* 3;
466 lf
.lfWidth
= lfWidth
* 3;
467 hfont
= create_font("3x3", &lf
);
468 old_hfont
= SelectObject(hdc
, hfont
);
469 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
470 SelectObject(hdc
, old_hfont
);
473 /* test integer scaling 1x1 */
474 lf
.lfHeight
= height_orig
* 1;
475 lf
.lfWidth
= lfWidth
* 1;
476 hfont
= create_font("1x1", &lf
);
477 old_hfont
= SelectObject(hdc
, hfont
);
478 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
479 SelectObject(hdc
, old_hfont
);
482 /* test integer scaling 1x1 */
483 lf
.lfHeight
= height_orig
;
485 hfont
= create_font("1x1", &lf
);
486 old_hfont
= SelectObject(hdc
, hfont
);
487 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
489 /* with an identity matrix */
490 memset(&gm
, 0, sizeof(gm
));
491 SetLastError(0xdeadbeef);
492 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
493 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
495 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
496 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
497 /* with a custom matrix */
498 memset(&gm
, 0, sizeof(gm
));
499 SetLastError(0xdeadbeef);
500 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
501 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
502 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
503 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
504 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
506 /* Test that changing the DC transformation affects only the font
507 * selected on this DC and doesn't affect the same font selected on
510 hdc_2
= CreateCompatibleDC(0);
511 old_hfont_2
= SelectObject(hdc_2
, hfont
);
512 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
514 SetMapMode(hdc
, MM_ANISOTROPIC
);
516 /* font metrics on another DC should be unchanged */
517 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
519 /* test restrictions of compatibility mode GM_COMPATIBLE */
520 /* part 1: rescaling only X should not change font scaling on screen.
521 So compressing the X axis by 2 is not done, and this
522 appears as X scaling of 2 that no one requested. */
523 SetWindowExtEx(hdc
, 100, 100, NULL
);
524 SetViewportExtEx(hdc
, 50, 100, NULL
);
525 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
526 /* font metrics on another DC should be unchanged */
527 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
529 /* part 2: rescaling only Y should change font scaling.
530 As also X is scaled by a factor of 2, but this is not
531 requested by the DC transformation, we get a scaling factor
532 of 2 in the X coordinate. */
533 SetViewportExtEx(hdc
, 100, 200, NULL
);
534 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
535 /* font metrics on another DC should be unchanged */
536 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
538 /* restore scaling */
539 SetMapMode(hdc
, MM_TEXT
);
541 /* font metrics on another DC should be unchanged */
542 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
544 SelectObject(hdc_2
, old_hfont_2
);
547 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
549 SelectObject(hdc
, old_hfont
);
552 skip("GM_ADVANCED is not supported on this platform\n");
563 SetLastError(0xdeadbeef);
564 ret
= SetWorldTransform(hdc
, &xform
);
565 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
567 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
569 /* with an identity matrix */
570 memset(&gm
, 0, sizeof(gm
));
571 SetLastError(0xdeadbeef);
572 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
573 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
574 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
575 pt
.x
= width_orig
; pt
.y
= 0;
577 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
578 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
579 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
580 /* with a custom matrix */
581 memset(&gm
, 0, sizeof(gm
));
582 SetLastError(0xdeadbeef);
583 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
584 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
585 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
586 pt
.x
= width_orig
; pt
.y
= 0;
588 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
589 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
590 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
592 SetLastError(0xdeadbeef);
593 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
594 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
596 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
598 /* with an identity matrix */
599 memset(&gm
, 0, sizeof(gm
));
600 SetLastError(0xdeadbeef);
601 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
602 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
604 pt
.x
= width_orig
; pt
.y
= 0;
606 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
607 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
608 /* with a custom matrix */
609 memset(&gm
, 0, sizeof(gm
));
610 SetLastError(0xdeadbeef);
611 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
612 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
613 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
614 pt
.x
= width_orig
; pt
.y
= 0;
616 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
617 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
619 SetLastError(0xdeadbeef);
620 ret
= SetMapMode(hdc
, MM_TEXT
);
621 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
623 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
625 /* with an identity matrix */
626 memset(&gm
, 0, sizeof(gm
));
627 SetLastError(0xdeadbeef);
628 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
629 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
630 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
631 pt
.x
= width_orig
; pt
.y
= 0;
633 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
634 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
635 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
636 /* with a custom matrix */
637 memset(&gm
, 0, sizeof(gm
));
638 SetLastError(0xdeadbeef);
639 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
640 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
641 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
642 pt
.x
= width_orig
; pt
.y
= 0;
644 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
645 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
646 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
648 SelectObject(hdc
, old_hfont
);
653 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
655 LOGFONT
*lf
= (LOGFONT
*)lParam
;
657 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
660 return 0; /* stop enumeration */
662 return 1; /* continue enumeration */
665 static void test_bitmap_font_metrics(void)
667 static const struct font_data
669 const char face_name
[LF_FACESIZE
];
670 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
671 int ave_char_width
, max_char_width
, dpi
;
676 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
677 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
678 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1
| FS_CYRILLIC
},
679 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2
},
680 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1
},
681 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2
},
682 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC
},
683 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1
},
684 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2
},
685 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC
},
686 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
688 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
689 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_LATIN2
},
690 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC
},
691 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
692 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1
| FS_LATIN2
},
693 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC
},
694 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
695 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
697 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
698 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
699 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
700 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
},
701 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2
| FS_CYRILLIC
},
702 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1
| FS_LATIN2
},
703 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC
},
704 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1
| FS_LATIN2
},
705 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC
},
706 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1
},
707 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2
},
708 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC
},
709 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1
},
710 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2
},
711 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC
},
712 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1
| FS_LATIN2
},
713 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC
},
715 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1
| FS_CYRILLIC
},
716 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2
},
717 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_CYRILLIC
},
718 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2
},
719 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1
| FS_CYRILLIC
},
720 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2
},
721 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1
| FS_LATIN2
},
722 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC
},
723 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1
| FS_LATIN2
},
724 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC
},
725 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
727 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
728 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
729 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
731 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
732 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
733 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
735 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
},
736 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2
| FS_CYRILLIC
},
737 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN
},
739 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1
},
740 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2
| FS_CYRILLIC
},
742 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1
},
743 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
744 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN
},
745 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1
, LANG_ARABIC
},
746 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
747 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN
},
748 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1
, LANG_ARABIC
},
749 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
750 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, FS_ARABIC
},
751 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN
},
752 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1
, LANG_ARABIC
},
753 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
754 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, FS_ARABIC
},
755 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN
},
756 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
757 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
758 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, FS_ARABIC
},
759 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN
},
760 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
761 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, FS_ARABIC
},
762 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN
},
764 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1
| FS_JISJAPAN
},
765 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
766 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1
| FS_JISJAPAN
},
767 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
768 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1
| FS_JISJAPAN
},
769 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
770 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
771 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC
},
772 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
773 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC
},
774 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
775 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC
},
777 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
},
778 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC
},
779 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN
},
781 /* The 120dpi version still has its dpi marked as 96 */
782 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
784 /* FIXME: add "Terminal" */
788 HFONT hfont
, old_hfont
;
793 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
795 hdc
= CreateCompatibleDC(0);
798 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
802 memset(&lf
, 0, sizeof(lf
));
804 lf
.lfHeight
= fd
[i
].height
;
805 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
807 for(bit
= 0; bit
< 32; bit
++)
815 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
816 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
818 lf
.lfCharSet
= csi
.ciCharset
;
819 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
822 hfont
= create_font(lf
.lfFaceName
, &lf
);
823 old_hfont
= SelectObject(hdc
, hfont
);
824 bRet
= GetTextMetrics(hdc
, &tm
);
825 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
826 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
828 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
829 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
831 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
);
832 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
);
833 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
);
834 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
);
835 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
);
836 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
);
837 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
);
839 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
840 that make the max width bigger */
841 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
842 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
);
845 skip("Skipping font metrics test for system langid 0x%x\n",
848 SelectObject(hdc
, old_hfont
);
856 static void test_GdiGetCharDimensions(void)
862 LONG avgwidth
, height
;
863 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
865 if (!pGdiGetCharDimensions
)
867 win_skip("GdiGetCharDimensions not available on this platform\n");
871 hdc
= CreateCompatibleDC(NULL
);
873 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
874 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
876 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
877 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
878 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
880 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
881 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
883 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
884 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
887 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
888 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
889 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
894 static int CALLBACK
create_font_proc(const LOGFONT
*lpelfe
,
895 const TEXTMETRIC
*lpntme
,
896 DWORD FontType
, LPARAM lParam
)
898 if (FontType
& TRUETYPE_FONTTYPE
)
902 hfont
= CreateFontIndirect(lpelfe
);
905 *(HFONT
*)lParam
= hfont
;
913 static void test_GetCharABCWidths(void)
915 static const WCHAR str
[] = {'a',0};
936 {0xffffff, 0xffffff},
937 {0x1000000, 0x1000000},
938 {0xffffff, 0x1000000},
939 {0xffffffff, 0xffffffff}
946 BOOL r
[sizeof range
/ sizeof range
[0]];
949 {ANSI_CHARSET
, 0x30, 0x30, {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
950 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
951 {HANGEUL_CHARSET
, 0x8141, 0xac02, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
952 {JOHAB_CHARSET
, 0x8446, 0x3135, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
953 {GB2312_CHARSET
, 0x8141, 0x4e04, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
954 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}}
958 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsI
)
960 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
964 memset(&lf
, 0, sizeof(lf
));
965 strcpy(lf
.lfFaceName
, "System");
968 hfont
= CreateFontIndirectA(&lf
);
970 hfont
= SelectObject(hdc
, hfont
);
972 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
973 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
975 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
976 ok(!ret
, "GetCharABCWidthsI should have failed\n");
978 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
979 ok(!ret
, "GetCharABCWidthsI should have failed\n");
981 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
982 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
984 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
985 ok(!ret
, "GetCharABCWidthsW should have failed\n");
987 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
988 ok(!ret
, "GetCharABCWidthsW should have failed\n");
990 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
991 ok(!ret
, "GetCharABCWidthsW should have failed\n");
993 hfont
= SelectObject(hdc
, hfont
);
996 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1000 UINT code
= 0x41, j
;
1002 lf
.lfFaceName
[0] = '\0';
1003 lf
.lfCharSet
= c
[i
].cs
;
1004 lf
.lfPitchAndFamily
= 0;
1005 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1007 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1011 memset(a
, 0, sizeof a
);
1012 memset(w
, 0, sizeof w
);
1013 hfont
= SelectObject(hdc
, hfont
);
1014 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1015 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1016 memcmp(a
, w
, sizeof a
) == 0,
1017 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1019 memset(a
, 0xbb, sizeof a
);
1020 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1021 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1022 memset(full
, 0xcc, sizeof full
);
1023 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1024 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1025 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1026 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1028 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1030 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1031 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1032 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1035 hfont
= SelectObject(hdc
, hfont
);
1036 DeleteObject(hfont
);
1039 ReleaseDC(NULL
, hdc
);
1042 static void test_text_extents(void)
1044 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1046 INT i
, len
, fit1
, fit2
;
1054 memset(&lf
, 0, sizeof(lf
));
1055 strcpy(lf
.lfFaceName
, "Arial");
1058 hfont
= CreateFontIndirectA(&lf
);
1060 hfont
= SelectObject(hdc
, hfont
);
1061 GetTextMetricsA(hdc
, &tm
);
1062 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1063 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1065 SetLastError(0xdeadbeef);
1066 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1067 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1069 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1070 hfont
= SelectObject(hdc
, hfont
);
1071 DeleteObject(hfont
);
1077 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1078 extents
[0] = 1; /* So that the increasing sequence test will fail
1079 if the extents array is untouched. */
1080 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1081 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1082 ok(sz1
.cy
== sz2
.cy
,
1083 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1084 /* Because of the '\n' in the string GetTextExtentExPoint and
1085 GetTextExtentPoint return different widths under Win2k, but
1086 under WinXP they return the same width. So we don't test that
1089 for (i
= 1; i
< len
; ++i
)
1090 ok(extents
[i
-1] <= extents
[i
],
1091 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1093 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1094 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1095 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1096 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1097 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1098 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1099 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1100 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1101 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1102 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1103 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1104 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1105 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1106 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1107 HeapFree(GetProcessHeap(), 0, extents
);
1109 hfont
= SelectObject(hdc
, hfont
);
1110 DeleteObject(hfont
);
1111 ReleaseDC(NULL
, hdc
);
1114 static void test_GetGlyphIndices(void)
1121 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1122 WORD glyphs
[(sizeof(testtext
)/2)-1];
1126 if (!pGetGlyphIndicesW
) {
1127 win_skip("GetGlyphIndicesW not available on platform\n");
1133 memset(&lf
, 0, sizeof(lf
));
1134 strcpy(lf
.lfFaceName
, "System");
1136 lf
.lfCharSet
= ANSI_CHARSET
;
1138 hfont
= CreateFontIndirectA(&lf
);
1139 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1140 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1141 if (textm
.tmCharSet
== ANSI_CHARSET
)
1143 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1144 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1145 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1146 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
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] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1151 textm
.tmDefaultChar
, glyphs
[4]);
1154 /* FIXME: Write tests for non-ANSI charsets. */
1155 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1157 if(!is_font_installed("Tahoma"))
1159 skip("Tahoma is not installed so skipping this test\n");
1162 memset(&lf
, 0, sizeof(lf
));
1163 strcpy(lf
.lfFaceName
, "Tahoma");
1166 hfont
= CreateFontIndirectA(&lf
);
1167 hOldFont
= SelectObject(hdc
, hfont
);
1168 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1169 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1170 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1171 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1172 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1174 testtext
[0] = textm
.tmDefaultChar
;
1175 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1176 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1177 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1178 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1179 DeleteObject(SelectObject(hdc
, hOldFont
));
1182 static void test_GetKerningPairs(void)
1184 static const struct kerning_data
1186 const char face_name
[LF_FACESIZE
];
1188 /* some interesting fields from OUTLINETEXTMETRIC */
1189 LONG tmHeight
, tmAscent
, tmDescent
;
1194 UINT otmsCapEmHeight
;
1199 UINT otmusMinimumPPEM
;
1200 /* small subset of kerning pairs to test */
1201 DWORD total_kern_pairs
;
1202 const KERNINGPAIR kern_pair
[26];
1205 {"Arial", 12, 12, 9, 3,
1206 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1209 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1210 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1211 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1212 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1213 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1214 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1215 {933,970,+1},{933,972,-1}
1218 {"Arial", -34, 39, 32, 7,
1219 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1222 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1223 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1224 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1225 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1226 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1227 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1228 {933,970,+2},{933,972,-3}
1231 { "Arial", 120, 120, 97, 23,
1232 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1235 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1236 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1237 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1238 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1239 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1240 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1241 {933,970,+6},{933,972,-10}
1244 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1245 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1246 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1249 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1250 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1251 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1252 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1253 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1254 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1255 {933,970,+54},{933,972,-83}
1261 HFONT hfont
, hfont_old
;
1262 KERNINGPAIR
*kern_pair
;
1264 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1268 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1269 * which may render this test unusable, so we're trying to avoid that.
1271 SetLastError(0xdeadbeef);
1272 GetKerningPairsW(hdc
, 0, NULL
);
1273 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1275 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1280 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1282 OUTLINETEXTMETRICW otm
;
1285 if (!is_font_installed(kd
[i
].face_name
))
1287 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1291 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1293 memset(&lf
, 0, sizeof(lf
));
1294 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1295 lf
.lfHeight
= kd
[i
].height
;
1296 hfont
= CreateFontIndirect(&lf
);
1299 hfont_old
= SelectObject(hdc
, hfont
);
1301 SetLastError(0xdeadbeef);
1302 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1303 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1304 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1306 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
), "expected %d, got %d\n",
1307 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1308 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
), "expected %d, got %d\n",
1309 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1310 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1311 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1313 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1314 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1315 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1316 kd
[i
].otmAscent
, otm
.otmAscent
);
1317 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1318 kd
[i
].otmDescent
, otm
.otmDescent
);
1319 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1320 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1321 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1322 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1323 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1324 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1326 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1327 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1328 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1329 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1330 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1331 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1332 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1333 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1334 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1337 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1338 trace("total_kern_pairs %u\n", total_kern_pairs
);
1339 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1341 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1342 SetLastError(0xdeadbeef);
1343 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1344 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1345 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1346 ok(ret
== 0, "got %lu, expected 0\n", ret
);
1349 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1350 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1352 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1353 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1355 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1356 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1360 for (n
= 0; n
< ret
; n
++)
1364 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1365 trace("{'%c','%c',%d},\n",
1366 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1368 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1370 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1371 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1373 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1374 "pair %d:%d got %d, expected %d\n",
1375 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1376 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1382 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1383 matches
, kd
[i
].total_kern_pairs
);
1385 HeapFree(GetProcessHeap(), 0, kern_pair
);
1387 SelectObject(hdc
, hfont_old
);
1388 DeleteObject(hfont
);
1394 static void test_height_selection(void)
1396 static const struct font_data
1398 const char face_name
[LF_FACESIZE
];
1399 int requested_height
;
1400 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1403 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96 },
1404 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96 },
1405 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96 },
1406 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96 },
1407 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96 },
1408 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96 },
1409 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96 },
1410 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96 },
1411 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96 },
1412 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96 }
1416 HFONT hfont
, old_hfont
;
1420 hdc
= CreateCompatibleDC(0);
1423 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
1425 if (!is_truetype_font_installed(fd
[i
].face_name
))
1427 skip("%s is not installed\n", fd
[i
].face_name
);
1431 memset(&lf
, 0, sizeof(lf
));
1432 lf
.lfHeight
= fd
[i
].requested_height
;
1433 lf
.lfWeight
= fd
[i
].weight
;
1434 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1436 hfont
= CreateFontIndirect(&lf
);
1439 old_hfont
= SelectObject(hdc
, hfont
);
1440 ret
= GetTextMetrics(hdc
, &tm
);
1441 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1442 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1444 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1445 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
);
1446 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
);
1447 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
);
1448 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
);
1449 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1450 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
);
1452 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
);
1455 SelectObject(hdc
, old_hfont
);
1456 DeleteObject(hfont
);
1462 static void test_GetOutlineTextMetrics(void)
1464 OUTLINETEXTMETRIC
*otm
;
1466 HFONT hfont
, hfont_old
;
1468 DWORD ret
, otm_size
;
1471 if (!is_font_installed("Arial"))
1473 skip("Arial is not installed\n");
1479 memset(&lf
, 0, sizeof(lf
));
1480 strcpy(lf
.lfFaceName
, "Arial");
1482 lf
.lfWeight
= FW_NORMAL
;
1483 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1484 lf
.lfQuality
= PROOF_QUALITY
;
1485 hfont
= CreateFontIndirect(&lf
);
1488 hfont_old
= SelectObject(hdc
, hfont
);
1489 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1490 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1492 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1494 memset(otm
, 0xAA, otm_size
);
1495 SetLastError(0xdeadbeef);
1496 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1497 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1498 ok(ret
== 1 /* Win9x */ ||
1499 ret
== otm
->otmSize
/* XP*/,
1500 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1501 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1503 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1504 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1505 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1506 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1509 memset(otm
, 0xAA, otm_size
);
1510 SetLastError(0xdeadbeef);
1511 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1512 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1513 ok(ret
== 1 /* Win9x */ ||
1514 ret
== otm
->otmSize
/* XP*/,
1515 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1516 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1518 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1519 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1520 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1521 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1524 /* ask about truncated data */
1525 memset(otm
, 0xAA, otm_size
);
1526 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1527 SetLastError(0xdeadbeef);
1528 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1529 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1530 ok(ret
== 1 /* Win9x */ ||
1531 ret
== otm
->otmSize
/* XP*/,
1532 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1533 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1535 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1536 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1537 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1539 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1541 HeapFree(GetProcessHeap(), 0, otm
);
1543 SelectObject(hdc
, hfont_old
);
1544 DeleteObject(hfont
);
1549 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1553 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
1554 areaWidth
= clientArea
->right
- clientArea
->left
,
1556 BOOL lastExtent
= FALSE
;
1557 PSTR pFirstChar
, pLastChar
;
1563 int GetTextExtentExPointWWidth
;
1566 GetTextMetricsA(hdc
, &tm
);
1567 y
= clientArea
->top
;
1570 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1576 /* if not at the end of the string, ... */
1577 if (*str
== '\0') break;
1578 /* ... add the next word to the current extent */
1579 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1581 SetTextJustification(hdc
, 0, 0);
1582 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1583 } while ((int) size
.cx
< areaWidth
);
1585 /* ignore trailing break chars */
1587 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1593 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1595 SetTextJustification(hdc
, 0, 0);
1596 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1598 /* do not justify the last extent */
1599 if (*str
!= '\0' && breakCount
> 0)
1601 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1602 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1603 justifiedWidth
= size
.cx
;
1605 else lastExtent
= TRUE
;
1607 /* catch errors and report them */
1608 if (!lastExtent
&& (justifiedWidth
!= areaWidth
))
1610 memset(error
[nErrors
].extent
, 0, 100);
1611 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
1612 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
1618 } while (*str
&& y
< clientArea
->bottom
);
1620 for (e
= 0; e
< nErrors
; e
++)
1622 /* The width returned by GetTextExtentPoint32() is exactly the same
1623 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1624 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1625 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1626 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1630 static void test_SetTextJustification(void)
1637 static char testText
[] =
1638 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1639 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1640 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1641 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1642 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1643 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1644 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1646 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1647 GetClientRect( hwnd
, &clientArea
);
1648 hdc
= GetDC( hwnd
);
1650 memset(&lf
, 0, sizeof lf
);
1651 lf
.lfCharSet
= ANSI_CHARSET
;
1652 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1653 lf
.lfWeight
= FW_DONTCARE
;
1655 lf
.lfQuality
= DEFAULT_QUALITY
;
1656 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1657 hfont
= create_font("Times New Roman", &lf
);
1658 SelectObject(hdc
, hfont
);
1660 testJustification(hdc
, testText
, &clientArea
);
1662 DeleteObject(hfont
);
1663 ReleaseDC(hwnd
, hdc
);
1664 DestroyWindow(hwnd
);
1667 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1671 HFONT hfont
, hfont_old
;
1678 assert(count
<= 128);
1680 memset(&lf
, 0, sizeof(lf
));
1682 lf
.lfCharSet
= charset
;
1684 lstrcpyA(lf
.lfFaceName
, "Arial");
1685 SetLastError(0xdeadbeef);
1686 hfont
= CreateFontIndirectA(&lf
);
1687 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1690 hfont_old
= SelectObject(hdc
, hfont
);
1692 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1693 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1695 SetLastError(0xdeadbeef);
1696 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1697 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1699 if (charset
== SYMBOL_CHARSET
)
1701 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1702 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1706 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1707 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1710 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1712 trace("Can't find codepage for charset %d\n", cs
);
1716 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1718 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
1720 skip("Font code page %d, looking for code page %d\n",
1721 pGdiGetCodePage(hdc
), code_page
);
1729 WCHAR unicode_buf
[128];
1731 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1733 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1735 SetLastError(0xdeadbeef);
1736 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1737 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
1738 count
, ret
, GetLastError());
1744 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1746 SetLastError(0xdeadbeef);
1747 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1748 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
1749 count
, ret
, GetLastError());
1752 SelectObject(hdc
, hfont_old
);
1753 DeleteObject(hfont
);
1760 static void test_font_charset(void)
1762 static struct charset_data
1766 WORD font_idxA
[128], font_idxW
[128];
1769 { ANSI_CHARSET
, 1252 },
1770 { RUSSIAN_CHARSET
, 1251 },
1771 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1775 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1777 win_skip("Skipping the font charset test on a Win9x platform\n");
1781 if (!is_font_installed("Arial"))
1783 skip("Arial is not installed\n");
1787 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1789 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1791 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1793 skip("Symbol or Wingdings is not installed\n");
1797 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
1798 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
1799 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1802 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1805 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1806 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1809 skip("Symbol or Wingdings is not installed\n");
1812 static void test_GetFontUnicodeRanges(void)
1816 HFONT hfont
, hfont_old
;
1820 if (!pGetFontUnicodeRanges
)
1822 win_skip("GetFontUnicodeRanges not available before W2K\n");
1826 memset(&lf
, 0, sizeof(lf
));
1827 lstrcpyA(lf
.lfFaceName
, "Arial");
1828 hfont
= create_font("Arial", &lf
);
1831 hfont_old
= SelectObject(hdc
, hfont
);
1833 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1834 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1836 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1837 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1839 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1841 size
= pGetFontUnicodeRanges(hdc
, gs
);
1842 ok(size
, "GetFontUnicodeRanges failed\n");
1844 for (i
= 0; i
< gs
->cRanges
; i
++)
1845 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1847 trace("found %u ranges\n", gs
->cRanges
);
1849 HeapFree(GetProcessHeap(), 0, gs
);
1851 SelectObject(hdc
, hfont_old
);
1852 DeleteObject(hfont
);
1853 ReleaseDC(NULL
, hdc
);
1856 #define MAX_ENUM_FONTS 4096
1858 struct enum_font_data
1861 LOGFONT lf
[MAX_ENUM_FONTS
];
1864 struct enum_font_dataW
1867 LOGFONTW lf
[MAX_ENUM_FONTS
];
1870 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1872 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1874 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1876 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1878 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1879 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1881 if (efd
->total
< MAX_ENUM_FONTS
)
1882 efd
->lf
[efd
->total
++] = *lf
;
1884 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1889 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
1891 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
1893 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1895 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1897 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1898 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1900 if (efd
->total
< MAX_ENUM_FONTS
)
1901 efd
->lf
[efd
->total
++] = *lf
;
1903 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1908 static void get_charset_stats(struct enum_font_data
*efd
,
1909 int *ansi_charset
, int *symbol_charset
,
1910 int *russian_charset
)
1915 *symbol_charset
= 0;
1916 *russian_charset
= 0;
1918 for (i
= 0; i
< efd
->total
; i
++)
1920 switch (efd
->lf
[i
].lfCharSet
)
1925 case SYMBOL_CHARSET
:
1926 (*symbol_charset
)++;
1928 case RUSSIAN_CHARSET
:
1929 (*russian_charset
)++;
1935 static void get_charset_statsW(struct enum_font_dataW
*efd
,
1936 int *ansi_charset
, int *symbol_charset
,
1937 int *russian_charset
)
1942 *symbol_charset
= 0;
1943 *russian_charset
= 0;
1945 for (i
= 0; i
< efd
->total
; i
++)
1947 switch (efd
->lf
[i
].lfCharSet
)
1952 case SYMBOL_CHARSET
:
1953 (*symbol_charset
)++;
1955 case RUSSIAN_CHARSET
:
1956 (*russian_charset
)++;
1962 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1964 struct enum_font_data efd
;
1965 struct enum_font_dataW efdw
;
1968 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1970 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1972 if (*font_name
&& !is_truetype_font_installed(font_name
))
1974 skip("%s is not installed\n", font_name
);
1980 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1981 * while EnumFontFamiliesEx doesn't.
1983 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1986 * Use EnumFontFamiliesW since win98 crashes when the
1987 * second parameter is NULL using EnumFontFamilies
1990 SetLastError(0xdeadbeef);
1991 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
1992 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
1995 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1996 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1997 ansi_charset
, symbol_charset
, russian_charset
);
1998 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
1999 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2000 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2001 ok(russian_charset
> 0 ||
2002 broken(russian_charset
== 0), /* NT4 */
2003 "NULL family should enumerate RUSSIAN_CHARSET\n");
2007 SetLastError(0xdeadbeef);
2008 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2009 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2012 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2013 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2014 ansi_charset
, symbol_charset
, russian_charset
);
2015 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2016 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2017 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2018 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2023 SetLastError(0xdeadbeef);
2024 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2025 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2026 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2027 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2028 ansi_charset
, symbol_charset
, russian_charset
,
2029 *font_name
? font_name
: "<empty>");
2031 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2033 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2034 for (i
= 0; i
< efd
.total
; i
++)
2036 /* FIXME: remove completely once Wine is fixed */
2037 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2040 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2043 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2044 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2045 font_name
, efd
.lf
[i
].lfFaceName
);
2048 memset(&lf
, 0, sizeof(lf
));
2049 lf
.lfCharSet
= ANSI_CHARSET
;
2050 lstrcpy(lf
.lfFaceName
, font_name
);
2052 SetLastError(0xdeadbeef);
2053 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2054 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2055 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2056 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2057 ansi_charset
, symbol_charset
, russian_charset
,
2058 *font_name
? font_name
: "<empty>");
2059 if (font_charset
== SYMBOL_CHARSET
)
2062 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2064 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2068 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2069 for (i
= 0; i
< efd
.total
; i
++)
2071 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2073 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2074 font_name
, efd
.lf
[i
].lfFaceName
);
2078 /* DEFAULT_CHARSET should enumerate all available charsets */
2079 memset(&lf
, 0, sizeof(lf
));
2080 lf
.lfCharSet
= DEFAULT_CHARSET
;
2081 lstrcpy(lf
.lfFaceName
, font_name
);
2083 SetLastError(0xdeadbeef);
2084 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2085 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2086 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2087 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2088 ansi_charset
, symbol_charset
, russian_charset
,
2089 *font_name
? font_name
: "<empty>");
2090 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2091 for (i
= 0; i
< efd
.total
; i
++)
2094 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2095 font_name
, efd
.lf
[i
].lfFaceName
);
2099 switch (font_charset
)
2102 ok(ansi_charset
> 0,
2103 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2105 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2106 ok(russian_charset
> 0,
2107 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2109 case SYMBOL_CHARSET
:
2111 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2113 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2114 ok(!russian_charset
,
2115 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2117 case DEFAULT_CHARSET
:
2118 ok(ansi_charset
> 0,
2119 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2120 ok(symbol_charset
> 0,
2121 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2122 ok(russian_charset
> 0,
2123 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2129 ok(ansi_charset
> 0,
2130 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2131 ok(symbol_charset
> 0,
2132 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2133 ok(russian_charset
> 0,
2134 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2137 memset(&lf
, 0, sizeof(lf
));
2138 lf
.lfCharSet
= SYMBOL_CHARSET
;
2139 lstrcpy(lf
.lfFaceName
, font_name
);
2141 SetLastError(0xdeadbeef);
2142 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2143 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2144 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2145 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2146 ansi_charset
, symbol_charset
, russian_charset
,
2147 *font_name
? font_name
: "<empty>");
2148 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2149 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2152 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2153 for (i
= 0; i
< efd
.total
; i
++)
2155 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2157 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2158 font_name
, efd
.lf
[i
].lfFaceName
);
2162 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2163 ok(symbol_charset
> 0,
2164 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2165 ok(!russian_charset
,
2166 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2172 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2174 HFONT hfont
, hfont_prev
;
2176 GLYPHMETRICS gm1
, gm2
;
2180 if(!pGetGlyphIndicesA
)
2183 /* negative widths are handled just as positive ones */
2184 lf2
.lfWidth
= -lf
->lfWidth
;
2186 SetLastError(0xdeadbeef);
2187 hfont
= CreateFontIndirectA(lf
);
2188 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2189 check_font("original", lf
, hfont
);
2191 hfont_prev
= SelectObject(hdc
, hfont
);
2193 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2194 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2196 SelectObject(hdc
, hfont_prev
);
2197 DeleteObject(hfont
);
2198 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2202 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2203 memset(&gm1
, 0xab, sizeof(gm1
));
2204 SetLastError(0xdeadbeef);
2205 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2206 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2208 SelectObject(hdc
, hfont_prev
);
2209 DeleteObject(hfont
);
2211 SetLastError(0xdeadbeef);
2212 hfont
= CreateFontIndirectA(&lf2
);
2213 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2214 check_font("negative width", &lf2
, hfont
);
2216 hfont_prev
= SelectObject(hdc
, hfont
);
2218 memset(&gm2
, 0xbb, sizeof(gm2
));
2219 SetLastError(0xdeadbeef);
2220 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2221 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2223 SelectObject(hdc
, hfont_prev
);
2224 DeleteObject(hfont
);
2226 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2227 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2228 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2229 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2230 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2231 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2232 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2233 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2234 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2235 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2236 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2239 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2240 #include "pshpack2.h"
2244 SHORT xAvgCharWidth
;
2245 USHORT usWeightClass
;
2246 USHORT usWidthClass
;
2248 SHORT ySubscriptXSize
;
2249 SHORT ySubscriptYSize
;
2250 SHORT ySubscriptXOffset
;
2251 SHORT ySubscriptYOffset
;
2252 SHORT ySuperscriptXSize
;
2253 SHORT ySuperscriptYSize
;
2254 SHORT ySuperscriptXOffset
;
2255 SHORT ySuperscriptYOffset
;
2256 SHORT yStrikeoutSize
;
2257 SHORT yStrikeoutPosition
;
2260 ULONG ulUnicodeRange1
;
2261 ULONG ulUnicodeRange2
;
2262 ULONG ulUnicodeRange3
;
2263 ULONG ulUnicodeRange4
;
2266 USHORT usFirstCharIndex
;
2267 USHORT usLastCharIndex
;
2268 /* According to the Apple spec, original version didn't have the below fields,
2269 * version numbers were taked from the OpenType spec.
2271 /* version 0 (TrueType 1.5) */
2272 USHORT sTypoAscender
;
2273 USHORT sTypoDescender
;
2274 USHORT sTypoLineGap
;
2276 USHORT usWinDescent
;
2277 /* version 1 (TrueType 1.66) */
2278 ULONG ulCodePageRange1
;
2279 ULONG ulCodePageRange2
;
2280 /* version 2 (OpenType 1.2) */
2283 USHORT usDefaultChar
;
2285 USHORT usMaxContext
;
2287 #include "poppack.h"
2289 #ifdef WORDS_BIGENDIAN
2290 #define GET_BE_WORD(x) (x)
2291 #define GET_BE_DWORD(x) (x)
2293 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2294 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2297 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2298 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2299 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2300 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2301 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2314 } cmap_encoding_record
;
2322 BYTE glyph_ids
[256];
2332 USHORT search_range
;
2333 USHORT entry_selector
;
2336 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2339 USHORT start_count[seg_countx2 / 2];
2340 USHORT id_delta[seg_countx2 / 2];
2341 USHORT id_range_offset[seg_countx2 / 2];
2351 USHORT id_range_offset
;
2352 } cmap_format_4_seg
;
2354 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2356 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
2357 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
2358 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2359 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2360 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2363 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2366 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2370 for(i
= 0; i
< 256; i
++)
2372 if(cmap
->glyph_ids
[i
] == 0) continue;
2374 if(*first
== 256) *first
= i
;
2376 if(*first
== 256) return FALSE
;
2380 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2382 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2383 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2384 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2385 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2386 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2389 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2392 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2393 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2394 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2398 for(i
= 0; i
< seg_count
; i
++)
2401 cmap_format_4_seg seg
;
2403 get_seg4(cmap
, i
, &seg
);
2404 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2406 if(seg
.id_range_offset
== 0)
2407 index
= (seg
.id_delta
+ code
) & 0xffff;
2410 index
= seg
.id_range_offset
/ 2
2411 + code
- seg
.start_count
2414 /* some fonts have broken last segment */
2415 if ((char *)(glyph_ids
+ index
+ sizeof(*glyph_ids
)) < (char *)ptr
+ limit
)
2416 index
= GET_BE_WORD(glyph_ids
[index
]);
2419 trace("segment %04x/%04x index %04x points to nowhere\n",
2420 seg
.start_count
, seg
.end_count
, index
);
2423 if(index
) index
+= seg
.id_delta
;
2425 if(*first
== 0x10000)
2426 *last
= *first
= code
;
2432 if(*first
== 0x10000) return FALSE
;
2436 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2439 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2441 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2443 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2444 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2457 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2460 cmap_header
*header
;
2465 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2466 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2467 if(size
== GDI_ERROR
) return FALSE
;
2469 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2470 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2471 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2472 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2474 cmap
= get_cmap(header
, 3, 1);
2476 *cmap_type
= cmap_ms_unicode
;
2479 cmap
= get_cmap(header
, 3, 0);
2480 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2484 *cmap_type
= cmap_none
;
2488 format
= GET_BE_WORD(*(WORD
*)cmap
);
2492 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2495 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2498 trace("unhandled cmap format %d\n", format
);
2503 HeapFree(GetProcessHeap(), 0, header
);
2507 static void test_text_metrics(const LOGFONTA
*lf
)
2510 HFONT hfont
, hfont_old
;
2514 const char *font_name
= lf
->lfFaceName
;
2515 DWORD cmap_first
= 0, cmap_last
= 0;
2516 cmap_type cmap_type
;
2517 BOOL sys_lang_non_english
;
2519 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
2522 SetLastError(0xdeadbeef);
2523 hfont
= CreateFontIndirectA(lf
);
2524 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2526 hfont_old
= SelectObject(hdc
, hfont
);
2528 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2529 if (size
== GDI_ERROR
)
2531 trace("OS/2 chunk was not found\n");
2534 if (size
> sizeof(tt_os2
))
2536 trace("got too large OS/2 chunk of size %u\n", size
);
2537 size
= sizeof(tt_os2
);
2540 memset(&tt_os2
, 0, sizeof(tt_os2
));
2541 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2542 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2544 SetLastError(0xdeadbeef);
2545 ret
= GetTextMetricsA(hdc
, &tmA
);
2546 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2548 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
2550 skip("Unable to retrieve first and last glyphs from cmap\n");
2554 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
2555 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
2556 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
2560 version
= GET_BE_WORD(tt_os2
.version
);
2562 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2563 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2564 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2565 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2567 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2568 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
2569 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
2571 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
2576 case 1257: /* Baltic */
2577 expect_last_W
= 0xf8fd;
2580 expect_last_W
= 0xf0ff;
2582 expect_break_W
= 0x20;
2583 expect_default_W
= expect_break_W
- 1;
2584 expect_first_A
= 0x1e;
2585 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
2589 expect_first_W
= cmap_first
;
2590 expect_last_W
= min(cmap_last
, os2_last_char
);
2591 if(os2_first_char
<= 1)
2592 expect_break_W
= os2_first_char
+ 2;
2593 else if(os2_first_char
> 0xff)
2594 expect_break_W
= 0x20;
2596 expect_break_W
= os2_first_char
;
2597 expect_default_W
= expect_break_W
- 1;
2598 expect_first_A
= expect_default_W
- 1;
2599 expect_last_A
= min(expect_last_W
, 0xff);
2601 expect_break_A
= expect_break_W
;
2602 expect_default_A
= expect_default_W
;
2604 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2605 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
2606 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
2607 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2608 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2610 ok(tmA
.tmFirstChar
== expect_first_A
||
2611 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2612 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2613 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
2614 ok(tmA
.tmLastChar
== expect_last_A
||
2615 tmA
.tmLastChar
== 0xff /* win9x */,
2616 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
2618 skip("tmLastChar is DBCS lead byte\n");
2619 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
2620 font_name
, tmA
.tmBreakChar
, expect_break_A
);
2621 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
2622 "A: tmDefaultChar for %s got %02x expected %02x\n",
2623 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
2626 SetLastError(0xdeadbeef);
2627 ret
= GetTextMetricsW(hdc
, &tmW
);
2628 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2629 "GetTextMetricsW error %u\n", GetLastError());
2632 /* Wine uses the os2 first char */
2633 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
2634 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2635 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2637 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2638 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2640 /* Wine uses the os2 last char */
2641 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
2642 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2643 font_name
, tmW
.tmLastChar
, expect_last_W
);
2645 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2646 font_name
, tmW
.tmLastChar
, expect_last_W
);
2647 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
2648 font_name
, tmW
.tmBreakChar
, expect_break_W
);
2649 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
2650 "W: tmDefaultChar for %s got %02x expected %02x\n",
2651 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
2653 /* Test the aspect ratio while we have tmW */
2654 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2655 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2656 tmW
.tmDigitizedAspectX
, ret
);
2657 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2658 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2659 tmW
.tmDigitizedAspectX
, ret
);
2663 /* test FF_ values */
2664 switch(tt_os2
.panose
.bFamilyType
)
2668 case PAN_FAMILY_TEXT_DISPLAY
:
2669 case PAN_FAMILY_PICTORIAL
:
2671 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
2672 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
2674 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
2677 switch(tt_os2
.panose
.bSerifStyle
)
2682 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
2685 case PAN_SERIF_COVE
:
2686 case PAN_SERIF_OBTUSE_COVE
:
2687 case PAN_SERIF_SQUARE_COVE
:
2688 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
2689 case PAN_SERIF_SQUARE
:
2690 case PAN_SERIF_THIN
:
2691 case PAN_SERIF_BONE
:
2692 case PAN_SERIF_EXAGGERATED
:
2693 case PAN_SERIF_TRIANGLE
:
2694 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
2697 case PAN_SERIF_NORMAL_SANS
:
2698 case PAN_SERIF_OBTUSE_SANS
:
2699 case PAN_SERIF_PERP_SANS
:
2700 case PAN_SERIF_FLARED
:
2701 case PAN_SERIF_ROUNDED
:
2702 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
2707 case PAN_FAMILY_SCRIPT
:
2708 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
2711 case PAN_FAMILY_DECORATIVE
:
2712 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
2716 test_negative_width(hdc
, lf
);
2719 SelectObject(hdc
, hfont_old
);
2720 DeleteObject(hfont
);
2725 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2727 INT
*enumed
= (INT
*)lParam
;
2729 if (type
== TRUETYPE_FONTTYPE
)
2732 test_text_metrics(lf
);
2737 static void test_GetTextMetrics(void)
2743 /* Report only once */
2744 if(!pGetGlyphIndicesA
)
2745 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2749 memset(&lf
, 0, sizeof(lf
));
2750 lf
.lfCharSet
= DEFAULT_CHARSET
;
2752 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2753 trace("Tested metrics of %d truetype fonts\n", enumed
);
2758 static void test_nonexistent_font(void)
2766 { "Times New Roman Baltic", 186 },
2767 { "Times New Roman CE", 238 },
2768 { "Times New Roman CYR", 204 },
2769 { "Times New Roman Greek", 161 },
2770 { "Times New Roman TUR", 162 }
2776 INT cs
, expected_cs
, i
;
2777 char buf
[LF_FACESIZE
];
2779 if (!is_truetype_font_installed("Arial") ||
2780 !is_truetype_font_installed("Times New Roman"))
2782 skip("Arial or Times New Roman not installed\n");
2786 expected_cs
= GetACP();
2787 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
2789 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
2792 expected_cs
= csi
.ciCharset
;
2793 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
2797 memset(&lf
, 0, sizeof(lf
));
2799 lf
.lfWeight
= FW_REGULAR
;
2800 lf
.lfCharSet
= ANSI_CHARSET
;
2801 lf
.lfPitchAndFamily
= FF_SWISS
;
2802 strcpy(lf
.lfFaceName
, "Nonexistent font");
2803 hfont
= CreateFontIndirectA(&lf
);
2804 hfont
= SelectObject(hdc
, hfont
);
2805 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2806 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
2807 cs
= GetTextCharset(hdc
);
2808 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2809 DeleteObject(SelectObject(hdc
, hfont
));
2811 memset(&lf
, 0, sizeof(lf
));
2813 lf
.lfWeight
= FW_DONTCARE
;
2814 strcpy(lf
.lfFaceName
, "Nonexistent font");
2815 hfont
= CreateFontIndirectA(&lf
);
2816 hfont
= SelectObject(hdc
, hfont
);
2817 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2818 todo_wine
/* Wine uses Arial for all substitutions */
2819 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
2820 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
2821 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2823 cs
= GetTextCharset(hdc
);
2824 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
2825 DeleteObject(SelectObject(hdc
, hfont
));
2827 memset(&lf
, 0, sizeof(lf
));
2829 lf
.lfWeight
= FW_REGULAR
;
2830 strcpy(lf
.lfFaceName
, "Nonexistent font");
2831 hfont
= CreateFontIndirectA(&lf
);
2832 hfont
= SelectObject(hdc
, hfont
);
2833 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2834 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2835 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
2836 cs
= GetTextCharset(hdc
);
2837 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2838 DeleteObject(SelectObject(hdc
, hfont
));
2840 memset(&lf
, 0, sizeof(lf
));
2842 lf
.lfWeight
= FW_DONTCARE
;
2843 strcpy(lf
.lfFaceName
, "Times New Roman");
2844 hfont
= CreateFontIndirectA(&lf
);
2845 hfont
= SelectObject(hdc
, hfont
);
2846 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2847 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
2848 cs
= GetTextCharset(hdc
);
2849 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2850 DeleteObject(SelectObject(hdc
, hfont
));
2852 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
2854 memset(&lf
, 0, sizeof(lf
));
2856 lf
.lfWeight
= FW_REGULAR
;
2857 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2858 hfont
= CreateFontIndirectA(&lf
);
2859 hfont
= SelectObject(hdc
, hfont
);
2860 cs
= GetTextCharset(hdc
);
2861 if (font_subst
[i
].charset
== expected_cs
)
2863 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2864 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2865 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
2869 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
2870 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2871 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2872 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
2874 DeleteObject(SelectObject(hdc
, hfont
));
2876 memset(&lf
, 0, sizeof(lf
));
2878 lf
.lfWeight
= FW_DONTCARE
;
2879 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2880 hfont
= CreateFontIndirectA(&lf
);
2881 hfont
= SelectObject(hdc
, hfont
);
2882 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2883 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
2884 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
2885 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
2886 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2887 "got %s for font %s\n", buf
, font_subst
[i
].name
);
2888 cs
= GetTextCharset(hdc
);
2889 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2890 DeleteObject(SelectObject(hdc
, hfont
));
2896 static void test_GdiRealizationInfo(void)
2901 HFONT hfont
, hfont_old
;
2904 if(!pGdiRealizationInfo
)
2906 win_skip("GdiRealizationInfo not available\n");
2912 memset(info
, 0xcc, sizeof(info
));
2913 r
= pGdiRealizationInfo(hdc
, info
);
2914 ok(r
!= 0, "ret 0\n");
2915 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
2916 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2918 if (!is_truetype_font_installed("Arial"))
2920 skip("skipping GdiRealizationInfo with truetype font\n");
2924 memset(&lf
, 0, sizeof(lf
));
2925 strcpy(lf
.lfFaceName
, "Arial");
2927 lf
.lfWeight
= FW_NORMAL
;
2928 hfont
= CreateFontIndirectA(&lf
);
2929 hfont_old
= SelectObject(hdc
, hfont
);
2931 memset(info
, 0xcc, sizeof(info
));
2932 r
= pGdiRealizationInfo(hdc
, info
);
2933 ok(r
!= 0, "ret 0\n");
2934 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
2935 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2937 DeleteObject(SelectObject(hdc
, hfont_old
));
2943 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2944 the nul in the count of characters copied when the face name buffer is not
2945 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2946 always includes it. */
2947 static void test_GetTextFace(void)
2949 static const char faceA
[] = "Tahoma";
2950 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
2953 char bufA
[LF_FACESIZE
];
2954 WCHAR bufW
[LF_FACESIZE
];
2959 if(!is_font_installed("Tahoma"))
2961 skip("Tahoma is not installed so skipping this test\n");
2966 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
2967 f
= CreateFontIndirectA(&fA
);
2968 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
2971 g
= SelectObject(dc
, f
);
2972 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
2973 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
2974 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
2976 /* Play with the count arg. */
2978 n
= GetTextFaceA(dc
, 0, bufA
);
2979 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2980 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2983 n
= GetTextFaceA(dc
, 1, bufA
);
2984 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2985 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2987 bufA
[0] = 'x'; bufA
[1] = 'y';
2988 n
= GetTextFaceA(dc
, 2, bufA
);
2989 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
2990 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
2992 n
= GetTextFaceA(dc
, 0, NULL
);
2993 ok(n
== sizeof faceA
||
2994 broken(n
== 0), /* win98, winMe */
2995 "GetTextFaceA returned %d\n", n
);
2997 DeleteObject(SelectObject(dc
, g
));
2998 ReleaseDC(NULL
, dc
);
3001 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3002 SetLastError(0xdeadbeef);
3003 f
= CreateFontIndirectW(&fW
);
3004 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3006 win_skip("CreateFontIndirectW is not implemented\n");
3009 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3012 g
= SelectObject(dc
, f
);
3013 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3014 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3015 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3017 /* Play with the count arg. */
3019 n
= GetTextFaceW(dc
, 0, bufW
);
3020 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3021 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3024 n
= GetTextFaceW(dc
, 1, bufW
);
3025 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3026 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3028 bufW
[0] = 'x'; bufW
[1] = 'y';
3029 n
= GetTextFaceW(dc
, 2, bufW
);
3030 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
3031 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
3033 n
= GetTextFaceW(dc
, 0, NULL
);
3034 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3036 DeleteObject(SelectObject(dc
, g
));
3037 ReleaseDC(NULL
, dc
);
3040 static void test_orientation(void)
3042 static const char test_str
[11] = "Test String";
3045 HFONT hfont
, old_hfont
;
3048 if (!is_truetype_font_installed("Arial"))
3050 skip("Arial is not installed\n");
3054 hdc
= CreateCompatibleDC(0);
3055 memset(&lf
, 0, sizeof(lf
));
3056 lstrcpyA(lf
.lfFaceName
, "Arial");
3058 lf
.lfOrientation
= lf
.lfEscapement
= 900;
3059 hfont
= create_font("orientation", &lf
);
3060 old_hfont
= SelectObject(hdc
, hfont
);
3061 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
3062 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
3063 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
3064 SelectObject(hdc
, old_hfont
);
3065 DeleteObject(hfont
);
3069 static void test_oemcharset(void)
3073 HFONT hfont
, old_hfont
;
3076 hdc
= CreateCompatibleDC(0);
3077 ZeroMemory(&lf
, sizeof(lf
));
3079 lf
.lfCharSet
= OEM_CHARSET
;
3080 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
3081 lstrcpyA(lf
.lfFaceName
, "Terminal");
3082 hfont
= CreateFontIndirectA(&lf
);
3083 old_hfont
= SelectObject(hdc
, hfont
);
3084 charset
= GetTextCharset(hdc
);
3086 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
3087 hfont
= SelectObject(hdc
, old_hfont
);
3088 GetObjectA(hfont
, sizeof(clf
), &clf
);
3089 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
3090 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
3091 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
3092 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
3093 DeleteObject(hfont
);
3097 static void test_GetGlyphOutline(void)
3100 GLYPHMETRICS gm
, gm2
;
3102 HFONT hfont
, old_hfont
;
3111 {ANSI_CHARSET
, 0x30, 0x30},
3112 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
3113 {HANGEUL_CHARSET
, 0x8141, 0xac02},
3114 {JOHAB_CHARSET
, 0x8446, 0x3135},
3115 {GB2312_CHARSET
, 0x8141, 0x4e04},
3116 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
3120 if (!is_truetype_font_installed("Tahoma"))
3122 skip("Tahoma is not installed\n");
3126 hdc
= CreateCompatibleDC(0);
3127 memset(&lf
, 0, sizeof(lf
));
3129 lstrcpyA(lf
.lfFaceName
, "Tahoma");
3130 SetLastError(0xdeadbeef);
3131 hfont
= CreateFontIndirectA(&lf
);
3132 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
3133 old_hfont
= SelectObject(hdc
, hfont
);
3135 memset(&gm
, 0, sizeof(gm
));
3136 SetLastError(0xdeadbeef);
3137 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3138 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3140 memset(&gm
, 0, sizeof(gm
));
3141 SetLastError(0xdeadbeef);
3142 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3143 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
3144 ok(GetLastError() == 0xdeadbeef ||
3145 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
3146 "expected 0xdeadbeef, got %u\n", GetLastError());
3148 memset(&gm
, 0, sizeof(gm
));
3149 SetLastError(0xdeadbeef);
3150 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3151 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3152 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
3154 memset(&gm
, 0, sizeof(gm
));
3155 SetLastError(0xdeadbeef);
3156 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3157 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3159 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
3160 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3163 /* test for needed buffer size request on space char */
3164 memset(&gm
, 0, sizeof(gm
));
3165 SetLastError(0xdeadbeef);
3166 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3167 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3168 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3170 /* requesting buffer size for space char + error */
3171 memset(&gm
, 0, sizeof(gm
));
3172 SetLastError(0xdeadbeef);
3173 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3174 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3176 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3177 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3180 SelectObject(hdc
, old_hfont
);
3181 DeleteObject(hfont
);
3183 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
3185 lf
.lfFaceName
[0] = '\0';
3186 lf
.lfCharSet
= c
[i
].cs
;
3187 lf
.lfPitchAndFamily
= 0;
3188 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
3190 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
3194 old_hfont
= SelectObject(hdc
, hfont
);
3196 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3197 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3198 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3200 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3201 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3202 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3204 hfont
= SelectObject(hdc
, old_hfont
);
3205 DeleteObject(hfont
);
3211 /* bug #9995: there is a limit to the character width that can be specified */
3212 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3218 int ave_width
, height
, width
, ratio
, scale
;
3220 if (!is_truetype_font_installed( fontname
)) {
3221 skip("%s is not installed\n", fontname
);
3224 hdc
= CreateCompatibleDC(0);
3225 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3226 /* select width = 0 */
3227 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3228 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3229 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3231 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3232 of
= SelectObject( hdc
, hf
);
3233 ret
= GetTextMetricsA( hdc
, &tm
);
3234 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3235 height
= tm
.tmHeight
;
3236 ave_width
= tm
.tmAveCharWidth
;
3237 SelectObject( hdc
, of
);
3240 trace("height %d, ave width %d\n", height
, ave_width
);
3242 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3244 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3245 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3246 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3247 ok(hf
!= 0, "CreateFont failed\n");
3248 of
= SelectObject(hdc
, hf
);
3249 ret
= GetTextMetrics(hdc
, &tm
);
3250 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3251 SelectObject(hdc
, of
);
3254 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3260 ratio
= width
/ height
;
3261 scale
= width
/ ave_width
;
3263 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3264 width
, height
, ratio
, width
, ave_width
, scale
);
3266 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3269 static void test_CreateFontIndirect(void)
3271 LOGFONTA lf
, getobj_lf
;
3274 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3276 memset(&lf
, 0, sizeof(lf
));
3277 lf
.lfCharSet
= ANSI_CHARSET
;
3278 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3281 lf
.lfQuality
= DEFAULT_QUALITY
;
3282 lf
.lfItalic
= FALSE
;
3283 lf
.lfWeight
= FW_DONTCARE
;
3285 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3287 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3288 hfont
= CreateFontIndirectA(&lf
);
3289 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3290 SetLastError(0xdeadbeef);
3291 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3292 ok(ret
, "GetObject failed: %d\n", GetLastError());
3293 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3294 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3295 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3296 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3297 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3298 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3299 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3300 DeleteObject(hfont
);
3304 static void test_CreateFontIndirectEx(void)
3306 ENUMLOGFONTEXDVA lfex
;
3309 if (!pCreateFontIndirectExA
)
3311 win_skip("CreateFontIndirectExA is not available\n");
3315 if (!is_truetype_font_installed("Arial"))
3317 skip("Arial is not installed\n");
3321 SetLastError(0xdeadbeef);
3322 hfont
= pCreateFontIndirectExA(NULL
);
3323 ok(hfont
== NULL
, "got %p\n", hfont
);
3324 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3326 memset(&lfex
, 0, sizeof(lfex
));
3327 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3328 hfont
= pCreateFontIndirectExA(&lfex
);
3329 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3331 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3332 DeleteObject(hfont
);
3335 static void free_font(void *font
)
3337 UnmapViewOfFile(font
);
3340 static void *load_font(const char *font_name
, DWORD
*font_size
)
3342 char file_name
[MAX_PATH
];
3343 HANDLE file
, mapping
;
3346 if (!GetWindowsDirectory(file_name
, sizeof(file_name
))) return NULL
;
3347 strcat(file_name
, "\\fonts\\");
3348 strcat(file_name
, font_name
);
3350 file
= CreateFile(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3351 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
3353 *font_size
= GetFileSize(file
, NULL
);
3355 mapping
= CreateFileMapping(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
3362 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
3365 CloseHandle(mapping
);
3369 static void test_AddFontMemResource(void)
3372 DWORD font_size
, num_fonts
;
3376 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
3378 win_skip("AddFontMemResourceEx is not available on this platform\n");
3382 font
= load_font("sserife.fon", &font_size
);
3385 skip("Unable to locate and load font sserife.fon\n");
3389 SetLastError(0xdeadbeef);
3390 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
3391 ok(!ret
, "AddFontMemResourceEx should fail\n");
3392 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3393 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3396 SetLastError(0xdeadbeef);
3397 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
3398 ok(!ret
, "AddFontMemResourceEx should fail\n");
3399 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3400 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3403 SetLastError(0xdeadbeef);
3404 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
3405 ok(!ret
, "AddFontMemResourceEx should fail\n");
3406 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3407 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3410 SetLastError(0xdeadbeef);
3411 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
3412 ok(!ret
, "AddFontMemResourceEx should fail\n");
3413 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3414 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3417 SetLastError(0xdeadbeef);
3418 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
3419 ok(!ret
, "AddFontMemResourceEx should fail\n");
3420 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3421 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3424 SetLastError(0xdeadbeef);
3425 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
3426 ok(!ret
, "AddFontMemResourceEx should fail\n");
3427 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3428 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3431 num_fonts
= 0xdeadbeef;
3432 SetLastError(0xdeadbeef);
3433 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
3434 ok(!ret
, "AddFontMemResourceEx should fail\n");
3435 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3436 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3438 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3440 if (0) /* hangs under windows 2000 */
3442 num_fonts
= 0xdeadbeef;
3443 SetLastError(0xdeadbeef);
3444 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
3445 ok(!ret
, "AddFontMemResourceEx should fail\n");
3446 ok(GetLastError() == 0xdeadbeef,
3447 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3449 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3452 num_fonts
= 0xdeadbeef;
3453 SetLastError(0xdeadbeef);
3454 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
3455 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
3456 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3457 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
3461 SetLastError(0xdeadbeef);
3462 bRet
= pRemoveFontMemResourceEx(ret
);
3463 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
3465 /* test invalid pointer to number of loaded fonts */
3466 font
= load_font("sserife.fon", &font_size
);
3467 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
3469 SetLastError(0xdeadbeef);
3470 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
3471 ok(!ret
, "AddFontMemResourceEx should fail\n");
3472 ok(GetLastError() == 0xdeadbeef,
3473 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3476 SetLastError(0xdeadbeef);
3477 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
3478 ok(!ret
, "AddFontMemResourceEx should fail\n");
3479 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3480 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3486 static INT CALLBACK
enum_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3490 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3492 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3494 lf
= (LOGFONT
*)lparam
;
3499 static INT CALLBACK
enum_all_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3504 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3506 lf
= (LOGFONT
*)lparam
;
3507 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
3510 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3517 static void test_EnumFonts(void)
3523 if (!is_truetype_font_installed("Arial"))
3525 skip("Arial is not installed\n");
3529 /* Windows uses localized font face names, so Arial Bold won't be found */
3530 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
3532 skip("User locale is not English, skipping the test\n");
3536 hdc
= CreateCompatibleDC(0);
3538 ret
= EnumFontFamilies(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
3539 ok(!ret
, "font Arial is not enumerated\n");
3540 ret
= strcmp(lf
.lfFaceName
, "Arial");
3541 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3542 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
3544 lstrcpy(lf
.lfFaceName
, "Arial");
3545 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3546 ok(!ret
, "font Arial is not enumerated\n");
3547 ret
= strcmp(lf
.lfFaceName
, "Arial");
3548 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3549 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
3551 ret
= EnumFontFamilies(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
3552 ok(!ret
, "font Arial Bold is not enumerated\n");
3553 ret
= strcmp(lf
.lfFaceName
, "Arial");
3554 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3555 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
3557 lstrcpy(lf
.lfFaceName
, "Arial Bold");
3558 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3559 ok(ret
, "font Arial Bold should not be enumerated\n");
3561 ret
= EnumFontFamilies(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
3562 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
3563 ret
= strcmp(lf
.lfFaceName
, "Arial");
3564 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3565 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
3567 lstrcpy(lf
.lfFaceName
, "Arial Bold Italic");
3568 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3569 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
3571 ret
= EnumFontFamilies(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
3572 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
3574 lstrcpy(lf
.lfFaceName
, "Arial Italic Bold");
3575 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3576 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
3587 test_outline_font();
3588 test_bitmap_font_metrics();
3589 test_GdiGetCharDimensions();
3590 test_GetCharABCWidths();
3591 test_text_extents();
3592 test_GetGlyphIndices();
3593 test_GetKerningPairs();
3594 test_GetOutlineTextMetrics();
3595 test_SetTextJustification();
3596 test_font_charset();
3597 test_GetFontUnicodeRanges();
3598 test_nonexistent_font();
3600 test_height_selection();
3601 test_AddFontMemResource();
3604 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3605 * I'd like to avoid them in this test.
3607 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
3608 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
3609 if (is_truetype_font_installed("Arial Black") &&
3610 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3612 test_EnumFontFamilies("", ANSI_CHARSET
);
3613 test_EnumFontFamilies("", SYMBOL_CHARSET
);
3614 test_EnumFontFamilies("", DEFAULT_CHARSET
);
3617 skip("Arial Black or Symbol/Wingdings is not installed\n");
3618 test_GetTextMetrics();
3619 test_GdiRealizationInfo();
3621 test_GetGlyphOutline();
3622 test_GetTextMetrics2("Tahoma", -11);
3623 test_GetTextMetrics2("Tahoma", -55);
3624 test_GetTextMetrics2("Tahoma", -110);
3625 test_GetTextMetrics2("Arial", -11);
3626 test_GetTextMetrics2("Arial", -55);
3627 test_GetTextMetrics2("Arial", -110);
3628 test_CreateFontIndirect();
3629 test_CreateFontIndirectEx();