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 BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
45 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
46 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
47 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
48 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
49 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDV
*);
50 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
51 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
52 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
53 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
55 static HMODULE hgdi32
= 0;
56 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
58 static void init(void)
60 hgdi32
= GetModuleHandleA("gdi32.dll");
62 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
63 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
64 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
65 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
66 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
67 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
68 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
69 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
70 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
71 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
72 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
73 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
74 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
75 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
76 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
79 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
81 if (type
!= TRUETYPE_FONTTYPE
) return 1;
86 static BOOL
is_truetype_font_installed(const char *name
)
91 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
98 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
103 static BOOL
is_font_installed(const char *name
)
108 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
115 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
123 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
124 /* NT4 tries to be clever and only returns the minimum length */
125 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
127 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
128 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
129 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
130 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
131 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
132 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
133 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
134 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
135 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
136 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
137 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
138 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
139 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
140 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
141 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
142 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
143 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
144 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
145 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
146 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
147 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
148 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
149 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
150 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
151 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
152 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
153 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
154 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
157 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
159 HFONT hfont
= CreateFontIndirectA(lf
);
160 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
162 check_font(test
, lf
, hfont
);
166 static void test_logfont(void)
171 memset(&lf
, 0, sizeof lf
);
173 lf
.lfCharSet
= ANSI_CHARSET
;
174 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
175 lf
.lfWeight
= FW_DONTCARE
;
178 lf
.lfQuality
= DEFAULT_QUALITY
;
180 lstrcpyA(lf
.lfFaceName
, "Arial");
181 hfont
= create_font("Arial", &lf
);
184 memset(&lf
, 'A', sizeof(lf
));
185 hfont
= CreateFontIndirectA(&lf
);
186 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
188 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
189 check_font("AAA...", &lf
, hfont
);
193 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
195 if (type
& RASTER_FONTTYPE
)
197 LOGFONT
*lf
= (LOGFONT
*)lParam
;
199 return 0; /* stop enumeration */
202 return 1; /* continue enumeration */
205 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
207 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
208 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
209 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
210 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
211 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
212 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
213 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
214 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
215 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
216 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
217 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
218 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
219 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
220 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
221 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
222 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
223 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
224 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
225 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
226 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
229 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
230 LONG lfWidth
, const char *test_str
,
231 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
232 const SIZE
*size_orig
, INT width_of_A_orig
,
233 INT scale_x
, INT scale_y
)
236 OUTLINETEXTMETRIC otm
;
239 INT width_of_A
, cx
, cy
;
245 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
247 GetObjectA(hfont
, sizeof(lf
), &lf
);
249 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
251 otm
.otmSize
= sizeof(otm
) / 2;
252 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
253 ok(ret
== sizeof(otm
)/2 /* XP */ ||
254 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
256 memset(&otm
, 0x1, sizeof(otm
));
257 otm
.otmSize
= sizeof(otm
);
258 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
259 ok(ret
== sizeof(otm
) /* XP */ ||
260 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
262 memset(&tm
, 0x2, sizeof(tm
));
263 ret
= GetTextMetricsA(hdc
, &tm
);
264 ok(ret
, "GetTextMetricsA failed\n");
265 /* the structure size is aligned */
266 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
268 ok(0, "tm != otm\n");
269 compare_tm(&tm
, &otm
.otmTextMetrics
);
272 tm
= otm
.otmTextMetrics
;
273 if (0) /* these metrics are scaled too, but with rounding errors */
275 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
276 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
278 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
279 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
280 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
281 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
282 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
283 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
287 ret
= GetTextMetricsA(hdc
, &tm
);
288 ok(ret
, "GetTextMetricsA failed\n");
291 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
292 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
293 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
294 lfHeight
, scale_x
, scale_y
, cx
, cy
);
295 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
296 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
297 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
298 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
299 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
301 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
305 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
308 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
310 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
312 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
313 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
315 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
317 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
);
320 /* Test how GDI scales bitmap font metrics */
321 static void test_bitmap_font(void)
323 static const char test_str
[11] = "Test String";
326 HFONT hfont
, old_hfont
;
329 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
333 /* "System" has only 1 pixel size defined, otherwise the test breaks */
334 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
338 trace("no bitmap fonts were found, skipping the test\n");
342 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
344 height_orig
= bitmap_lf
.lfHeight
;
345 lfWidth
= bitmap_lf
.lfWidth
;
347 hfont
= create_font("bitmap", &bitmap_lf
);
348 old_hfont
= SelectObject(hdc
, hfont
);
349 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
350 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
351 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
352 SelectObject(hdc
, old_hfont
);
355 bitmap_lf
.lfHeight
= 0;
356 bitmap_lf
.lfWidth
= 4;
357 hfont
= create_font("bitmap", &bitmap_lf
);
358 old_hfont
= SelectObject(hdc
, hfont
);
359 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
360 SelectObject(hdc
, old_hfont
);
363 bitmap_lf
.lfHeight
= height_orig
;
364 bitmap_lf
.lfWidth
= lfWidth
;
366 /* test fractional scaling */
367 for (i
= 1; i
<= height_orig
* 6; i
++)
371 bitmap_lf
.lfHeight
= i
;
372 hfont
= create_font("fractional", &bitmap_lf
);
373 scale
= (i
+ height_orig
- 1) / height_orig
;
374 nearest_height
= scale
* height_orig
;
375 /* Only jump to the next height if the difference <= 25% original height */
376 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
377 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
378 so we'll not test this particular height. */
379 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
380 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
381 old_hfont
= SelectObject(hdc
, hfont
);
382 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
383 SelectObject(hdc
, old_hfont
);
387 /* test integer scaling 3x2 */
388 bitmap_lf
.lfHeight
= height_orig
* 2;
389 bitmap_lf
.lfWidth
*= 3;
390 hfont
= create_font("3x2", &bitmap_lf
);
391 old_hfont
= SelectObject(hdc
, hfont
);
392 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
393 SelectObject(hdc
, old_hfont
);
396 /* test integer scaling 3x3 */
397 bitmap_lf
.lfHeight
= height_orig
* 3;
398 bitmap_lf
.lfWidth
= 0;
399 hfont
= create_font("3x3", &bitmap_lf
);
400 old_hfont
= SelectObject(hdc
, hfont
);
401 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
402 SelectObject(hdc
, old_hfont
);
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
411 static const char test_str
[11] = "Test String";
414 HFONT hfont
, old_hfont
, old_hfont_2
;
415 OUTLINETEXTMETRICA otm
;
417 INT width_orig
, height_orig
, lfWidth
;
420 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
424 if (!is_truetype_font_installed("Arial"))
426 skip("Arial is not installed\n");
430 hdc
= CreateCompatibleDC(0);
432 memset(&lf
, 0, sizeof(lf
));
433 strcpy(lf
.lfFaceName
, "Arial");
435 hfont
= create_font("outline", &lf
);
436 old_hfont
= SelectObject(hdc
, hfont
);
437 otm
.otmSize
= sizeof(otm
);
438 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
442 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
443 SelectObject(hdc
, old_hfont
);
446 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
447 lf
.lfHeight
= otm
.otmEMSquare
;
448 lf
.lfHeight
= -lf
.lfHeight
;
449 hfont
= create_font("outline", &lf
);
450 old_hfont
= SelectObject(hdc
, hfont
);
451 otm
.otmSize
= sizeof(otm
);
452 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
453 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
454 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
455 SelectObject(hdc
, old_hfont
);
458 height_orig
= otm
.otmTextMetrics
.tmHeight
;
459 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
461 /* test integer scaling 3x2 */
462 lf
.lfHeight
= height_orig
* 2;
463 lf
.lfWidth
= lfWidth
* 3;
464 hfont
= create_font("3x2", &lf
);
465 old_hfont
= SelectObject(hdc
, hfont
);
466 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
467 SelectObject(hdc
, old_hfont
);
470 /* test integer scaling 3x3 */
471 lf
.lfHeight
= height_orig
* 3;
472 lf
.lfWidth
= lfWidth
* 3;
473 hfont
= create_font("3x3", &lf
);
474 old_hfont
= SelectObject(hdc
, hfont
);
475 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
476 SelectObject(hdc
, old_hfont
);
479 /* test integer scaling 1x1 */
480 lf
.lfHeight
= height_orig
* 1;
481 lf
.lfWidth
= lfWidth
* 1;
482 hfont
= create_font("1x1", &lf
);
483 old_hfont
= SelectObject(hdc
, hfont
);
484 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
485 SelectObject(hdc
, old_hfont
);
488 /* test integer scaling 1x1 */
489 lf
.lfHeight
= height_orig
;
491 hfont
= create_font("1x1", &lf
);
492 old_hfont
= SelectObject(hdc
, hfont
);
493 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
495 /* with an identity matrix */
496 memset(&gm
, 0, sizeof(gm
));
497 SetLastError(0xdeadbeef);
498 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
499 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
500 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
501 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
502 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
503 /* with a custom matrix */
504 memset(&gm
, 0, sizeof(gm
));
505 SetLastError(0xdeadbeef);
506 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
507 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
508 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
509 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
510 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
512 /* Test that changing the DC transformation affects only the font
513 * selected on this DC and doesn't affect the same font selected on
516 hdc_2
= CreateCompatibleDC(0);
517 old_hfont_2
= SelectObject(hdc_2
, hfont
);
518 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
520 SetMapMode(hdc
, MM_ANISOTROPIC
);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
525 /* test restrictions of compatibility mode GM_COMPATIBLE */
526 /* part 1: rescaling only X should not change font scaling on screen.
527 So compressing the X axis by 2 is not done, and this
528 appears as X scaling of 2 that no one requested. */
529 SetWindowExtEx(hdc
, 100, 100, NULL
);
530 SetViewportExtEx(hdc
, 50, 100, NULL
);
531 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
532 /* font metrics on another DC should be unchanged */
533 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
535 /* part 2: rescaling only Y should change font scaling.
536 As also X is scaled by a factor of 2, but this is not
537 requested by the DC transformation, we get a scaling factor
538 of 2 in the X coordinate. */
539 SetViewportExtEx(hdc
, 100, 200, NULL
);
540 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
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 /* restore scaling */
545 SetMapMode(hdc
, MM_TEXT
);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
550 SelectObject(hdc_2
, old_hfont_2
);
553 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
555 SelectObject(hdc
, old_hfont
);
558 skip("GM_ADVANCED is not supported on this platform\n");
569 SetLastError(0xdeadbeef);
570 ret
= SetWorldTransform(hdc
, &xform
);
571 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
573 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
575 /* with an identity matrix */
576 memset(&gm
, 0, sizeof(gm
));
577 SetLastError(0xdeadbeef);
578 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
579 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
581 pt
.x
= width_orig
; pt
.y
= 0;
583 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
584 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
585 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
586 /* with a custom matrix */
587 memset(&gm
, 0, sizeof(gm
));
588 SetLastError(0xdeadbeef);
589 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
590 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
591 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
592 pt
.x
= width_orig
; pt
.y
= 0;
594 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
595 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
596 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
598 SetLastError(0xdeadbeef);
599 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
600 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
602 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
604 /* with an identity matrix */
605 memset(&gm
, 0, sizeof(gm
));
606 SetLastError(0xdeadbeef);
607 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
608 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
610 pt
.x
= width_orig
; pt
.y
= 0;
612 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
613 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
614 /* with a custom matrix */
615 memset(&gm
, 0, sizeof(gm
));
616 SetLastError(0xdeadbeef);
617 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
618 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
619 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
620 pt
.x
= width_orig
; pt
.y
= 0;
622 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
623 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
625 SetLastError(0xdeadbeef);
626 ret
= SetMapMode(hdc
, MM_TEXT
);
627 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
629 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
631 /* with an identity matrix */
632 memset(&gm
, 0, sizeof(gm
));
633 SetLastError(0xdeadbeef);
634 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
635 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
636 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
637 pt
.x
= width_orig
; pt
.y
= 0;
639 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
640 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
641 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
642 /* with a custom matrix */
643 memset(&gm
, 0, sizeof(gm
));
644 SetLastError(0xdeadbeef);
645 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
646 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
647 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
648 pt
.x
= width_orig
; pt
.y
= 0;
650 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
651 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
652 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
654 SelectObject(hdc
, old_hfont
);
659 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
661 LOGFONT
*lf
= (LOGFONT
*)lParam
;
663 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
666 return 0; /* stop enumeration */
668 return 1; /* continue enumeration */
671 static void test_bitmap_font_metrics(void)
673 static const struct font_data
675 const char face_name
[LF_FACESIZE
];
676 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
677 int ave_char_width
, max_char_width
, dpi
;
678 BYTE first_char
, last_char
, def_char
, break_char
;
683 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
684 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
685 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
686 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
687 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
688 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
689 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
690 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
691 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
692 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
693 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
694 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
695 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
696 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
697 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
698 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
700 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
701 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
702 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
703 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
704 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
705 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
706 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
707 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
708 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
709 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
710 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
711 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
713 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
714 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
715 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
716 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
717 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
718 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
719 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
720 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
721 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
722 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
723 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
724 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
725 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
726 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
727 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
728 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
729 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
731 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
732 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
733 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
734 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
735 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
736 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
737 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
738 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
739 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
740 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
741 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
743 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
744 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
745 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
747 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
748 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
749 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
751 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
752 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
753 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN
},
755 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
756 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
758 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
759 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
760 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN
},
761 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
762 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
763 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN
},
764 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
765 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
766 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC
},
767 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN
},
768 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
769 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
770 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC
},
771 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN
},
772 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
773 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
774 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC
},
775 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN
},
776 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
777 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC
},
778 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN
},
780 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
781 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
782 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
783 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
784 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
785 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
786 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
787 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
788 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
789 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
790 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
791 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
793 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
794 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
795 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN
},
797 /* The 120dpi version still has its dpi marked as 96 */
798 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
800 /* FIXME: add "Terminal" */
804 HFONT hfont
, old_hfont
;
809 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
811 hdc
= CreateCompatibleDC(0);
814 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
818 memset(&lf
, 0, sizeof(lf
));
820 lf
.lfHeight
= fd
[i
].height
;
821 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
823 for(bit
= 0; bit
< 32; bit
++)
831 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
832 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
834 lf
.lfCharSet
= csi
.ciCharset
;
835 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
838 hfont
= create_font(lf
.lfFaceName
, &lf
);
839 old_hfont
= SelectObject(hdc
, hfont
);
840 bRet
= GetTextMetrics(hdc
, &tm
);
841 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
842 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
844 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
845 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
847 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
);
848 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
);
849 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
);
850 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
);
851 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
);
852 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
);
853 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
);
854 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmFirstChar
);
855 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmLastChar
);
856 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmDefaultChar
);
857 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmBreakChar
);
859 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
860 that make the max width bigger */
861 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
862 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
);
865 skip("Skipping font metrics test for system langid 0x%x\n",
868 SelectObject(hdc
, old_hfont
);
876 static void test_GdiGetCharDimensions(void)
882 LONG avgwidth
, height
;
883 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
885 if (!pGdiGetCharDimensions
)
887 win_skip("GdiGetCharDimensions not available on this platform\n");
891 hdc
= CreateCompatibleDC(NULL
);
893 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
894 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
896 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
897 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
898 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
900 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
901 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
903 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
904 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
907 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
908 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
909 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
914 static int CALLBACK
create_font_proc(const LOGFONT
*lpelfe
,
915 const TEXTMETRIC
*lpntme
,
916 DWORD FontType
, LPARAM lParam
)
918 if (FontType
& TRUETYPE_FONTTYPE
)
922 hfont
= CreateFontIndirect(lpelfe
);
925 *(HFONT
*)lParam
= hfont
;
933 static void test_GetCharABCWidths(void)
935 static const WCHAR str
[] = {'a',0};
957 {0xffffff, 0xffffff},
958 {0x1000000, 0x1000000},
959 {0xffffff, 0x1000000},
960 {0xffffffff, 0xffffffff}
967 BOOL r
[sizeof range
/ sizeof range
[0]];
970 {ANSI_CHARSET
, 0x30, 0x30, {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
971 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
972 {HANGEUL_CHARSET
, 0x8141, 0xac02, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
973 {JOHAB_CHARSET
, 0x8446, 0x3135, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
974 {GB2312_CHARSET
, 0x8141, 0x4e04, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}},
975 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001, {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
}}
979 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
981 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
985 memset(&lf
, 0, sizeof(lf
));
986 strcpy(lf
.lfFaceName
, "System");
989 hfont
= CreateFontIndirectA(&lf
);
991 hfont
= SelectObject(hdc
, hfont
);
993 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
994 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
996 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
997 ok(!ret
, "GetCharABCWidthsI should have failed\n");
999 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1000 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1002 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1003 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1005 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1006 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1008 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1009 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1011 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1012 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1014 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1015 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1017 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1018 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1020 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1021 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1023 hfont
= SelectObject(hdc
, hfont
);
1024 DeleteObject(hfont
);
1026 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1030 UINT code
= 0x41, j
;
1032 lf
.lfFaceName
[0] = '\0';
1033 lf
.lfCharSet
= c
[i
].cs
;
1034 lf
.lfPitchAndFamily
= 0;
1035 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1037 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1041 memset(a
, 0, sizeof a
);
1042 memset(w
, 0, sizeof w
);
1043 hfont
= SelectObject(hdc
, hfont
);
1044 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1045 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1046 memcmp(a
, w
, sizeof a
) == 0,
1047 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1049 memset(a
, 0xbb, sizeof a
);
1050 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1051 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1052 memset(full
, 0xcc, sizeof full
);
1053 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1054 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1055 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1056 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1058 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1060 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1061 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1062 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1065 hfont
= SelectObject(hdc
, hfont
);
1066 DeleteObject(hfont
);
1069 ReleaseDC(NULL
, hdc
);
1072 static void test_text_extents(void)
1074 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1076 INT i
, len
, fit1
, fit2
;
1085 memset(&lf
, 0, sizeof(lf
));
1086 strcpy(lf
.lfFaceName
, "Arial");
1089 hfont
= CreateFontIndirectA(&lf
);
1091 hfont
= SelectObject(hdc
, hfont
);
1092 GetTextMetricsA(hdc
, &tm
);
1093 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1094 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1096 SetLastError(0xdeadbeef);
1097 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1098 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1100 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1101 hfont
= SelectObject(hdc
, hfont
);
1102 DeleteObject(hfont
);
1108 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1109 extents
[0] = 1; /* So that the increasing sequence test will fail
1110 if the extents array is untouched. */
1111 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1112 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1113 ok(sz1
.cy
== sz2
.cy
,
1114 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1115 /* Because of the '\n' in the string GetTextExtentExPoint and
1116 GetTextExtentPoint return different widths under Win2k, but
1117 under WinXP they return the same width. So we don't test that
1120 for (i
= 1; i
< len
; ++i
)
1121 ok(extents
[i
-1] <= extents
[i
],
1122 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1124 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1125 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1126 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1127 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1128 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1129 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1130 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1131 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1132 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1133 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1134 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1135 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1136 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1137 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1138 HeapFree(GetProcessHeap(), 0, extents
);
1140 /* extents functions fail with -ve counts (the interesting case being -1) */
1141 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1142 ok(ret
== FALSE
, "got %d\n", ret
);
1143 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1144 ok(ret
== FALSE
, "got %d\n", ret
);
1145 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1146 ok(ret
== FALSE
, "got %d\n", ret
);
1148 /* max_extent = 0 succeeds and returns zero */
1150 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1152 broken(ret
== FALSE
), /* NT4, 2k */
1155 broken(fit1
== -215), /* NT4, 2k */
1156 "fit = %d\n", fit1
);
1157 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1158 ok(ret
== TRUE
, "got %d\n", ret
);
1159 ok(fit2
== 0, "fit = %d\n", fit2
);
1161 /* max_extent = -1 is interpreted as a very large width that will
1162 * definitely fit our three characters */
1164 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1165 ok(ret
== TRUE
, "got %d\n", ret
);
1166 todo_wine
ok(fit1
== 3, "fit = %d\n", fit1
);
1167 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1168 ok(ret
== TRUE
, "got %d\n", ret
);
1169 todo_wine
ok(fit2
== 3, "fit = %d\n", fit2
);
1171 /* max_extent = -2 is interpreted similarly, but the Ansi version
1172 * rejects it while the Unicode one accepts it */
1174 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1175 todo_wine
ok(ret
== FALSE
, "got %d\n", ret
);
1176 todo_wine
ok(fit1
== -215, "fit = %d\n", fit1
);
1177 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1178 ok(ret
== TRUE
, "got %d\n", ret
);
1179 todo_wine
ok(fit2
== 3, "fit = %d\n", fit2
);
1181 hfont
= SelectObject(hdc
, hfont
);
1182 DeleteObject(hfont
);
1183 ReleaseDC(NULL
, hdc
);
1186 static void test_GetGlyphIndices(void)
1193 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1194 WORD glyphs
[(sizeof(testtext
)/2)-1];
1198 if (!pGetGlyphIndicesW
) {
1199 win_skip("GetGlyphIndicesW not available on platform\n");
1205 memset(&lf
, 0, sizeof(lf
));
1206 strcpy(lf
.lfFaceName
, "System");
1208 lf
.lfCharSet
= ANSI_CHARSET
;
1210 hfont
= CreateFontIndirectA(&lf
);
1211 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1212 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1213 if (textm
.tmCharSet
== ANSI_CHARSET
)
1215 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1216 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1217 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1218 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1220 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1221 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1222 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1223 textm
.tmDefaultChar
, glyphs
[4]);
1226 /* FIXME: Write tests for non-ANSI charsets. */
1227 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1229 if(!is_font_installed("Tahoma"))
1231 skip("Tahoma is not installed so skipping this test\n");
1234 memset(&lf
, 0, sizeof(lf
));
1235 strcpy(lf
.lfFaceName
, "Tahoma");
1238 hfont
= CreateFontIndirectA(&lf
);
1239 hOldFont
= SelectObject(hdc
, hfont
);
1240 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1241 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1242 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1243 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1244 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1246 testtext
[0] = textm
.tmDefaultChar
;
1247 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1248 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1249 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1250 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1251 DeleteObject(SelectObject(hdc
, hOldFont
));
1254 static void test_GetKerningPairs(void)
1256 static const struct kerning_data
1258 const char face_name
[LF_FACESIZE
];
1260 /* some interesting fields from OUTLINETEXTMETRIC */
1261 LONG tmHeight
, tmAscent
, tmDescent
;
1266 UINT otmsCapEmHeight
;
1271 UINT otmusMinimumPPEM
;
1272 /* small subset of kerning pairs to test */
1273 DWORD total_kern_pairs
;
1274 const KERNINGPAIR kern_pair
[26];
1277 {"Arial", 12, 12, 9, 3,
1278 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1281 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1282 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1283 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1284 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1285 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1286 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1287 {933,970,+1},{933,972,-1}
1290 {"Arial", -34, 39, 32, 7,
1291 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1294 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1295 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1296 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1297 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1298 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1299 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1300 {933,970,+2},{933,972,-3}
1303 { "Arial", 120, 120, 97, 23,
1304 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1307 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1308 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1309 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1310 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1311 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1312 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1313 {933,970,+6},{933,972,-10}
1316 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1317 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1318 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1321 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1322 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1323 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1324 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1325 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1326 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1327 {933,970,+54},{933,972,-83}
1333 HFONT hfont
, hfont_old
;
1334 KERNINGPAIR
*kern_pair
;
1336 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1340 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1341 * which may render this test unusable, so we're trying to avoid that.
1343 SetLastError(0xdeadbeef);
1344 GetKerningPairsW(hdc
, 0, NULL
);
1345 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1347 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1352 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1354 OUTLINETEXTMETRICW otm
;
1357 if (!is_font_installed(kd
[i
].face_name
))
1359 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1363 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1365 memset(&lf
, 0, sizeof(lf
));
1366 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1367 lf
.lfHeight
= kd
[i
].height
;
1368 hfont
= CreateFontIndirect(&lf
);
1371 hfont_old
= SelectObject(hdc
, hfont
);
1373 SetLastError(0xdeadbeef);
1374 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1375 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1376 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1378 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
), "expected %d, got %d\n",
1379 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1380 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
), "expected %d, got %d\n",
1381 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1382 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1383 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1385 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1386 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1387 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1388 kd
[i
].otmAscent
, otm
.otmAscent
);
1389 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1390 kd
[i
].otmDescent
, otm
.otmDescent
);
1391 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1392 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1393 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1394 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1395 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1396 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1398 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1399 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1400 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1401 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1402 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1403 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1404 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1405 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1406 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1409 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1410 trace("total_kern_pairs %u\n", total_kern_pairs
);
1411 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1413 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1416 SetLastError(0xdeadbeef);
1417 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1418 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1419 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1420 ok(ret
== 0, "got %u, expected 0\n", ret
);
1422 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1423 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1425 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1426 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1428 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1429 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1433 for (n
= 0; n
< ret
; n
++)
1436 /* Disabled to limit console spam */
1437 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1438 trace("{'%c','%c',%d},\n",
1439 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1440 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1442 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1443 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1445 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1446 "pair %d:%d got %d, expected %d\n",
1447 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1448 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1454 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1455 matches
, kd
[i
].total_kern_pairs
);
1457 HeapFree(GetProcessHeap(), 0, kern_pair
);
1459 SelectObject(hdc
, hfont_old
);
1460 DeleteObject(hfont
);
1466 static void test_height_selection(void)
1468 static const struct font_data
1470 const char face_name
[LF_FACESIZE
];
1471 int requested_height
;
1472 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1475 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96 },
1476 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96 },
1477 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96 },
1478 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96 },
1479 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96 },
1480 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96 },
1481 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96 },
1482 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96 },
1483 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96 },
1484 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96 }
1488 HFONT hfont
, old_hfont
;
1492 hdc
= CreateCompatibleDC(0);
1495 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
1497 if (!is_truetype_font_installed(fd
[i
].face_name
))
1499 skip("%s is not installed\n", fd
[i
].face_name
);
1503 memset(&lf
, 0, sizeof(lf
));
1504 lf
.lfHeight
= fd
[i
].requested_height
;
1505 lf
.lfWeight
= fd
[i
].weight
;
1506 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1508 hfont
= CreateFontIndirect(&lf
);
1511 old_hfont
= SelectObject(hdc
, hfont
);
1512 ret
= GetTextMetrics(hdc
, &tm
);
1513 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1514 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1516 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1517 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
);
1518 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
);
1519 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
);
1520 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
);
1521 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1522 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
);
1524 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
);
1527 SelectObject(hdc
, old_hfont
);
1528 DeleteObject(hfont
);
1534 static void test_GetOutlineTextMetrics(void)
1536 OUTLINETEXTMETRIC
*otm
;
1538 HFONT hfont
, hfont_old
;
1540 DWORD ret
, otm_size
;
1543 if (!is_font_installed("Arial"))
1545 skip("Arial is not installed\n");
1551 memset(&lf
, 0, sizeof(lf
));
1552 strcpy(lf
.lfFaceName
, "Arial");
1554 lf
.lfWeight
= FW_NORMAL
;
1555 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1556 lf
.lfQuality
= PROOF_QUALITY
;
1557 hfont
= CreateFontIndirect(&lf
);
1560 hfont_old
= SelectObject(hdc
, hfont
);
1561 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1562 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1564 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1566 memset(otm
, 0xAA, otm_size
);
1567 SetLastError(0xdeadbeef);
1568 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1569 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1570 ok(ret
== 1 /* Win9x */ ||
1571 ret
== otm
->otmSize
/* XP*/,
1572 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1573 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1575 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1576 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1577 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1578 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1581 memset(otm
, 0xAA, otm_size
);
1582 SetLastError(0xdeadbeef);
1583 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1584 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1585 ok(ret
== 1 /* Win9x */ ||
1586 ret
== otm
->otmSize
/* XP*/,
1587 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1588 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1590 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1591 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1592 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1593 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1596 /* ask about truncated data */
1597 memset(otm
, 0xAA, otm_size
);
1598 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1599 SetLastError(0xdeadbeef);
1600 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1601 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1602 ok(ret
== 1 /* Win9x */ ||
1603 ret
== otm
->otmSize
/* XP*/,
1604 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1605 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1607 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1608 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1609 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1611 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1613 HeapFree(GetProcessHeap(), 0, otm
);
1615 SelectObject(hdc
, hfont_old
);
1616 DeleteObject(hfont
);
1621 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1625 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
1626 areaWidth
= clientArea
->right
- clientArea
->left
,
1628 BOOL lastExtent
= FALSE
;
1629 PSTR pFirstChar
, pLastChar
;
1635 int GetTextExtentExPointWWidth
;
1638 GetTextMetricsA(hdc
, &tm
);
1639 y
= clientArea
->top
;
1642 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1648 /* if not at the end of the string, ... */
1649 if (*str
== '\0') break;
1650 /* ... add the next word to the current extent */
1651 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1653 SetTextJustification(hdc
, 0, 0);
1654 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1655 } while ((int) size
.cx
< areaWidth
);
1657 /* ignore trailing break chars */
1659 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1665 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1667 SetTextJustification(hdc
, 0, 0);
1668 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1670 /* do not justify the last extent */
1671 if (*str
!= '\0' && breakCount
> 0)
1673 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1674 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1675 justifiedWidth
= size
.cx
;
1677 else lastExtent
= TRUE
;
1679 /* catch errors and report them */
1680 if (!lastExtent
&& (justifiedWidth
!= areaWidth
))
1682 memset(error
[nErrors
].extent
, 0, 100);
1683 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
1684 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
1690 } while (*str
&& y
< clientArea
->bottom
);
1692 for (e
= 0; e
< nErrors
; e
++)
1694 /* The width returned by GetTextExtentPoint32() is exactly the same
1695 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1696 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1697 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1698 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1702 static void test_SetTextJustification(void)
1709 static char testText
[] =
1710 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1711 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1712 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1713 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1714 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1715 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1716 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1718 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1719 GetClientRect( hwnd
, &clientArea
);
1720 hdc
= GetDC( hwnd
);
1722 memset(&lf
, 0, sizeof lf
);
1723 lf
.lfCharSet
= ANSI_CHARSET
;
1724 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1725 lf
.lfWeight
= FW_DONTCARE
;
1727 lf
.lfQuality
= DEFAULT_QUALITY
;
1728 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1729 hfont
= create_font("Times New Roman", &lf
);
1730 SelectObject(hdc
, hfont
);
1732 testJustification(hdc
, testText
, &clientArea
);
1734 DeleteObject(hfont
);
1735 ReleaseDC(hwnd
, hdc
);
1736 DestroyWindow(hwnd
);
1739 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1743 HFONT hfont
, hfont_old
;
1750 assert(count
<= 128);
1752 memset(&lf
, 0, sizeof(lf
));
1754 lf
.lfCharSet
= charset
;
1756 lstrcpyA(lf
.lfFaceName
, "Arial");
1757 SetLastError(0xdeadbeef);
1758 hfont
= CreateFontIndirectA(&lf
);
1759 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1762 hfont_old
= SelectObject(hdc
, hfont
);
1764 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1765 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1767 SetLastError(0xdeadbeef);
1768 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1769 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1771 if (charset
== SYMBOL_CHARSET
)
1773 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1774 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1778 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1779 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1782 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1784 trace("Can't find codepage for charset %d\n", cs
);
1788 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1790 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
1792 skip("Font code page %d, looking for code page %d\n",
1793 pGdiGetCodePage(hdc
), code_page
);
1801 WCHAR unicode_buf
[128];
1803 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1805 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1807 SetLastError(0xdeadbeef);
1808 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1809 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
1810 count
, ret
, GetLastError());
1816 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1818 SetLastError(0xdeadbeef);
1819 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1820 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
1821 count
, ret
, GetLastError());
1824 SelectObject(hdc
, hfont_old
);
1825 DeleteObject(hfont
);
1832 static void test_font_charset(void)
1834 static struct charset_data
1838 WORD font_idxA
[128], font_idxW
[128];
1841 { ANSI_CHARSET
, 1252 },
1842 { RUSSIAN_CHARSET
, 1251 },
1843 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1847 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1849 win_skip("Skipping the font charset test on a Win9x platform\n");
1853 if (!is_font_installed("Arial"))
1855 skip("Arial is not installed\n");
1859 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1861 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1863 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1865 skip("Symbol or Wingdings is not installed\n");
1869 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
1870 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
1871 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1874 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1877 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1878 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1881 skip("Symbol or Wingdings is not installed\n");
1884 static void test_GetFontUnicodeRanges(void)
1888 HFONT hfont
, hfont_old
;
1893 if (!pGetFontUnicodeRanges
)
1895 win_skip("GetFontUnicodeRanges not available before W2K\n");
1899 memset(&lf
, 0, sizeof(lf
));
1900 lstrcpyA(lf
.lfFaceName
, "Arial");
1901 hfont
= create_font("Arial", &lf
);
1904 hfont_old
= SelectObject(hdc
, hfont
);
1906 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1907 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1909 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1910 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1912 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1914 size
= pGetFontUnicodeRanges(hdc
, gs
);
1915 ok(size
, "GetFontUnicodeRanges failed\n");
1917 if (0) /* Disabled to limit console spam */
1918 for (i
= 0; i
< gs
->cRanges
; i
++)
1919 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1920 trace("found %u ranges\n", gs
->cRanges
);
1922 HeapFree(GetProcessHeap(), 0, gs
);
1924 SelectObject(hdc
, hfont_old
);
1925 DeleteObject(hfont
);
1926 ReleaseDC(NULL
, hdc
);
1929 #define MAX_ENUM_FONTS 4096
1931 struct enum_font_data
1934 LOGFONT lf
[MAX_ENUM_FONTS
];
1937 struct enum_font_dataW
1940 LOGFONTW lf
[MAX_ENUM_FONTS
];
1943 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1945 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1947 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1949 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1950 if (0) /* Disabled to limit console spam */
1951 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1952 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1953 if (efd
->total
< MAX_ENUM_FONTS
)
1954 efd
->lf
[efd
->total
++] = *lf
;
1956 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1961 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
1963 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
1965 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1967 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1968 if (0) /* Disabled to limit console spam */
1969 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1970 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1971 if (efd
->total
< MAX_ENUM_FONTS
)
1972 efd
->lf
[efd
->total
++] = *lf
;
1974 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1979 static void get_charset_stats(struct enum_font_data
*efd
,
1980 int *ansi_charset
, int *symbol_charset
,
1981 int *russian_charset
)
1986 *symbol_charset
= 0;
1987 *russian_charset
= 0;
1989 for (i
= 0; i
< efd
->total
; i
++)
1991 switch (efd
->lf
[i
].lfCharSet
)
1996 case SYMBOL_CHARSET
:
1997 (*symbol_charset
)++;
1999 case RUSSIAN_CHARSET
:
2000 (*russian_charset
)++;
2006 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2007 int *ansi_charset
, int *symbol_charset
,
2008 int *russian_charset
)
2013 *symbol_charset
= 0;
2014 *russian_charset
= 0;
2016 for (i
= 0; i
< efd
->total
; i
++)
2018 switch (efd
->lf
[i
].lfCharSet
)
2023 case SYMBOL_CHARSET
:
2024 (*symbol_charset
)++;
2026 case RUSSIAN_CHARSET
:
2027 (*russian_charset
)++;
2033 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2035 struct enum_font_data efd
;
2036 struct enum_font_dataW efdw
;
2039 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2041 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2043 if (*font_name
&& !is_truetype_font_installed(font_name
))
2045 skip("%s is not installed\n", font_name
);
2051 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2052 * while EnumFontFamiliesEx doesn't.
2054 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2057 * Use EnumFontFamiliesW since win98 crashes when the
2058 * second parameter is NULL using EnumFontFamilies
2061 SetLastError(0xdeadbeef);
2062 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2063 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2066 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2067 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2068 ansi_charset
, symbol_charset
, russian_charset
);
2069 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2070 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2071 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2072 ok(russian_charset
> 0 ||
2073 broken(russian_charset
== 0), /* NT4 */
2074 "NULL family should enumerate RUSSIAN_CHARSET\n");
2078 SetLastError(0xdeadbeef);
2079 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2080 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2083 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2084 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2085 ansi_charset
, symbol_charset
, russian_charset
);
2086 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2087 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2088 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2089 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2094 SetLastError(0xdeadbeef);
2095 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2096 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2097 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2098 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2099 ansi_charset
, symbol_charset
, russian_charset
,
2100 *font_name
? font_name
: "<empty>");
2102 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2104 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2105 for (i
= 0; i
< efd
.total
; i
++)
2107 /* FIXME: remove completely once Wine is fixed */
2108 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2111 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2114 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2115 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2116 font_name
, efd
.lf
[i
].lfFaceName
);
2119 memset(&lf
, 0, sizeof(lf
));
2120 lf
.lfCharSet
= ANSI_CHARSET
;
2121 lstrcpy(lf
.lfFaceName
, font_name
);
2123 SetLastError(0xdeadbeef);
2124 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2125 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2126 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2127 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2128 ansi_charset
, symbol_charset
, russian_charset
,
2129 *font_name
? font_name
: "<empty>");
2130 if (font_charset
== SYMBOL_CHARSET
)
2133 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2135 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2139 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2140 for (i
= 0; i
< efd
.total
; i
++)
2142 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2144 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2145 font_name
, efd
.lf
[i
].lfFaceName
);
2149 /* DEFAULT_CHARSET should enumerate all available charsets */
2150 memset(&lf
, 0, sizeof(lf
));
2151 lf
.lfCharSet
= DEFAULT_CHARSET
;
2152 lstrcpy(lf
.lfFaceName
, font_name
);
2154 SetLastError(0xdeadbeef);
2155 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2156 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2157 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2158 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2159 ansi_charset
, symbol_charset
, russian_charset
,
2160 *font_name
? font_name
: "<empty>");
2161 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2162 for (i
= 0; i
< efd
.total
; i
++)
2165 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2166 font_name
, efd
.lf
[i
].lfFaceName
);
2170 switch (font_charset
)
2173 ok(ansi_charset
> 0,
2174 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2176 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2177 ok(russian_charset
> 0,
2178 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2180 case SYMBOL_CHARSET
:
2182 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2184 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2185 ok(!russian_charset
,
2186 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2188 case DEFAULT_CHARSET
:
2189 ok(ansi_charset
> 0,
2190 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2191 ok(symbol_charset
> 0,
2192 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2193 ok(russian_charset
> 0,
2194 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2200 ok(ansi_charset
> 0,
2201 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2202 ok(symbol_charset
> 0,
2203 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2204 ok(russian_charset
> 0,
2205 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2208 memset(&lf
, 0, sizeof(lf
));
2209 lf
.lfCharSet
= SYMBOL_CHARSET
;
2210 lstrcpy(lf
.lfFaceName
, font_name
);
2212 SetLastError(0xdeadbeef);
2213 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2214 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2215 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2216 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2217 ansi_charset
, symbol_charset
, russian_charset
,
2218 *font_name
? font_name
: "<empty>");
2219 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2220 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2223 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2224 for (i
= 0; i
< efd
.total
; i
++)
2226 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2228 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2229 font_name
, efd
.lf
[i
].lfFaceName
);
2233 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2234 ok(symbol_charset
> 0,
2235 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2236 ok(!russian_charset
,
2237 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2243 static INT CALLBACK
enum_font_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2245 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2247 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2249 if (efd
->total
< MAX_ENUM_FONTS
)
2250 efd
->lf
[efd
->total
++] = *lf
;
2252 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2257 static void test_EnumFontFamiliesEx_default_charset(void)
2259 struct enum_font_data efd
;
2260 LOGFONT gui_font
, enum_font
;
2264 ret
= GetObject(GetStockObject(DEFAULT_GUI_FONT
), sizeof(gui_font
), &gui_font
);
2265 ok(ret
, "GetObject failed.\n");
2272 memset(&enum_font
, 0, sizeof(enum_font
));
2273 lstrcpy(enum_font
.lfFaceName
, gui_font
.lfFaceName
);
2274 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
2275 EnumFontFamiliesEx(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
2278 if (efd
.total
== 0) {
2279 skip("'%s' is not found or not a TrueType font.\n", gui_font
.lfFaceName
);
2282 trace("'%s' has %d charsets.\n", gui_font
.lfFaceName
, efd
.total
);
2284 ok(efd
.lf
[0].lfCharSet
== gui_font
.lfCharSet
,
2285 "(%s) got charset %d expected %d\n",
2286 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, gui_font
.lfCharSet
);
2291 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2293 HFONT hfont
, hfont_prev
;
2295 GLYPHMETRICS gm1
, gm2
;
2299 if(!pGetGlyphIndicesA
)
2302 /* negative widths are handled just as positive ones */
2303 lf2
.lfWidth
= -lf
->lfWidth
;
2305 SetLastError(0xdeadbeef);
2306 hfont
= CreateFontIndirectA(lf
);
2307 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2308 check_font("original", lf
, hfont
);
2310 hfont_prev
= SelectObject(hdc
, hfont
);
2312 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2313 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2315 SelectObject(hdc
, hfont_prev
);
2316 DeleteObject(hfont
);
2317 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2321 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2322 memset(&gm1
, 0xab, sizeof(gm1
));
2323 SetLastError(0xdeadbeef);
2324 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2325 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2327 SelectObject(hdc
, hfont_prev
);
2328 DeleteObject(hfont
);
2330 SetLastError(0xdeadbeef);
2331 hfont
= CreateFontIndirectA(&lf2
);
2332 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2333 check_font("negative width", &lf2
, hfont
);
2335 hfont_prev
= SelectObject(hdc
, hfont
);
2337 memset(&gm2
, 0xbb, sizeof(gm2
));
2338 SetLastError(0xdeadbeef);
2339 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2340 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2342 SelectObject(hdc
, hfont_prev
);
2343 DeleteObject(hfont
);
2345 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2346 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2347 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2348 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2349 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2350 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2351 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2352 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2353 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2354 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2355 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2358 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2359 #include "pshpack2.h"
2363 SHORT xAvgCharWidth
;
2364 USHORT usWeightClass
;
2365 USHORT usWidthClass
;
2367 SHORT ySubscriptXSize
;
2368 SHORT ySubscriptYSize
;
2369 SHORT ySubscriptXOffset
;
2370 SHORT ySubscriptYOffset
;
2371 SHORT ySuperscriptXSize
;
2372 SHORT ySuperscriptYSize
;
2373 SHORT ySuperscriptXOffset
;
2374 SHORT ySuperscriptYOffset
;
2375 SHORT yStrikeoutSize
;
2376 SHORT yStrikeoutPosition
;
2379 ULONG ulUnicodeRange1
;
2380 ULONG ulUnicodeRange2
;
2381 ULONG ulUnicodeRange3
;
2382 ULONG ulUnicodeRange4
;
2385 USHORT usFirstCharIndex
;
2386 USHORT usLastCharIndex
;
2387 /* According to the Apple spec, original version didn't have the below fields,
2388 * version numbers were taken from the OpenType spec.
2390 /* version 0 (TrueType 1.5) */
2391 USHORT sTypoAscender
;
2392 USHORT sTypoDescender
;
2393 USHORT sTypoLineGap
;
2395 USHORT usWinDescent
;
2396 /* version 1 (TrueType 1.66) */
2397 ULONG ulCodePageRange1
;
2398 ULONG ulCodePageRange2
;
2399 /* version 2 (OpenType 1.2) */
2402 USHORT usDefaultChar
;
2404 USHORT usMaxContext
;
2406 #include "poppack.h"
2408 #ifdef WORDS_BIGENDIAN
2409 #define GET_BE_WORD(x) (x)
2410 #define GET_BE_DWORD(x) (x)
2412 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2413 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2416 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2417 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2418 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2419 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2420 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2421 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2434 } cmap_encoding_record
;
2442 BYTE glyph_ids
[256];
2452 USHORT search_range
;
2453 USHORT entry_selector
;
2456 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2459 USHORT start_count[seg_countx2 / 2];
2460 USHORT id_delta[seg_countx2 / 2];
2461 USHORT id_range_offset[seg_countx2 / 2];
2471 USHORT id_range_offset
;
2472 } cmap_format_4_seg
;
2474 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2476 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
2477 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
2478 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2479 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2480 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2483 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2486 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2490 for(i
= 0; i
< 256; i
++)
2492 if(cmap
->glyph_ids
[i
] == 0) continue;
2494 if(*first
== 256) *first
= i
;
2496 if(*first
== 256) return FALSE
;
2500 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2502 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2503 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2504 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2505 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2506 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2509 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2512 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2513 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2514 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2518 for(i
= 0; i
< seg_count
; i
++)
2521 cmap_format_4_seg seg
;
2523 get_seg4(cmap
, i
, &seg
);
2524 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2526 if(seg
.id_range_offset
== 0)
2527 index
= (seg
.id_delta
+ code
) & 0xffff;
2530 index
= seg
.id_range_offset
/ 2
2531 + code
- seg
.start_count
2534 /* some fonts have broken last segment */
2535 if ((char *)(glyph_ids
+ index
+ 1) < (char *)ptr
+ limit
)
2536 index
= GET_BE_WORD(glyph_ids
[index
]);
2539 trace("segment %04x/%04x index %04x points to nowhere\n",
2540 seg
.start_count
, seg
.end_count
, index
);
2543 if(index
) index
+= seg
.id_delta
;
2545 if(*first
== 0x10000)
2546 *last
= *first
= code
;
2552 if(*first
== 0x10000) return FALSE
;
2556 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2559 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2561 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2563 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2564 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2577 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2580 cmap_header
*header
;
2585 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2586 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2587 if(size
== GDI_ERROR
) return FALSE
;
2589 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2590 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2591 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2592 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2594 cmap
= get_cmap(header
, 3, 1);
2596 *cmap_type
= cmap_ms_unicode
;
2599 cmap
= get_cmap(header
, 3, 0);
2600 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2604 *cmap_type
= cmap_none
;
2608 format
= GET_BE_WORD(*(WORD
*)cmap
);
2612 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2615 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2618 trace("unhandled cmap format %d\n", format
);
2623 HeapFree(GetProcessHeap(), 0, header
);
2627 #define TT_PLATFORM_MICROSOFT 3
2628 #define TT_MS_ID_UNICODE_CS 1
2629 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2630 #define TT_NAME_ID_FULL_NAME 4
2632 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, char *out_buf
, SIZE_T out_size
)
2634 struct sfnt_name_header
2637 USHORT number_of_record
;
2638 USHORT storage_offset
;
2650 LONG size
, offset
, length
;
2656 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
2657 ok(size
!= GDI_ERROR
, "no name table found\n");
2658 if(size
== GDI_ERROR
) return FALSE
;
2660 data
= HeapAlloc(GetProcessHeap(), 0, size
);
2661 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
2662 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2664 header
= (void *)data
;
2665 header
->format
= GET_BE_WORD(header
->format
);
2666 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
2667 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
2668 if (header
->format
!= 0)
2670 trace("got format %u\n", header
->format
);
2673 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
2675 trace("number records out of range: %d\n", header
->number_of_record
);
2678 if (header
->storage_offset
>= size
)
2680 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
2684 entry
= (void *)&header
[1];
2685 for (i
= 0; i
< header
->number_of_record
; i
++)
2687 if (GET_BE_WORD(entry
[i
].platform_id
) != TT_PLATFORM_MICROSOFT
||
2688 GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_UNICODE_CS
||
2689 GET_BE_WORD(entry
[i
].language_id
) != TT_MS_LANGID_ENGLISH_UNITED_STATES
||
2690 GET_BE_WORD(entry
[i
].name_id
) != name_id
)
2695 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[i
].offset
);
2696 length
= GET_BE_WORD(entry
[i
].length
);
2697 if (offset
+ length
> size
)
2699 trace("entry %d is out of range\n", i
);
2702 if (length
>= out_size
)
2704 trace("buffer too small for entry %d\n", i
);
2708 name
= (WCHAR
*)(data
+ offset
);
2709 for (c
= 0; c
< length
/ 2; c
++)
2710 out_buf
[c
] = GET_BE_WORD(name
[c
]);
2718 HeapFree(GetProcessHeap(), 0, data
);
2722 static void test_text_metrics(const LOGFONTA
*lf
)
2725 HFONT hfont
, hfont_old
;
2729 const char *font_name
= lf
->lfFaceName
;
2730 DWORD cmap_first
= 0, cmap_last
= 0;
2731 cmap_type cmap_type
;
2732 BOOL sys_lang_non_english
;
2734 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
2737 SetLastError(0xdeadbeef);
2738 hfont
= CreateFontIndirectA(lf
);
2739 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2741 hfont_old
= SelectObject(hdc
, hfont
);
2743 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2744 if (size
== GDI_ERROR
)
2746 trace("OS/2 chunk was not found\n");
2749 if (size
> sizeof(tt_os2
))
2751 trace("got too large OS/2 chunk of size %u\n", size
);
2752 size
= sizeof(tt_os2
);
2755 memset(&tt_os2
, 0, sizeof(tt_os2
));
2756 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2757 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2759 SetLastError(0xdeadbeef);
2760 ret
= GetTextMetricsA(hdc
, &tmA
);
2761 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2763 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
2765 skip("Unable to retrieve first and last glyphs from cmap\n");
2769 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
2770 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
2771 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
2775 version
= GET_BE_WORD(tt_os2
.version
);
2777 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2778 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2779 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2780 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2782 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2783 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
2784 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
2786 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
2791 case 1257: /* Baltic */
2792 expect_last_W
= 0xf8fd;
2795 expect_last_W
= 0xf0ff;
2797 expect_break_W
= 0x20;
2798 expect_default_W
= expect_break_W
- 1;
2799 expect_first_A
= 0x1e;
2800 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
2804 expect_first_W
= cmap_first
;
2805 expect_last_W
= min(cmap_last
, os2_last_char
);
2806 if(os2_first_char
<= 1)
2807 expect_break_W
= os2_first_char
+ 2;
2808 else if(os2_first_char
> 0xff)
2809 expect_break_W
= 0x20;
2811 expect_break_W
= os2_first_char
;
2812 expect_default_W
= expect_break_W
- 1;
2813 expect_first_A
= expect_default_W
- 1;
2814 expect_last_A
= min(expect_last_W
, 0xff);
2816 expect_break_A
= expect_break_W
;
2817 expect_default_A
= expect_default_W
;
2819 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2820 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
2821 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
2822 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2823 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2825 ok(tmA
.tmFirstChar
== expect_first_A
||
2826 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2827 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2828 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
2829 ok(tmA
.tmLastChar
== expect_last_A
||
2830 tmA
.tmLastChar
== 0xff /* win9x */,
2831 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
2833 skip("tmLastChar is DBCS lead byte\n");
2834 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
2835 font_name
, tmA
.tmBreakChar
, expect_break_A
);
2836 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
2837 "A: tmDefaultChar for %s got %02x expected %02x\n",
2838 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
2841 SetLastError(0xdeadbeef);
2842 ret
= GetTextMetricsW(hdc
, &tmW
);
2843 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2844 "GetTextMetricsW error %u\n", GetLastError());
2847 /* Wine uses the os2 first char */
2848 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
2849 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2850 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2852 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2853 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2855 /* Wine uses the os2 last char */
2856 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
2857 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2858 font_name
, tmW
.tmLastChar
, expect_last_W
);
2860 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2861 font_name
, tmW
.tmLastChar
, expect_last_W
);
2862 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
2863 font_name
, tmW
.tmBreakChar
, expect_break_W
);
2864 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
2865 "W: tmDefaultChar for %s got %02x expected %02x\n",
2866 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
2868 /* Test the aspect ratio while we have tmW */
2869 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2870 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2871 tmW
.tmDigitizedAspectX
, ret
);
2872 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2873 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2874 tmW
.tmDigitizedAspectX
, ret
);
2878 /* test FF_ values */
2879 switch(tt_os2
.panose
.bFamilyType
)
2883 case PAN_FAMILY_TEXT_DISPLAY
:
2884 case PAN_FAMILY_PICTORIAL
:
2886 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
2887 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
2889 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
2892 switch(tt_os2
.panose
.bSerifStyle
)
2897 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
2900 case PAN_SERIF_COVE
:
2901 case PAN_SERIF_OBTUSE_COVE
:
2902 case PAN_SERIF_SQUARE_COVE
:
2903 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
2904 case PAN_SERIF_SQUARE
:
2905 case PAN_SERIF_THIN
:
2906 case PAN_SERIF_BONE
:
2907 case PAN_SERIF_EXAGGERATED
:
2908 case PAN_SERIF_TRIANGLE
:
2909 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
2912 case PAN_SERIF_NORMAL_SANS
:
2913 case PAN_SERIF_OBTUSE_SANS
:
2914 case PAN_SERIF_PERP_SANS
:
2915 case PAN_SERIF_FLARED
:
2916 case PAN_SERIF_ROUNDED
:
2917 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
2922 case PAN_FAMILY_SCRIPT
:
2923 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
2926 case PAN_FAMILY_DECORATIVE
:
2927 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
2931 test_negative_width(hdc
, lf
);
2934 SelectObject(hdc
, hfont_old
);
2935 DeleteObject(hfont
);
2940 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2942 INT
*enumed
= (INT
*)lParam
;
2944 if (type
== TRUETYPE_FONTTYPE
)
2947 test_text_metrics(lf
);
2952 static void test_GetTextMetrics(void)
2958 /* Report only once */
2959 if(!pGetGlyphIndicesA
)
2960 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2964 memset(&lf
, 0, sizeof(lf
));
2965 lf
.lfCharSet
= DEFAULT_CHARSET
;
2967 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2968 trace("Tested metrics of %d truetype fonts\n", enumed
);
2973 static void test_nonexistent_font(void)
2981 { "Times New Roman Baltic", 186 },
2982 { "Times New Roman CE", 238 },
2983 { "Times New Roman CYR", 204 },
2984 { "Times New Roman Greek", 161 },
2985 { "Times New Roman TUR", 162 }
2991 INT cs
, expected_cs
, i
;
2992 char buf
[LF_FACESIZE
];
2994 if (!is_truetype_font_installed("Arial") ||
2995 !is_truetype_font_installed("Times New Roman"))
2997 skip("Arial or Times New Roman not installed\n");
3001 expected_cs
= GetACP();
3002 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3004 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3007 expected_cs
= csi
.ciCharset
;
3008 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3012 memset(&lf
, 0, sizeof(lf
));
3014 lf
.lfWeight
= FW_REGULAR
;
3015 lf
.lfCharSet
= ANSI_CHARSET
;
3016 lf
.lfPitchAndFamily
= FF_SWISS
;
3017 strcpy(lf
.lfFaceName
, "Nonexistent font");
3018 hfont
= CreateFontIndirectA(&lf
);
3019 hfont
= SelectObject(hdc
, hfont
);
3020 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3021 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
3022 cs
= GetTextCharset(hdc
);
3023 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3024 DeleteObject(SelectObject(hdc
, hfont
));
3026 memset(&lf
, 0, sizeof(lf
));
3028 lf
.lfWeight
= FW_DONTCARE
;
3029 strcpy(lf
.lfFaceName
, "Nonexistent font");
3030 hfont
= CreateFontIndirectA(&lf
);
3031 hfont
= SelectObject(hdc
, hfont
);
3032 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3033 todo_wine
/* Wine uses Arial for all substitutions */
3034 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
3035 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
3036 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3038 cs
= GetTextCharset(hdc
);
3039 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
3040 DeleteObject(SelectObject(hdc
, hfont
));
3042 memset(&lf
, 0, sizeof(lf
));
3044 lf
.lfWeight
= FW_REGULAR
;
3045 strcpy(lf
.lfFaceName
, "Nonexistent font");
3046 hfont
= CreateFontIndirectA(&lf
);
3047 hfont
= SelectObject(hdc
, hfont
);
3048 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3049 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3050 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
3051 cs
= GetTextCharset(hdc
);
3052 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3053 DeleteObject(SelectObject(hdc
, hfont
));
3055 memset(&lf
, 0, sizeof(lf
));
3057 lf
.lfWeight
= FW_DONTCARE
;
3058 strcpy(lf
.lfFaceName
, "Times New Roman");
3059 hfont
= CreateFontIndirectA(&lf
);
3060 hfont
= SelectObject(hdc
, hfont
);
3061 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3062 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
3063 cs
= GetTextCharset(hdc
);
3064 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3065 DeleteObject(SelectObject(hdc
, hfont
));
3067 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
3069 memset(&lf
, 0, sizeof(lf
));
3071 lf
.lfWeight
= FW_REGULAR
;
3072 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3073 hfont
= CreateFontIndirectA(&lf
);
3074 hfont
= SelectObject(hdc
, hfont
);
3075 cs
= GetTextCharset(hdc
);
3076 if (font_subst
[i
].charset
== expected_cs
)
3078 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3079 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3080 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
3084 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
3085 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3086 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3087 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
3089 DeleteObject(SelectObject(hdc
, hfont
));
3091 memset(&lf
, 0, sizeof(lf
));
3093 lf
.lfWeight
= FW_DONTCARE
;
3094 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3095 hfont
= CreateFontIndirectA(&lf
);
3096 hfont
= SelectObject(hdc
, hfont
);
3097 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3098 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
3099 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
3100 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
3101 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3102 "got %s for font %s\n", buf
, font_subst
[i
].name
);
3103 cs
= GetTextCharset(hdc
);
3104 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3105 DeleteObject(SelectObject(hdc
, hfont
));
3111 static void test_GdiRealizationInfo(void)
3116 HFONT hfont
, hfont_old
;
3119 if(!pGdiRealizationInfo
)
3121 win_skip("GdiRealizationInfo not available\n");
3127 memset(info
, 0xcc, sizeof(info
));
3128 r
= pGdiRealizationInfo(hdc
, info
);
3129 ok(r
!= 0, "ret 0\n");
3130 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
3131 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3133 if (!is_truetype_font_installed("Arial"))
3135 skip("skipping GdiRealizationInfo with truetype font\n");
3139 memset(&lf
, 0, sizeof(lf
));
3140 strcpy(lf
.lfFaceName
, "Arial");
3142 lf
.lfWeight
= FW_NORMAL
;
3143 hfont
= CreateFontIndirectA(&lf
);
3144 hfont_old
= SelectObject(hdc
, hfont
);
3146 memset(info
, 0xcc, sizeof(info
));
3147 r
= pGdiRealizationInfo(hdc
, info
);
3148 ok(r
!= 0, "ret 0\n");
3149 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
3150 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3152 DeleteObject(SelectObject(hdc
, hfont_old
));
3158 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3159 the nul in the count of characters copied when the face name buffer is not
3160 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3161 always includes it. */
3162 static void test_GetTextFace(void)
3164 static const char faceA
[] = "Tahoma";
3165 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
3168 char bufA
[LF_FACESIZE
];
3169 WCHAR bufW
[LF_FACESIZE
];
3174 if(!is_font_installed("Tahoma"))
3176 skip("Tahoma is not installed so skipping this test\n");
3181 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
3182 f
= CreateFontIndirectA(&fA
);
3183 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
3186 g
= SelectObject(dc
, f
);
3187 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
3188 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
3189 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
3191 /* Play with the count arg. */
3193 n
= GetTextFaceA(dc
, 0, bufA
);
3194 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3195 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3198 n
= GetTextFaceA(dc
, 1, bufA
);
3199 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3200 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3202 bufA
[0] = 'x'; bufA
[1] = 'y';
3203 n
= GetTextFaceA(dc
, 2, bufA
);
3204 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
3205 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
3207 n
= GetTextFaceA(dc
, 0, NULL
);
3208 ok(n
== sizeof faceA
||
3209 broken(n
== 0), /* win98, winMe */
3210 "GetTextFaceA returned %d\n", n
);
3212 DeleteObject(SelectObject(dc
, g
));
3213 ReleaseDC(NULL
, dc
);
3216 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3217 SetLastError(0xdeadbeef);
3218 f
= CreateFontIndirectW(&fW
);
3219 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3221 win_skip("CreateFontIndirectW is not implemented\n");
3224 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3227 g
= SelectObject(dc
, f
);
3228 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3229 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3230 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3232 /* Play with the count arg. */
3234 n
= GetTextFaceW(dc
, 0, bufW
);
3235 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3236 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3239 n
= GetTextFaceW(dc
, 1, bufW
);
3240 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3241 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3243 bufW
[0] = 'x'; bufW
[1] = 'y';
3244 n
= GetTextFaceW(dc
, 2, bufW
);
3245 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
3246 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
3248 n
= GetTextFaceW(dc
, 0, NULL
);
3249 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3251 DeleteObject(SelectObject(dc
, g
));
3252 ReleaseDC(NULL
, dc
);
3255 static void test_orientation(void)
3257 static const char test_str
[11] = "Test String";
3260 HFONT hfont
, old_hfont
;
3263 if (!is_truetype_font_installed("Arial"))
3265 skip("Arial is not installed\n");
3269 hdc
= CreateCompatibleDC(0);
3270 memset(&lf
, 0, sizeof(lf
));
3271 lstrcpyA(lf
.lfFaceName
, "Arial");
3273 lf
.lfOrientation
= lf
.lfEscapement
= 900;
3274 hfont
= create_font("orientation", &lf
);
3275 old_hfont
= SelectObject(hdc
, hfont
);
3276 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
3277 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
3278 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
3279 SelectObject(hdc
, old_hfont
);
3280 DeleteObject(hfont
);
3284 static void test_oemcharset(void)
3288 HFONT hfont
, old_hfont
;
3291 hdc
= CreateCompatibleDC(0);
3292 ZeroMemory(&lf
, sizeof(lf
));
3294 lf
.lfCharSet
= OEM_CHARSET
;
3295 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
3296 lstrcpyA(lf
.lfFaceName
, "Terminal");
3297 hfont
= CreateFontIndirectA(&lf
);
3298 old_hfont
= SelectObject(hdc
, hfont
);
3299 charset
= GetTextCharset(hdc
);
3301 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
3302 hfont
= SelectObject(hdc
, old_hfont
);
3303 GetObjectA(hfont
, sizeof(clf
), &clf
);
3304 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
3305 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
3306 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
3307 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
3308 DeleteObject(hfont
);
3312 static void test_GetGlyphOutline(void)
3315 GLYPHMETRICS gm
, gm2
;
3317 HFONT hfont
, old_hfont
;
3326 {ANSI_CHARSET
, 0x30, 0x30},
3327 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
3328 {HANGEUL_CHARSET
, 0x8141, 0xac02},
3329 {JOHAB_CHARSET
, 0x8446, 0x3135},
3330 {GB2312_CHARSET
, 0x8141, 0x4e04},
3331 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
3335 if (!is_truetype_font_installed("Tahoma"))
3337 skip("Tahoma is not installed\n");
3341 hdc
= CreateCompatibleDC(0);
3342 memset(&lf
, 0, sizeof(lf
));
3344 lstrcpyA(lf
.lfFaceName
, "Tahoma");
3345 SetLastError(0xdeadbeef);
3346 hfont
= CreateFontIndirectA(&lf
);
3347 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
3348 old_hfont
= SelectObject(hdc
, hfont
);
3350 memset(&gm
, 0, sizeof(gm
));
3351 SetLastError(0xdeadbeef);
3352 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3353 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3355 memset(&gm
, 0, sizeof(gm
));
3356 SetLastError(0xdeadbeef);
3357 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3358 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
3359 ok(GetLastError() == 0xdeadbeef ||
3360 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
3361 "expected 0xdeadbeef, got %u\n", GetLastError());
3363 memset(&gm
, 0, sizeof(gm
));
3364 SetLastError(0xdeadbeef);
3365 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3366 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3367 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
3369 memset(&gm
, 0, sizeof(gm
));
3370 SetLastError(0xdeadbeef);
3371 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3372 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3374 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
3375 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3378 /* test for needed buffer size request on space char */
3379 memset(&gm
, 0, sizeof(gm
));
3380 SetLastError(0xdeadbeef);
3381 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3382 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3383 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3385 /* requesting buffer size for space char + error */
3386 memset(&gm
, 0, sizeof(gm
));
3387 SetLastError(0xdeadbeef);
3388 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3389 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3391 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3392 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3395 SelectObject(hdc
, old_hfont
);
3396 DeleteObject(hfont
);
3398 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
3400 lf
.lfFaceName
[0] = '\0';
3401 lf
.lfCharSet
= c
[i
].cs
;
3402 lf
.lfPitchAndFamily
= 0;
3403 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
3405 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
3409 old_hfont
= SelectObject(hdc
, hfont
);
3411 /* expected to ignore superfluous bytes (sigle-byte character) */
3412 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3413 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3414 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3416 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3417 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3418 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3420 /* expected to ignore superfluous bytes (double-byte character) */
3421 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3422 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3423 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3424 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3426 /* expected to match wide-char version results */
3427 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3428 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3430 hfont
= SelectObject(hdc
, old_hfont
);
3431 DeleteObject(hfont
);
3437 /* bug #9995: there is a limit to the character width that can be specified */
3438 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3444 int ave_width
, height
, width
, ratio
, scale
;
3446 if (!is_truetype_font_installed( fontname
)) {
3447 skip("%s is not installed\n", fontname
);
3450 hdc
= CreateCompatibleDC(0);
3451 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3452 /* select width = 0 */
3453 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3454 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3455 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3457 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3458 of
= SelectObject( hdc
, hf
);
3459 ret
= GetTextMetricsA( hdc
, &tm
);
3460 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3461 height
= tm
.tmHeight
;
3462 ave_width
= tm
.tmAveCharWidth
;
3463 SelectObject( hdc
, of
);
3466 trace("height %d, ave width %d\n", height
, ave_width
);
3468 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3470 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3471 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3472 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3473 ok(hf
!= 0, "CreateFont failed\n");
3474 of
= SelectObject(hdc
, hf
);
3475 ret
= GetTextMetrics(hdc
, &tm
);
3476 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3477 SelectObject(hdc
, of
);
3480 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3486 ratio
= width
/ height
;
3487 scale
= width
/ ave_width
;
3489 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3490 width
, height
, ratio
, width
, ave_width
, scale
);
3492 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3495 static void test_CreateFontIndirect(void)
3497 LOGFONTA lf
, getobj_lf
;
3500 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3502 memset(&lf
, 0, sizeof(lf
));
3503 lf
.lfCharSet
= ANSI_CHARSET
;
3504 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3507 lf
.lfQuality
= DEFAULT_QUALITY
;
3508 lf
.lfItalic
= FALSE
;
3509 lf
.lfWeight
= FW_DONTCARE
;
3511 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3513 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3514 hfont
= CreateFontIndirectA(&lf
);
3515 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3516 SetLastError(0xdeadbeef);
3517 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3518 ok(ret
, "GetObject failed: %d\n", GetLastError());
3519 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3520 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3521 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3522 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3523 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3524 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3525 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3526 DeleteObject(hfont
);
3530 static void test_CreateFontIndirectEx(void)
3532 ENUMLOGFONTEXDVA lfex
;
3535 if (!pCreateFontIndirectExA
)
3537 win_skip("CreateFontIndirectExA is not available\n");
3541 if (!is_truetype_font_installed("Arial"))
3543 skip("Arial is not installed\n");
3547 SetLastError(0xdeadbeef);
3548 hfont
= pCreateFontIndirectExA(NULL
);
3549 ok(hfont
== NULL
, "got %p\n", hfont
);
3550 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3552 memset(&lfex
, 0, sizeof(lfex
));
3553 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3554 hfont
= pCreateFontIndirectExA(&lfex
);
3555 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3557 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3558 DeleteObject(hfont
);
3561 static void free_font(void *font
)
3563 UnmapViewOfFile(font
);
3566 static void *load_font(const char *font_name
, DWORD
*font_size
)
3568 char file_name
[MAX_PATH
];
3569 HANDLE file
, mapping
;
3572 if (!GetWindowsDirectory(file_name
, sizeof(file_name
))) return NULL
;
3573 strcat(file_name
, "\\fonts\\");
3574 strcat(file_name
, font_name
);
3576 file
= CreateFile(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3577 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
3579 *font_size
= GetFileSize(file
, NULL
);
3581 mapping
= CreateFileMapping(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
3588 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
3591 CloseHandle(mapping
);
3595 static void test_AddFontMemResource(void)
3598 DWORD font_size
, num_fonts
;
3602 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
3604 win_skip("AddFontMemResourceEx is not available on this platform\n");
3608 font
= load_font("sserife.fon", &font_size
);
3611 skip("Unable to locate and load font sserife.fon\n");
3615 SetLastError(0xdeadbeef);
3616 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
3617 ok(!ret
, "AddFontMemResourceEx should fail\n");
3618 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3619 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3622 SetLastError(0xdeadbeef);
3623 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
3624 ok(!ret
, "AddFontMemResourceEx should fail\n");
3625 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3626 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3629 SetLastError(0xdeadbeef);
3630 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
3631 ok(!ret
, "AddFontMemResourceEx should fail\n");
3632 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3633 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3636 SetLastError(0xdeadbeef);
3637 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
3638 ok(!ret
, "AddFontMemResourceEx should fail\n");
3639 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3640 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3643 SetLastError(0xdeadbeef);
3644 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
3645 ok(!ret
, "AddFontMemResourceEx should fail\n");
3646 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3647 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3650 SetLastError(0xdeadbeef);
3651 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
3652 ok(!ret
, "AddFontMemResourceEx should fail\n");
3653 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3654 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3657 num_fonts
= 0xdeadbeef;
3658 SetLastError(0xdeadbeef);
3659 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
3660 ok(!ret
, "AddFontMemResourceEx should fail\n");
3661 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3662 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3664 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3666 if (0) /* hangs under windows 2000 */
3668 num_fonts
= 0xdeadbeef;
3669 SetLastError(0xdeadbeef);
3670 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
3671 ok(!ret
, "AddFontMemResourceEx should fail\n");
3672 ok(GetLastError() == 0xdeadbeef,
3673 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3675 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3678 num_fonts
= 0xdeadbeef;
3679 SetLastError(0xdeadbeef);
3680 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
3681 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
3682 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3683 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
3687 SetLastError(0xdeadbeef);
3688 bRet
= pRemoveFontMemResourceEx(ret
);
3689 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
3691 /* test invalid pointer to number of loaded fonts */
3692 font
= load_font("sserife.fon", &font_size
);
3693 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
3695 SetLastError(0xdeadbeef);
3696 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
3697 ok(!ret
, "AddFontMemResourceEx should fail\n");
3698 ok(GetLastError() == 0xdeadbeef,
3699 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3702 SetLastError(0xdeadbeef);
3703 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
3704 ok(!ret
, "AddFontMemResourceEx should fail\n");
3705 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3706 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3712 static INT CALLBACK
enum_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3716 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3718 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3720 lf
= (LOGFONT
*)lparam
;
3725 static INT CALLBACK
enum_all_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3730 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3732 lf
= (LOGFONT
*)lparam
;
3733 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
3736 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3743 static void test_EnumFonts(void)
3749 if (!is_truetype_font_installed("Arial"))
3751 skip("Arial is not installed\n");
3755 /* Windows uses localized font face names, so Arial Bold won't be found */
3756 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
3758 skip("User locale is not English, skipping the test\n");
3762 hdc
= CreateCompatibleDC(0);
3764 ret
= EnumFontFamilies(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
3765 ok(!ret
, "font Arial is not enumerated\n");
3766 ret
= strcmp(lf
.lfFaceName
, "Arial");
3767 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3768 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
3770 lstrcpy(lf
.lfFaceName
, "Arial");
3771 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3772 ok(!ret
, "font Arial is not enumerated\n");
3773 ret
= strcmp(lf
.lfFaceName
, "Arial");
3774 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3775 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
3777 ret
= EnumFontFamilies(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
3778 ok(!ret
, "font Arial Bold is not enumerated\n");
3779 ret
= strcmp(lf
.lfFaceName
, "Arial");
3780 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3781 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
3783 lstrcpy(lf
.lfFaceName
, "Arial Bold");
3784 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3785 ok(ret
, "font Arial Bold should not be enumerated\n");
3787 ret
= EnumFontFamilies(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
3788 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
3789 ret
= strcmp(lf
.lfFaceName
, "Arial");
3790 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
3791 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
3793 lstrcpy(lf
.lfFaceName
, "Arial Bold Italic");
3794 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3795 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
3797 ret
= EnumFontFamilies(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
3798 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
3800 lstrcpy(lf
.lfFaceName
, "Arial Italic Bold");
3801 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
3802 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
3807 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
3809 const ENUMLOGFONT
*elf
= (const ENUMLOGFONT
*)lf
;
3810 const char *fullname
= (const char *)lParam
;
3812 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
3817 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
3822 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
3829 static void test_fullname(void)
3831 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3832 char buf
[LF_FULLFACESIZE
];
3838 hdc
= CreateCompatibleDC(0);
3839 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
3841 memset(&lf
, 0, sizeof(lf
));
3842 lf
.lfCharSet
= ANSI_CHARSET
;
3843 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3846 lf
.lfQuality
= DEFAULT_QUALITY
;
3847 lf
.lfItalic
= FALSE
;
3848 lf
.lfWeight
= FW_DONTCARE
;
3850 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
3852 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
3854 skip("%s is not installed\n", TestName
[i
]);
3858 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3859 hfont
= CreateFontIndirectA(&lf
);
3860 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3862 of
= SelectObject(hdc
, hfont
);
3864 ok(get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, buf
, sizeof(buf
)),
3865 "face full name could not be read\n");
3866 ok(!lstrcmpA(buf
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], buf
);
3867 SelectObject(hdc
, of
);
3868 DeleteObject(hfont
);
3873 static BOOL
write_ttf_file(char *tmp_name
)
3875 char tmp_path
[MAX_PATH
];
3882 SetLastError(0xdeadbeef);
3883 rsrc
= FindResource(GetModuleHandle(0), "wine_test.ttf", RT_RCDATA
);
3884 ok(rsrc
!= 0, "FindResource error %d\n", GetLastError());
3885 if (!rsrc
) return FALSE
;
3886 SetLastError(0xdeadbeef);
3887 rsrc_data
= LockResource(LoadResource(GetModuleHandle(0), rsrc
));
3888 ok(rsrc_data
!= 0, "LockResource error %d\n", GetLastError());
3889 if (!rsrc_data
) return FALSE
;
3890 SetLastError(0xdeadbeef);
3891 rsrc_size
= SizeofResource(GetModuleHandle(0), rsrc
);
3892 ok(rsrc_size
!= 0, "SizeofResource error %d\n", GetLastError());
3893 if (!rsrc_size
) return FALSE
;
3895 SetLastError(0xdeadbeef);
3896 ret
= GetTempPath(MAX_PATH
, tmp_path
);
3897 ok(ret
, "GetTempPath() error %d\n", GetLastError());
3898 SetLastError(0xdeadbeef);
3899 ret
= GetTempFileName(tmp_path
, "ttf", 0, tmp_name
);
3900 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
3902 SetLastError(0xdeadbeef);
3903 hfile
= CreateFile(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
3904 ok(hfile
!= INVALID_HANDLE_VALUE
, "CreateFile() error %d\n", GetLastError());
3905 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
3907 SetLastError(0xdeadbeef);
3908 ret
= WriteFile(hfile
, rsrc_data
, rsrc_size
, &rsrc_size
, NULL
);
3909 ok(ret
, "WriteFile() error %d\n", GetLastError());
3915 static void test_CreateScalableFontResource(void)
3917 char ttf_name
[MAX_PATH
];
3918 char tmp_path
[MAX_PATH
];
3919 char fot_name
[MAX_PATH
];
3923 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
3925 win_skip("AddFontResourceExA is not available on this platform\n");
3929 if (!write_ttf_file(ttf_name
))
3931 skip("Failed to create ttf file for testing\n");
3935 trace("created %s\n", ttf_name
);
3937 ret
= is_truetype_font_installed("wine_test");
3938 ok(!ret
, "font wine_test should not be enumerated\n");
3940 ret
= GetTempPath(MAX_PATH
, tmp_path
);
3941 ok(ret
, "GetTempPath() error %d\n", GetLastError());
3942 ret
= GetTempFileName(tmp_path
, "fot", 0, fot_name
);
3943 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
3945 ret
= GetFileAttributes(fot_name
);
3946 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
3948 SetLastError(0xdeadbeef);
3949 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
3950 ok(!ret
, "CreateScalableFontResource() should fail\n");
3951 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
3953 SetLastError(0xdeadbeef);
3954 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, "");
3955 ok(!ret
, "CreateScalableFontResource() should fail\n");
3956 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
3958 file_part
= strrchr(ttf_name
, '\\');
3959 SetLastError(0xdeadbeef);
3960 ret
= CreateScalableFontResource(0, fot_name
, file_part
, tmp_path
);
3961 ok(!ret
, "CreateScalableFontResource() should fail\n");
3962 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
3964 SetLastError(0xdeadbeef);
3965 ret
= CreateScalableFontResource(0, fot_name
, "random file name", tmp_path
);
3966 ok(!ret
, "CreateScalableFontResource() should fail\n");
3968 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
3970 SetLastError(0xdeadbeef);
3971 ret
= CreateScalableFontResource(0, fot_name
, NULL
, ttf_name
);
3972 ok(!ret
, "CreateScalableFontResource() should fail\n");
3974 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
3976 ret
= DeleteFile(fot_name
);
3977 ok(ret
, "DeleteFile() error %d\n", GetLastError());
3979 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
3981 ok(!ret
, "RemoveFontResourceEx() should fail\n");
3983 /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3986 /* test public font resource */
3987 SetLastError(0xdeadbeef);
3988 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
3989 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
3991 ret
= is_truetype_font_installed("wine_test");
3992 ok(!ret
, "font wine_test should not be enumerated\n");
3994 SetLastError(0xdeadbeef);
3995 ret
= pAddFontResourceExA(fot_name
, 0, 0);
3996 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
3998 ret
= is_truetype_font_installed("wine_test");
3999 ok(ret
, "font wine_test should be enumerated\n");
4001 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4002 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
4004 SetLastError(0xdeadbeef);
4005 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4007 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4009 ret
= is_truetype_font_installed("wine_test");
4011 ok(!ret
, "font wine_test should not be enumerated\n");
4013 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4016 /* remove once RemoveFontResource is implemented */
4017 DeleteFile(fot_name
);
4018 DeleteFile(ttf_name
);
4022 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4023 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4025 DeleteFile(fot_name
);
4027 /* test hidden font resource */
4028 SetLastError(0xdeadbeef);
4029 ret
= CreateScalableFontResource(1, fot_name
, ttf_name
, NULL
);
4030 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
4032 ret
= is_truetype_font_installed("wine_test");
4033 ok(!ret
, "font wine_test should not be enumerated\n");
4035 SetLastError(0xdeadbeef);
4036 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4037 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4039 ret
= is_truetype_font_installed("wine_test");
4040 ok(!ret
, "font wine_test should not be enumerated\n");
4042 /* XP allows removing a private font added with 0 flags */
4043 SetLastError(0xdeadbeef);
4044 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4045 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4047 ret
= is_truetype_font_installed("wine_test");
4048 ok(!ret
, "font wine_test should not be enumerated\n");
4050 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4051 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4053 DeleteFile(fot_name
);
4054 DeleteFile(ttf_name
);
4063 test_outline_font();
4064 test_bitmap_font_metrics();
4065 test_GdiGetCharDimensions();
4066 test_GetCharABCWidths();
4067 test_text_extents();
4068 test_GetGlyphIndices();
4069 test_GetKerningPairs();
4070 test_GetOutlineTextMetrics();
4071 test_SetTextJustification();
4072 test_font_charset();
4073 test_GetFontUnicodeRanges();
4074 test_nonexistent_font();
4076 test_height_selection();
4077 test_AddFontMemResource();
4080 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4081 * I'd like to avoid them in this test.
4083 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
4084 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
4085 if (is_truetype_font_installed("Arial Black") &&
4086 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4088 test_EnumFontFamilies("", ANSI_CHARSET
);
4089 test_EnumFontFamilies("", SYMBOL_CHARSET
);
4090 test_EnumFontFamilies("", DEFAULT_CHARSET
);
4093 skip("Arial Black or Symbol/Wingdings is not installed\n");
4094 test_EnumFontFamiliesEx_default_charset();
4095 test_GetTextMetrics();
4096 test_GdiRealizationInfo();
4098 test_GetGlyphOutline();
4099 test_GetTextMetrics2("Tahoma", -11);
4100 test_GetTextMetrics2("Tahoma", -55);
4101 test_GetTextMetrics2("Tahoma", -110);
4102 test_GetTextMetrics2("Arial", -11);
4103 test_GetTextMetrics2("Arial", -55);
4104 test_GetTextMetrics2("Arial", -110);
4105 test_CreateFontIndirect();
4106 test_CreateFontIndirectEx();
4110 /* CreateScalableFontResource should be last test until RemoveFontResource
4111 * is properly implemented.
4113 test_CreateScalableFontResource();