2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 #define near_match(a, b) (abs((a) - (b)) <= 6)
34 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
36 LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
37 BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
38 BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
39 DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
40 DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
41 DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
42 BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
44 static HMODULE hgdi32
= 0;
46 static void init(void)
48 hgdi32
= GetModuleHandleA("gdi32.dll");
50 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
51 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
52 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
53 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
54 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
55 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
56 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
59 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
61 if (type
!= TRUETYPE_FONTTYPE
) return 1;
66 static BOOL
is_truetype_font_installed(const char *name
)
71 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
78 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
83 static BOOL
is_font_installed(const char *name
)
88 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
95 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
103 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
104 /* NT4 tries to be clever and only returns the minimum length */
105 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
107 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
108 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
109 ok(!memcmp(&lf
, &lf
, FIELD_OFFSET(LOGFONTA
, lfFaceName
)), "%s: fonts don't match\n", test
);
110 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
),
111 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
114 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
116 HFONT hfont
= CreateFontIndirectA(lf
);
117 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
119 check_font(test
, lf
, hfont
);
123 static void test_logfont(void)
128 memset(&lf
, 0, sizeof lf
);
130 lf
.lfCharSet
= ANSI_CHARSET
;
131 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
132 lf
.lfWeight
= FW_DONTCARE
;
135 lf
.lfQuality
= DEFAULT_QUALITY
;
137 lstrcpyA(lf
.lfFaceName
, "Arial");
138 hfont
= create_font("Arial", &lf
);
141 memset(&lf
, 'A', sizeof(lf
));
142 hfont
= CreateFontIndirectA(&lf
);
143 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
145 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
146 check_font("AAA...", &lf
, hfont
);
150 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
152 if (type
& RASTER_FONTTYPE
)
154 LOGFONT
*lf
= (LOGFONT
*)lParam
;
156 return 0; /* stop enumeration */
159 return 1; /* continue enumeration */
162 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
164 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
165 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
166 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
167 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
168 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
169 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
170 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
171 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
172 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
173 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
174 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
175 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
176 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
177 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
178 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
179 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
180 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
181 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
182 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
183 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
186 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
187 LONG lfWidth
, const char *test_str
,
188 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
189 const SIZE
*size_orig
, INT width_of_A_orig
,
190 INT scale_x
, INT scale_y
)
194 OUTLINETEXTMETRIC otm
;
197 INT width_of_A
, cx
, cy
;
203 GetObjectA(hfont
, sizeof(lf
), &lf
);
205 old_hfont
= SelectObject(hdc
, hfont
);
207 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
209 otm
.otmSize
= sizeof(otm
) / 2;
210 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
211 ok(ret
== sizeof(otm
)/2 /* XP */ ||
212 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
214 memset(&otm
, 0x1, sizeof(otm
));
215 otm
.otmSize
= sizeof(otm
);
216 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
217 ok(ret
== sizeof(otm
) /* XP */ ||
218 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
220 memset(&tm
, 0x2, sizeof(tm
));
221 ret
= GetTextMetricsA(hdc
, &tm
);
222 ok(ret
, "GetTextMetricsA failed\n");
223 /* the structure size is aligned */
224 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
226 ok(0, "tm != otm\n");
227 compare_tm(&tm
, &otm
.otmTextMetrics
);
230 tm
= otm
.otmTextMetrics
;
231 if (0) /* these metrics are scaled too, but with rounding errors */
233 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
234 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
236 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
237 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
238 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
239 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
240 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
241 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
245 ret
= GetTextMetricsA(hdc
, &tm
);
246 ok(ret
, "GetTextMetricsA failed\n");
249 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
250 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
251 ok(cx
== scale_x
&& cy
== scale_y
, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
252 scale_x
, scale_y
, cx
, cy
);
253 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
254 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
255 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
256 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
257 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
259 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
263 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
266 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
268 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
270 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
271 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
273 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
275 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
);
277 SelectObject(hdc
, old_hfont
);
280 /* Test how GDI scales bitmap font metrics */
281 static void test_bitmap_font(void)
283 static const char test_str
[11] = "Test String";
286 HFONT hfont
, old_hfont
;
289 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
293 /* "System" has only 1 pixel size defined, otherwise the test breaks */
294 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
298 trace("no bitmap fonts were found, skipping the test\n");
302 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
304 height_orig
= bitmap_lf
.lfHeight
;
305 lfWidth
= bitmap_lf
.lfWidth
;
307 hfont
= create_font("bitmap", &bitmap_lf
);
308 old_hfont
= SelectObject(hdc
, hfont
);
309 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
310 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
311 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
312 SelectObject(hdc
, old_hfont
);
315 bitmap_lf
.lfHeight
= 0;
316 bitmap_lf
.lfWidth
= 4;
317 hfont
= create_font("bitmap", &bitmap_lf
);
318 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
321 bitmap_lf
.lfHeight
= height_orig
;
322 bitmap_lf
.lfWidth
= lfWidth
;
324 /* test fractional scaling */
325 for (i
= 1; i
<= height_orig
* 3; i
++)
329 bitmap_lf
.lfHeight
= i
;
330 hfont
= create_font("fractional", &bitmap_lf
);
331 scale
= (i
+ height_orig
- 1) / height_orig
;
332 nearest_height
= scale
* height_orig
;
333 /* XP allows not more than 10% deviation */
334 if (scale
> 1 && nearest_height
- i
> nearest_height
/ 10) scale
--;
335 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
339 /* test integer scaling 3x2 */
340 bitmap_lf
.lfHeight
= height_orig
* 2;
341 bitmap_lf
.lfWidth
*= 3;
342 hfont
= create_font("3x2", &bitmap_lf
);
343 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
346 /* test integer scaling 3x3 */
347 bitmap_lf
.lfHeight
= height_orig
* 3;
348 bitmap_lf
.lfWidth
= 0;
349 hfont
= create_font("3x3", &bitmap_lf
);
350 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
356 /* Test how GDI scales outline font metrics */
357 static void test_outline_font(void)
359 static const char test_str
[11] = "Test String";
362 HFONT hfont
, old_hfont
;
363 OUTLINETEXTMETRICA otm
;
365 INT width_orig
, height_orig
, lfWidth
;
368 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
369 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
373 if (!is_truetype_font_installed("Arial"))
375 skip("Arial is not installed\n");
379 hdc
= CreateCompatibleDC(0);
381 memset(&lf
, 0, sizeof(lf
));
382 strcpy(lf
.lfFaceName
, "Arial");
384 hfont
= create_font("outline", &lf
);
385 old_hfont
= SelectObject(hdc
, hfont
);
386 otm
.otmSize
= sizeof(otm
);
387 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
388 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
389 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
390 SelectObject(hdc
, old_hfont
);
392 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
395 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
396 lf
.lfHeight
= otm
.otmEMSquare
;
397 lf
.lfHeight
= -lf
.lfHeight
;
398 hfont
= create_font("outline", &lf
);
399 old_hfont
= SelectObject(hdc
, hfont
);
400 otm
.otmSize
= sizeof(otm
);
401 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
402 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
403 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
404 SelectObject(hdc
, old_hfont
);
407 height_orig
= otm
.otmTextMetrics
.tmHeight
;
408 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
410 /* test integer scaling 3x2 */
411 lf
.lfHeight
= height_orig
* 2;
412 lf
.lfWidth
= lfWidth
* 3;
413 hfont
= create_font("3x2", &lf
);
414 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
417 /* test integer scaling 3x3 */
418 lf
.lfHeight
= height_orig
* 3;
419 lf
.lfWidth
= lfWidth
* 3;
420 hfont
= create_font("3x3", &lf
);
421 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
424 /* test integer scaling 1x1 */
425 lf
.lfHeight
= height_orig
* 1;
426 lf
.lfWidth
= lfWidth
* 1;
427 hfont
= create_font("1x1", &lf
);
428 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
431 /* test integer scaling 1x1 */
432 lf
.lfHeight
= height_orig
;
434 hfont
= create_font("1x1", &lf
);
435 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
437 old_hfont
= SelectObject(hdc
, hfont
);
438 /* with an identity matrix */
439 memset(&gm
, 0, sizeof(gm
));
440 SetLastError(0xdeadbeef);
441 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
442 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
443 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
444 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
445 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
446 /* with a custom matrix */
447 memset(&gm
, 0, sizeof(gm
));
448 SetLastError(0xdeadbeef);
449 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
450 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
451 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
452 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
453 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
454 SelectObject(hdc
, old_hfont
);
456 SetMapMode(hdc
, MM_ANISOTROPIC
);
457 /* test restrictions of compatibility mode GM_COMPATIBLE */
458 /* part 1: rescaling only X should not change font scaling on screen.
459 So compressing the X axis by 2 is not done, and this
460 appears as X scaling of 2 that no one requested. */
461 SetWindowExtEx(hdc
, 100, 100, NULL
);
462 SetViewportExtEx(hdc
, 50, 100, NULL
);
463 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
465 /* part 2: rescaling only Y should change font scaling.
466 As also X is scaled by a factor of 2, but this is not
467 requested by the DC transformation, we get a scaling factor
468 of 2 in the X coordinate. */
469 SetViewportExtEx(hdc
, 100, 200, NULL
);
470 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
472 /* restore scaling */
473 SetMapMode(hdc
, MM_TEXT
);
475 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
479 skip("GM_ADVANCED is not supported on this platform\n");
490 SetLastError(0xdeadbeef);
491 ret
= SetWorldTransform(hdc
, &xform
);
492 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
494 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
496 old_hfont
= SelectObject(hdc
, hfont
);
497 /* with an identity matrix */
498 memset(&gm
, 0, sizeof(gm
));
499 SetLastError(0xdeadbeef);
500 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
501 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
502 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
503 pt
.x
= width_orig
; pt
.y
= 0;
505 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
506 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
507 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
508 /* with a custom matrix */
509 memset(&gm
, 0, sizeof(gm
));
510 SetLastError(0xdeadbeef);
511 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
512 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
513 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
514 pt
.x
= width_orig
; pt
.y
= 0;
516 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
517 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
518 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
519 SelectObject(hdc
, old_hfont
);
521 SetLastError(0xdeadbeef);
522 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
523 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
525 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
527 old_hfont
= SelectObject(hdc
, hfont
);
528 /* with an identity matrix */
529 memset(&gm
, 0, sizeof(gm
));
530 SetLastError(0xdeadbeef);
531 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
532 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
533 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
534 pt
.x
= width_orig
; pt
.y
= 0;
536 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
537 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
538 /* with a custom matrix */
539 memset(&gm
, 0, sizeof(gm
));
540 SetLastError(0xdeadbeef);
541 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
542 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
543 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
544 pt
.x
= width_orig
; pt
.y
= 0;
546 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
547 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
548 SelectObject(hdc
, old_hfont
);
550 SetLastError(0xdeadbeef);
551 ret
= SetMapMode(hdc
, MM_TEXT
);
552 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
554 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
556 old_hfont
= SelectObject(hdc
, hfont
);
557 /* with an identity matrix */
558 memset(&gm
, 0, sizeof(gm
));
559 SetLastError(0xdeadbeef);
560 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
561 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
562 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
563 pt
.x
= width_orig
; pt
.y
= 0;
565 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
566 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
567 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
568 /* with a custom matrix */
569 memset(&gm
, 0, sizeof(gm
));
570 SetLastError(0xdeadbeef);
571 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
572 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
573 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
574 pt
.x
= width_orig
; pt
.y
= 0;
576 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
577 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
578 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
579 SelectObject(hdc
, old_hfont
);
585 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
587 LOGFONT
*lf
= (LOGFONT
*)lParam
;
589 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
592 return 0; /* stop enumeration */
594 return 1; /* continue enumeration */
597 static void test_bitmap_font_metrics(void)
599 static const struct font_data
601 const char face_name
[LF_FACESIZE
];
602 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
603 int ave_char_width
, max_char_width
;
607 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
608 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
609 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1
| FS_CYRILLIC
},
610 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2
},
611 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1
},
612 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2
},
613 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC
},
614 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1
},
615 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2
},
616 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC
},
617 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
618 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1
| FS_LATIN2
},
619 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC
},
620 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
621 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1
},
622 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2
| FS_CYRILLIC
},
623 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1
| FS_LATIN2
},
624 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC
},
625 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1
| FS_LATIN2
},
626 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC
},
627 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1
},
628 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2
},
629 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC
},
630 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1
},
631 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2
},
632 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC
},
633 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1
| FS_LATIN2
},
634 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC
},
635 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
636 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
637 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
638 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1
},
639 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2
| FS_CYRILLIC
},
641 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
642 * require a new system.sfd for that font
644 { "System", FW_BOLD
, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN
},
645 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1
},
646 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2
| FS_CYRILLIC
},
647 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN
},
648 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1
},
649 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2
| FS_CYRILLIC
},
650 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN
},
651 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1
},
652 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2
| FS_CYRILLIC
},
653 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN
},
654 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1
},
655 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2
| FS_CYRILLIC
},
656 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN
},
657 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1
| FS_LATIN2
},
658 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC
},
659 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN
},
660 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
661 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN
},
662 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1
| FS_LATIN2
},
663 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC
},
664 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN
}
666 /* FIXME: add "Terminal" */
670 HFONT hfont
, old_hfont
;
674 hdc
= CreateCompatibleDC(0);
677 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
681 memset(&lf
, 0, sizeof(lf
));
683 lf
.lfHeight
= fd
[i
].height
;
684 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
686 for(bit
= 0; bit
< 32; bit
++)
693 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
694 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
696 lf
.lfCharSet
= csi
.ciCharset
;
697 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
700 trace("found font %s, height %d charset %x\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
702 hfont
= create_font(lf
.lfFaceName
, &lf
);
703 old_hfont
= SelectObject(hdc
, hfont
);
704 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %d\n", GetLastError());
706 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
);
707 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
);
708 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
);
709 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
);
710 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
);
711 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
);
712 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
);
714 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
715 that make the max width bigger */
716 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
717 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
);
719 SelectObject(hdc
, old_hfont
);
727 static void test_GdiGetCharDimensions(void)
733 LONG avgwidth
, height
;
734 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
736 if (!pGdiGetCharDimensions
)
738 skip("GdiGetCharDimensions not available on this platform\n");
742 hdc
= CreateCompatibleDC(NULL
);
744 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
745 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
747 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
748 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
749 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
751 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
752 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
754 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
755 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
758 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
759 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
760 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
765 static void test_GetCharABCWidths(void)
767 static const WCHAR str
[] = {'a',0};
776 if (!pGetCharABCWidthsW
|| !pGetCharABCWidthsI
)
778 skip("GetCharABCWidthsW/I not available on this platform\n");
782 memset(&lf
, 0, sizeof(lf
));
783 strcpy(lf
.lfFaceName
, "System");
786 hfont
= CreateFontIndirectA(&lf
);
788 hfont
= SelectObject(hdc
, hfont
);
790 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
791 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
793 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
794 ok(!ret
, "GetCharABCWidthsI should have failed\n");
796 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
797 ok(!ret
, "GetCharABCWidthsI should have failed\n");
799 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
800 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
802 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
803 ok(!ret
, "GetCharABCWidthsW should have failed\n");
805 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
806 ok(!ret
, "GetCharABCWidthsW should have failed\n");
808 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
809 ok(!ret
, "GetCharABCWidthsW should have failed\n");
811 hfont
= SelectObject(hdc
, hfont
);
813 ReleaseDC(NULL
, hdc
);
816 static void test_text_extents(void)
818 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
820 INT i
, len
, fit1
, fit2
;
828 memset(&lf
, 0, sizeof(lf
));
829 strcpy(lf
.lfFaceName
, "Arial");
832 hfont
= CreateFontIndirectA(&lf
);
834 hfont
= SelectObject(hdc
, hfont
);
835 GetTextMetricsA(hdc
, &tm
);
836 GetTextExtentPointA(hdc
, "o", 1, &sz
);
837 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
839 SetLastError(0xdeadbeef);
840 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
841 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
843 skip("Skipping remainder of text extents test on a Win9x platform\n");
844 hfont
= SelectObject(hdc
, hfont
);
851 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
852 extents
[0] = 1; /* So that the increasing sequence test will fail
853 if the extents array is untouched. */
854 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
855 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
857 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
858 /* Because of the '\n' in the string GetTextExtentExPoint and
859 GetTextExtentPoint return different widths under Win2k, but
860 under WinXP they return the same width. So we don't test that
863 for (i
= 1; i
< len
; ++i
)
864 ok(extents
[i
-1] <= extents
[i
],
865 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
867 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
868 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
869 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
870 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
871 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
872 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
873 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
874 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
875 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
876 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
877 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
878 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
879 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
880 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
881 HeapFree(GetProcessHeap(), 0, extents
);
883 hfont
= SelectObject(hdc
, hfont
);
885 ReleaseDC(NULL
, hdc
);
888 static void test_GetGlyphIndices(void)
895 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
896 WORD glyphs
[(sizeof(testtext
)/2)-1];
900 if (!pGetGlyphIndicesW
) {
901 skip("GetGlyphIndicesW not available on platform\n");
907 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
908 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
909 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
910 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
911 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
913 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
914 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
915 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
916 textm
.tmDefaultChar
, glyphs
[4]);
918 if(!is_font_installed("Tahoma"))
920 skip("Tahoma is not installed so skipping this test\n");
923 memset(&lf
, 0, sizeof(lf
));
924 strcpy(lf
.lfFaceName
, "Tahoma");
927 hfont
= CreateFontIndirectA(&lf
);
928 hOldFont
= SelectObject(hdc
, hfont
);
929 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
930 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
931 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
932 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
933 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
935 testtext
[0] = textm
.tmDefaultChar
;
936 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
937 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
938 todo_wine
ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
939 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
940 DeleteObject(SelectObject(hdc
, hOldFont
));
943 static void test_GetKerningPairs(void)
945 static const struct kerning_data
947 const char face_name
[LF_FACESIZE
];
949 /* some interesting fields from OUTLINETEXTMETRIC */
950 LONG tmHeight
, tmAscent
, tmDescent
;
955 UINT otmsCapEmHeight
;
960 UINT otmusMinimumPPEM
;
961 /* small subset of kerning pairs to test */
962 DWORD total_kern_pairs
;
963 const KERNINGPAIR kern_pair
[26];
966 {"Arial", 12, 12, 9, 3,
967 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
970 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
971 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
972 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
973 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
974 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
975 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
976 {933,970,+1},{933,972,-1}
979 {"Arial", -34, 39, 32, 7,
980 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
983 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
984 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
985 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
986 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
987 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
988 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
989 {933,970,+2},{933,972,-3}
992 { "Arial", 120, 120, 97, 23,
993 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
996 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
997 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
998 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
999 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1000 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1001 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1002 {933,970,+6},{933,972,-10}
1005 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1006 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1007 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1010 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1011 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1012 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1013 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1014 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1015 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1016 {933,970,+54},{933,972,-83}
1022 HFONT hfont
, hfont_old
;
1023 KERNINGPAIR
*kern_pair
;
1025 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1029 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1030 * which may render this test unusable, so we're trying to avoid that.
1032 SetLastError(0xdeadbeef);
1033 GetKerningPairsW(hdc
, 0, NULL
);
1034 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1036 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1041 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1043 OUTLINETEXTMETRICW otm
;
1045 if (!is_font_installed(kd
[i
].face_name
))
1047 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1051 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1053 memset(&lf
, 0, sizeof(lf
));
1054 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1055 lf
.lfHeight
= kd
[i
].height
;
1056 hfont
= CreateFontIndirect(&lf
);
1059 hfont_old
= SelectObject(hdc
, hfont
);
1061 SetLastError(0xdeadbeef);
1062 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1063 ok(GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
) == sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1065 ok(kd
[i
].tmHeight
== otm
.otmTextMetrics
.tmHeight
, "expected %d, got %d\n",
1066 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1067 ok(kd
[i
].tmAscent
== otm
.otmTextMetrics
.tmAscent
, "expected %d, got %d\n",
1068 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1069 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1070 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1072 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1073 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1074 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1075 kd
[i
].otmAscent
, otm
.otmAscent
);
1076 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1077 kd
[i
].otmDescent
, otm
.otmDescent
);
1078 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1079 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1080 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1081 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1083 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1084 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1085 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1086 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1087 ok(kd
[i
].otmMacAscent
== otm
.otmMacAscent
, "expected %d, got %d\n",
1088 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1089 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1090 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1091 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1092 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1093 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1096 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1097 trace("total_kern_pairs %u\n", total_kern_pairs
);
1098 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1100 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1101 SetLastError(0xdeadbeef);
1102 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1103 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1104 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1105 ok(ret
== 0, "got %lu, expected 0\n", ret
);
1108 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1109 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1111 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1112 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1114 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1115 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1119 for (n
= 0; n
< ret
; n
++)
1123 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1124 trace("{'%c','%c',%d},\n",
1125 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1127 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1129 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1130 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1132 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1133 "pair %d:%d got %d, expected %d\n",
1134 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1135 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1141 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1142 matches
, kd
[i
].total_kern_pairs
);
1144 HeapFree(GetProcessHeap(), 0, kern_pair
);
1146 SelectObject(hdc
, hfont_old
);
1147 DeleteObject(hfont
);
1153 static void test_GetOutlineTextMetrics(void)
1155 OUTLINETEXTMETRIC
*otm
;
1157 HFONT hfont
, hfont_old
;
1159 DWORD ret
, otm_size
;
1161 if (!is_font_installed("Arial"))
1163 skip("Arial is not installed\n");
1169 memset(&lf
, 0, sizeof(lf
));
1170 strcpy(lf
.lfFaceName
, "Arial");
1172 lf
.lfWeight
= FW_NORMAL
;
1173 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1174 lf
.lfQuality
= PROOF_QUALITY
;
1175 hfont
= CreateFontIndirect(&lf
);
1178 hfont_old
= SelectObject(hdc
, hfont
);
1179 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1180 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1182 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1184 memset(otm
, 0xAA, otm_size
);
1185 SetLastError(0xdeadbeef);
1186 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1187 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1188 ok(ret
== 1 /* Win9x */ ||
1189 ret
== otm
->otmSize
/* XP*/,
1190 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1191 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1193 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1194 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1195 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1196 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1199 memset(otm
, 0xAA, otm_size
);
1200 SetLastError(0xdeadbeef);
1201 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1202 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1203 ok(ret
== 1 /* Win9x */ ||
1204 ret
== otm
->otmSize
/* XP*/,
1205 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1206 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1208 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1209 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1210 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1211 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1214 /* ask about truncated data */
1215 memset(otm
, 0xAA, otm_size
);
1216 SetLastError(0xdeadbeef);
1217 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1218 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1219 ok(ret
== 1 /* Win9x */ ||
1220 ret
== otm
->otmSize
/* XP*/,
1221 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1222 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1224 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1225 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1226 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1228 ok(otm
->otmpFullName
== (LPSTR
)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm
->otmpFullName
);
1230 HeapFree(GetProcessHeap(), 0, otm
);
1232 SelectObject(hdc
, hfont_old
);
1233 DeleteObject(hfont
);
1238 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1242 outputWidth
= 0, /* to test TabbedTextOut() */
1243 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
1244 areaWidth
= clientArea
->right
- clientArea
->left
,
1246 BOOL lastExtent
= FALSE
;
1247 PSTR pFirstChar
, pLastChar
;
1253 int GetTextExtentExPointWWidth
;
1254 int TabbedTextOutWidth
;
1257 GetTextMetricsA(hdc
, &tm
);
1258 y
= clientArea
->top
;
1261 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1267 /* if not at the end of the string, ... */
1268 if (*str
== '\0') break;
1269 /* ... add the next word to the current extent */
1270 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1272 SetTextJustification(hdc
, 0, 0);
1273 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1274 } while ((int) size
.cx
< areaWidth
);
1276 /* ignore trailing break chars */
1278 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1284 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1286 SetTextJustification(hdc
, 0, 0);
1287 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1289 /* do not justify the last extent */
1290 if (*str
!= '\0' && breakCount
> 0)
1292 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1293 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1294 justifiedWidth
= size
.cx
;
1296 else lastExtent
= TRUE
;
1298 x
= clientArea
->left
;
1300 outputWidth
= LOWORD(TabbedTextOut(
1301 hdc
, x
, y
, pFirstChar
, pLastChar
- pFirstChar
,
1303 /* catch errors and report them */
1304 if (!lastExtent
&& ((outputWidth
!= areaWidth
) || (justifiedWidth
!= areaWidth
)))
1306 memset(error
[nErrors
].extent
, 0, 100);
1307 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
1308 error
[nErrors
].TabbedTextOutWidth
= outputWidth
;
1309 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
1315 } while (*str
&& y
< clientArea
->bottom
);
1317 for (e
= 0; e
< nErrors
; e
++)
1319 ok(error
[e
].TabbedTextOutWidth
== areaWidth
,
1320 "The output text (\"%s\") width should be %d, not %d.\n",
1321 error
[e
].extent
, areaWidth
, error
[e
].TabbedTextOutWidth
);
1322 /* The width returned by GetTextExtentPoint32() is exactly the same
1323 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1324 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1325 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1326 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1330 static void test_SetTextJustification(void)
1337 static char testText
[] =
1338 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1339 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1340 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1341 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1342 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1343 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1344 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1346 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1347 GetClientRect( hwnd
, &clientArea
);
1348 hdc
= GetDC( hwnd
);
1350 memset(&lf
, 0, sizeof lf
);
1351 lf
.lfCharSet
= ANSI_CHARSET
;
1352 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1353 lf
.lfWeight
= FW_DONTCARE
;
1355 lf
.lfQuality
= DEFAULT_QUALITY
;
1356 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1357 hfont
= create_font("Times New Roman", &lf
);
1358 SelectObject(hdc
, hfont
);
1360 testJustification(hdc
, testText
, &clientArea
);
1362 DeleteObject(hfont
);
1363 ReleaseDC(hwnd
, hdc
);
1364 DestroyWindow(hwnd
);
1367 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1371 HFONT hfont
, hfont_old
;
1378 assert(count
<= 128);
1380 memset(&lf
, 0, sizeof(lf
));
1382 lf
.lfCharSet
= charset
;
1384 lstrcpyA(lf
.lfFaceName
, "Arial");
1385 SetLastError(0xdeadbeef);
1386 hfont
= CreateFontIndirectA(&lf
);
1387 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1390 hfont_old
= SelectObject(hdc
, hfont
);
1392 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1393 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1395 SetLastError(0xdeadbeef);
1396 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1397 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1399 if (charset
== SYMBOL_CHARSET
)
1401 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1402 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1406 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1407 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1410 if (!TranslateCharsetInfo((DWORD
*)cs
, &csi
, TCI_SRCCHARSET
))
1412 trace("Can't find codepage for charset %d\n", cs
);
1416 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1421 WCHAR unicode_buf
[128];
1423 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1425 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1427 SetLastError(0xdeadbeef);
1428 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1429 ok(ret
== count
, "GetGlyphIndicesW error %u\n", GetLastError());
1435 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1437 SetLastError(0xdeadbeef);
1438 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1439 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1442 SelectObject(hdc
, hfont_old
);
1443 DeleteObject(hfont
);
1450 static void test_font_charset(void)
1452 static struct charset_data
1456 WORD font_idxA
[128], font_idxW
[128];
1459 { ANSI_CHARSET
, 1252 },
1460 { RUSSIAN_CHARSET
, 1251 },
1461 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1465 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1467 skip("Skipping the font charset test on a Win9x platform\n");
1471 if (!is_font_installed("Arial"))
1473 skip("Arial is not installed\n");
1477 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1479 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1481 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1483 skip("Symbol or Wingdings is not installed\n");
1487 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
);
1488 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
);
1489 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1492 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1495 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1496 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1499 skip("Symbol or Wingdings is not installed\n");
1502 static void test_GetFontUnicodeRanges(void)
1506 HFONT hfont
, hfont_old
;
1510 if (!pGetFontUnicodeRanges
)
1512 skip("GetFontUnicodeRanges not available before W2K\n");
1516 memset(&lf
, 0, sizeof(lf
));
1517 lstrcpyA(lf
.lfFaceName
, "Arial");
1518 hfont
= create_font("Arial", &lf
);
1521 hfont_old
= SelectObject(hdc
, hfont
);
1523 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1524 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1526 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1527 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1529 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1531 size
= pGetFontUnicodeRanges(hdc
, gs
);
1532 ok(size
, "GetFontUnicodeRanges failed\n");
1534 for (i
= 0; i
< gs
->cRanges
; i
++)
1535 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1537 trace("found %u ranges\n", gs
->cRanges
);
1539 HeapFree(GetProcessHeap(), 0, gs
);
1541 SelectObject(hdc
, hfont_old
);
1542 DeleteObject(hfont
);
1543 ReleaseDC(NULL
, hdc
);
1546 #define MAX_ENUM_FONTS 256
1548 struct enum_font_data
1551 LOGFONT lf
[MAX_ENUM_FONTS
];
1554 struct enum_font_dataW
1557 LOGFONTW lf
[MAX_ENUM_FONTS
];
1560 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1562 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1564 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1566 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1567 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfWeight
, lf
->lfItalic
);
1569 if (efd
->total
< MAX_ENUM_FONTS
)
1570 efd
->lf
[efd
->total
++] = *lf
;
1575 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
1577 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
1579 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1581 if (efd
->total
< MAX_ENUM_FONTS
)
1582 efd
->lf
[efd
->total
++] = *lf
;
1587 static void get_charset_stats(struct enum_font_data
*efd
,
1588 int *ansi_charset
, int *symbol_charset
,
1589 int *russian_charset
)
1594 *symbol_charset
= 0;
1595 *russian_charset
= 0;
1597 for (i
= 0; i
< efd
->total
; i
++)
1599 switch (efd
->lf
[i
].lfCharSet
)
1604 case SYMBOL_CHARSET
:
1605 (*symbol_charset
)++;
1607 case RUSSIAN_CHARSET
:
1608 (*russian_charset
)++;
1614 static void get_charset_statsW(struct enum_font_dataW
*efd
,
1615 int *ansi_charset
, int *symbol_charset
,
1616 int *russian_charset
)
1621 *symbol_charset
= 0;
1622 *russian_charset
= 0;
1624 for (i
= 0; i
< efd
->total
; i
++)
1626 switch (efd
->lf
[i
].lfCharSet
)
1631 case SYMBOL_CHARSET
:
1632 (*symbol_charset
)++;
1634 case RUSSIAN_CHARSET
:
1635 (*russian_charset
)++;
1641 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1643 struct enum_font_data efd
;
1644 struct enum_font_dataW efdw
;
1647 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1649 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1651 if (*font_name
&& !is_truetype_font_installed(font_name
))
1653 skip("%s is not installed\n", font_name
);
1659 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1660 * while EnumFontFamiliesEx doesn't.
1662 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1665 * Use EnumFontFamiliesW since win98 crashes when the
1666 * second parameter is NULL using EnumFontFamilies
1669 SetLastError(0xdeadbeef);
1670 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
1671 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
1674 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1675 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1676 ansi_charset
, symbol_charset
, russian_charset
);
1677 ok(efd
.total
== 0, "fonts enumerated: NULL\n");
1678 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1679 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1680 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1684 SetLastError(0xdeadbeef);
1685 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
1686 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
1689 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1690 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1691 ansi_charset
, symbol_charset
, russian_charset
);
1692 ok(efd
.total
== 0, "fonts enumerated: NULL\n");
1693 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1694 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1695 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1700 SetLastError(0xdeadbeef);
1701 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
1702 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1703 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1704 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1705 ansi_charset
, symbol_charset
, russian_charset
,
1706 *font_name
? font_name
: "<empty>");
1708 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1710 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
1711 for (i
= 0; i
< efd
.total
; i
++)
1713 /* FIXME: remove completely once Wine is fixed */
1714 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
1717 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1720 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1721 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1722 font_name
, efd
.lf
[i
].lfFaceName
);
1725 memset(&lf
, 0, sizeof(lf
));
1726 lf
.lfCharSet
= ANSI_CHARSET
;
1727 lstrcpy(lf
.lfFaceName
, font_name
);
1729 SetLastError(0xdeadbeef);
1730 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1731 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1732 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1733 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1734 ansi_charset
, symbol_charset
, russian_charset
,
1735 *font_name
? font_name
: "<empty>");
1736 if (font_charset
== SYMBOL_CHARSET
)
1739 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
1741 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1745 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
1746 for (i
= 0; i
< efd
.total
; i
++)
1748 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1750 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1751 font_name
, efd
.lf
[i
].lfFaceName
);
1755 /* DEFAULT_CHARSET should enumerate all available charsets */
1756 memset(&lf
, 0, sizeof(lf
));
1757 lf
.lfCharSet
= DEFAULT_CHARSET
;
1758 lstrcpy(lf
.lfFaceName
, font_name
);
1760 SetLastError(0xdeadbeef);
1761 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1762 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1763 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1764 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1765 ansi_charset
, symbol_charset
, russian_charset
,
1766 *font_name
? font_name
: "<empty>");
1767 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
1768 for (i
= 0; i
< efd
.total
; i
++)
1771 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1772 font_name
, efd
.lf
[i
].lfFaceName
);
1776 switch (font_charset
)
1779 ok(ansi_charset
> 0,
1780 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1782 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
1783 ok(russian_charset
> 0,
1784 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1786 case SYMBOL_CHARSET
:
1788 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
1790 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1791 ok(!russian_charset
,
1792 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1794 case DEFAULT_CHARSET
:
1795 ok(ansi_charset
> 0,
1796 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1797 ok(symbol_charset
> 0,
1798 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1799 ok(russian_charset
> 0,
1800 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1806 ok(ansi_charset
> 0,
1807 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1808 ok(symbol_charset
> 0,
1809 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1810 ok(russian_charset
> 0,
1811 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1814 memset(&lf
, 0, sizeof(lf
));
1815 lf
.lfCharSet
= SYMBOL_CHARSET
;
1816 lstrcpy(lf
.lfFaceName
, font_name
);
1818 SetLastError(0xdeadbeef);
1819 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1820 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1821 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1822 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1823 ansi_charset
, symbol_charset
, russian_charset
,
1824 *font_name
? font_name
: "<empty>");
1825 if (*font_name
&& font_charset
== ANSI_CHARSET
)
1826 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
1829 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
1830 for (i
= 0; i
< efd
.total
; i
++)
1832 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1834 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1835 font_name
, efd
.lf
[i
].lfFaceName
);
1839 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1840 ok(symbol_charset
> 0,
1841 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1842 ok(!russian_charset
,
1843 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1849 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
1851 HFONT hfont
, hfont_prev
;
1853 GLYPHMETRICS gm1
, gm2
;
1856 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
1858 if(!pGetGlyphIndicesA
)
1860 skip("GetGlyphIndicesA is unavailable\n");
1864 /* negative widths are handled just as positive ones */
1865 lf2
.lfWidth
= -lf
->lfWidth
;
1867 SetLastError(0xdeadbeef);
1868 hfont
= CreateFontIndirectA(lf
);
1869 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1870 check_font("original", lf
, hfont
);
1872 hfont_prev
= SelectObject(hdc
, hfont
);
1874 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
1875 if (ret
== GDI_ERROR
|| idx
== 0xffff)
1877 SelectObject(hdc
, hfont_prev
);
1878 DeleteObject(hfont
);
1879 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
1883 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1884 memset(&gm1
, 0xab, sizeof(gm1
));
1885 SetLastError(0xdeadbeef);
1886 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
1887 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1889 SelectObject(hdc
, hfont_prev
);
1890 DeleteObject(hfont
);
1892 SetLastError(0xdeadbeef);
1893 hfont
= CreateFontIndirectA(&lf2
);
1894 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1895 check_font("negative width", &lf2
, hfont
);
1897 hfont_prev
= SelectObject(hdc
, hfont
);
1899 memset(&gm2
, 0xbb, sizeof(gm2
));
1900 SetLastError(0xdeadbeef);
1901 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
1902 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1904 SelectObject(hdc
, hfont_prev
);
1905 DeleteObject(hfont
);
1907 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
1908 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
1909 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
1910 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
1911 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
1912 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
1913 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1914 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
1915 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
1916 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
1917 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
1920 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1921 #include "pshpack2.h"
1925 SHORT xAvgCharWidth
;
1926 USHORT usWeightClass
;
1927 USHORT usWidthClass
;
1929 SHORT ySubscriptXSize
;
1930 SHORT ySubscriptYSize
;
1931 SHORT ySubscriptXOffset
;
1932 SHORT ySubscriptYOffset
;
1933 SHORT ySuperscriptXSize
;
1934 SHORT ySuperscriptYSize
;
1935 SHORT ySuperscriptXOffset
;
1936 SHORT ySuperscriptYOffset
;
1937 SHORT yStrikeoutSize
;
1938 SHORT yStrikeoutPosition
;
1941 ULONG ulUnicodeRange1
;
1942 ULONG ulUnicodeRange2
;
1943 ULONG ulUnicodeRange3
;
1944 ULONG ulUnicodeRange4
;
1947 USHORT usFirstCharIndex
;
1948 USHORT usLastCharIndex
;
1949 /* According to the Apple spec, original version didn't have the below fields,
1950 * version numbers were taked from the OpenType spec.
1952 /* version 0 (TrueType 1.5) */
1953 USHORT sTypoAscender
;
1954 USHORT sTypoDescender
;
1955 USHORT sTypoLineGap
;
1957 USHORT usWinDescent
;
1958 /* version 1 (TrueType 1.66) */
1959 ULONG ulCodePageRange1
;
1960 ULONG ulCodePageRange2
;
1961 /* version 2 (OpenType 1.2) */
1964 USHORT usDefaultChar
;
1966 USHORT usMaxContext
;
1968 #include "poppack.h"
1970 #ifdef WORDS_BIGENDIAN
1971 #define GET_BE_WORD(x) (x)
1973 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1976 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1977 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1978 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1979 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1981 static void test_text_metrics(const LOGFONTA
*lf
)
1984 HFONT hfont
, hfont_old
;
1987 UINT first_unicode_char
, last_unicode_char
, default_char
, break_char
;
1992 const char *font_name
= lf
->lfFaceName
;
1996 SetLastError(0xdeadbeef);
1997 hfont
= CreateFontIndirectA(lf
);
1998 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2000 hfont_old
= SelectObject(hdc
, hfont
);
2002 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2003 if (size
== GDI_ERROR
)
2005 trace("OS/2 chunk was not found\n");
2008 if (size
> sizeof(tt_os2
))
2010 trace("got too large OS/2 chunk of size %u\n", size
);
2011 size
= sizeof(tt_os2
);
2014 memset(&tt_os2
, 0, sizeof(tt_os2
));
2015 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2016 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2018 version
= GET_BE_WORD(tt_os2
.version
);
2020 first_unicode_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2021 last_unicode_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2022 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2023 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2025 trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
2026 font_name
, lf
->lfCharSet
, first_unicode_char
, last_unicode_char
, default_char
, break_char
,
2027 version
, (LPCSTR
)&tt_os2
.achVendID
);
2029 SetLastError(0xdeadbeef);
2030 ret
= GetTextMetricsA(hdc
, &tmA
);
2031 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2033 #if 0 /* FIXME: This doesn't appear to be what Windows does */
2034 test_char
= min(first_unicode_char
- 1, 255);
2035 ok(tmA
.tmFirstChar
== test_char
, "A: tmFirstChar for %s %02x != %02x\n",
2036 font_name
, tmA
.tmFirstChar
, test_char
);
2038 if (lf
->lfCharSet
== SYMBOL_CHARSET
)
2040 test_char
= min(last_unicode_char
- 0xf000, 255);
2041 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
2042 font_name
, tmA
.tmLastChar
, test_char
);
2046 test_char
= min(last_unicode_char
, 255);
2047 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
2048 font_name
, tmA
.tmLastChar
, test_char
);
2051 SetLastError(0xdeadbeef);
2052 ret
= GetTextMetricsW(hdc
, &tmW
);
2053 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2054 "GetTextMetricsW error %u\n", GetLastError());
2057 trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
2058 tmW
.tmFirstChar
, tmW
.tmLastChar
, tmA
.tmFirstChar
, tmA
.tmLastChar
,
2059 tmW
.tmDefaultChar
, tmA
.tmDefaultChar
, tmW
.tmBreakChar
, tmA
.tmBreakChar
);
2061 if (lf
->lfCharSet
== SYMBOL_CHARSET
)
2063 /* It appears that for fonts with SYMBOL_CHARSET Windows always
2064 * sets symbol range to 0 - f0ff
2066 ok(tmW
.tmFirstChar
== 0, "W: tmFirstChar for %s %02x != 0\n",
2067 font_name
, tmW
.tmFirstChar
);
2068 /* FIXME: Windows returns f0ff here, while Wine f0xx */
2069 ok(tmW
.tmLastChar
>= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
2070 font_name
, tmW
.tmLastChar
);
2072 ok(tmW
.tmDefaultChar
== 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
2073 font_name
, tmW
.tmDefaultChar
);
2074 ok(tmW
.tmBreakChar
== 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
2075 font_name
, tmW
.tmBreakChar
);
2079 ok(tmW
.tmFirstChar
== first_unicode_char
, "W: tmFirstChar for %s %02x != %02x\n",
2080 font_name
, tmW
.tmFirstChar
, first_unicode_char
);
2081 ok(tmW
.tmLastChar
== last_unicode_char
, "W: tmLastChar for %s %02x != %02x\n",
2082 font_name
, tmW
.tmLastChar
, last_unicode_char
);
2084 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2085 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2086 tmW
.tmDigitizedAspectX
, ret
);
2087 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2088 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2089 tmW
.tmDigitizedAspectX
, ret
);
2092 test_negative_width(hdc
, lf
);
2095 SelectObject(hdc
, hfont_old
);
2096 DeleteObject(hfont
);
2101 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2103 INT
*enumed
= (INT
*)lParam
;
2105 if (type
== TRUETYPE_FONTTYPE
)
2108 test_text_metrics(lf
);
2113 static void test_GetTextMetrics(void)
2121 memset(&lf
, 0, sizeof(lf
));
2122 lf
.lfCharSet
= DEFAULT_CHARSET
;
2124 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2125 trace("Tested metrics of %d truetype fonts\n", enumed
);
2130 static void test_nonexistent_font(void)
2138 { "Times New Roman Baltic", 186 },
2139 { "Times New Roman CE", 238 },
2140 { "Times New Roman CYR", 204 },
2141 { "Times New Roman Greek", 161 },
2142 { "Times New Roman TUR", 162 }
2148 INT cs
, expected_cs
, i
;
2149 char buf
[LF_FACESIZE
];
2151 if (!is_truetype_font_installed("Arial") ||
2152 !is_truetype_font_installed("Times New Roman"))
2154 skip("Arial or Times New Roman not installed\n");
2158 expected_cs
= GetACP();
2159 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
2161 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
2164 expected_cs
= csi
.ciCharset
;
2165 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
2169 memset(&lf
, 0, sizeof(lf
));
2171 lf
.lfWeight
= FW_REGULAR
;
2172 lf
.lfCharSet
= ANSI_CHARSET
;
2173 lf
.lfPitchAndFamily
= FF_SWISS
;
2174 strcpy(lf
.lfFaceName
, "Nonexistent font");
2175 hfont
= CreateFontIndirectA(&lf
);
2176 hfont
= SelectObject(hdc
, hfont
);
2177 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2178 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
2179 cs
= GetTextCharset(hdc
);
2180 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2181 DeleteObject(SelectObject(hdc
, hfont
));
2183 memset(&lf
, 0, sizeof(lf
));
2185 lf
.lfWeight
= FW_DONTCARE
;
2186 strcpy(lf
.lfFaceName
, "Nonexistent font");
2187 hfont
= CreateFontIndirectA(&lf
);
2188 hfont
= SelectObject(hdc
, hfont
);
2189 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2190 todo_wine
/* Wine uses Arial for all substitutions */
2191 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
2192 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
2193 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2195 cs
= GetTextCharset(hdc
);
2196 ok(cs
== expected_cs
, "expected %d, got %d\n", expected_cs
, cs
);
2197 DeleteObject(SelectObject(hdc
, hfont
));
2199 memset(&lf
, 0, sizeof(lf
));
2201 lf
.lfWeight
= FW_REGULAR
;
2202 strcpy(lf
.lfFaceName
, "Nonexistent font");
2203 hfont
= CreateFontIndirectA(&lf
);
2204 hfont
= SelectObject(hdc
, hfont
);
2205 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2206 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2207 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
2208 cs
= GetTextCharset(hdc
);
2209 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2210 DeleteObject(SelectObject(hdc
, hfont
));
2212 memset(&lf
, 0, sizeof(lf
));
2214 lf
.lfWeight
= FW_DONTCARE
;
2215 strcpy(lf
.lfFaceName
, "Times New Roman");
2216 hfont
= CreateFontIndirectA(&lf
);
2217 hfont
= SelectObject(hdc
, hfont
);
2218 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2219 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
2220 cs
= GetTextCharset(hdc
);
2221 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2222 DeleteObject(SelectObject(hdc
, hfont
));
2224 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
2226 memset(&lf
, 0, sizeof(lf
));
2228 lf
.lfWeight
= FW_REGULAR
;
2229 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2230 hfont
= CreateFontIndirectA(&lf
);
2231 hfont
= SelectObject(hdc
, hfont
);
2232 cs
= GetTextCharset(hdc
);
2233 if (font_subst
[i
].charset
== expected_cs
)
2235 ok(cs
== expected_cs
, "expected %d, got %d\n", expected_cs
, cs
);
2236 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2237 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
2241 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2242 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2243 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2244 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s\n", buf
);
2246 DeleteObject(SelectObject(hdc
, hfont
));
2248 memset(&lf
, 0, sizeof(lf
));
2250 lf
.lfWeight
= FW_DONTCARE
;
2251 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2252 hfont
= CreateFontIndirectA(&lf
);
2253 hfont
= SelectObject(hdc
, hfont
);
2254 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2255 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
2256 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
2257 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
2258 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2260 cs
= GetTextCharset(hdc
);
2261 ok(cs
== expected_cs
, "expected %d, got %d\n", expected_cs
, cs
);
2262 DeleteObject(SelectObject(hdc
, hfont
));
2268 static void test_GdiRealizationInfo(void)
2273 HFONT hfont
, hfont_old
;
2276 if(!pGdiRealizationInfo
)
2278 skip("GdiRealizationInfo not available\n");
2284 memset(info
, 0xcc, sizeof(info
));
2285 r
= pGdiRealizationInfo(hdc
, info
);
2286 ok(r
!= 0, "ret 0\n");
2287 ok(info
[0] == 1, "info[0] = %x for the system font\n", info
[0]);
2288 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2290 if (!is_truetype_font_installed("Arial"))
2292 skip("skipping GdiRealizationInfo with truetype font\n");
2296 memset(&lf
, 0, sizeof(lf
));
2297 strcpy(lf
.lfFaceName
, "Arial");
2299 lf
.lfWeight
= FW_NORMAL
;
2300 hfont
= CreateFontIndirectA(&lf
);
2301 hfont_old
= SelectObject(hdc
, hfont
);
2303 memset(info
, 0xcc, sizeof(info
));
2304 r
= pGdiRealizationInfo(hdc
, info
);
2305 ok(r
!= 0, "ret 0\n");
2306 ok(info
[0] == 3, "info[0] = %x for arial\n", info
[0]);
2307 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2309 DeleteObject(SelectObject(hdc
, hfont_old
));
2315 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2316 the nul in the count of characters copied when the face name buffer is not
2317 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2318 always includes it. */
2319 static void test_GetTextFace(void)
2321 static const char faceA
[] = "Tahoma";
2322 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
2325 char bufA
[LF_FACESIZE
];
2326 WCHAR bufW
[LF_FACESIZE
];
2332 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
2333 f
= CreateFontIndirectA(&fA
);
2334 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
2337 g
= SelectObject(dc
, f
);
2338 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
2339 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
2340 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
2342 /* Play with the count arg. */
2344 n
= GetTextFaceA(dc
, 0, bufA
);
2345 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2346 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2349 n
= GetTextFaceA(dc
, 1, bufA
);
2350 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2351 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2353 bufA
[0] = 'x'; bufA
[1] = 'y';
2354 n
= GetTextFaceA(dc
, 2, bufA
);
2355 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
2356 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
2358 n
= GetTextFaceA(dc
, 0, NULL
);
2359 ok(n
== sizeof faceA
, "GetTextFaceA returned %d\n", n
);
2361 DeleteObject(SelectObject(dc
, g
));
2362 ReleaseDC(NULL
, dc
);
2365 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
2366 SetLastError(0xdeadbeef);
2367 f
= CreateFontIndirectW(&fW
);
2368 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2370 win_skip("CreateFontIndirectW is not implemented\n");
2373 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
2376 g
= SelectObject(dc
, f
);
2377 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
2378 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2379 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
2381 /* Play with the count arg. */
2383 n
= GetTextFaceW(dc
, 0, bufW
);
2384 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
2385 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2388 n
= GetTextFaceW(dc
, 1, bufW
);
2389 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
2390 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2392 bufW
[0] = 'x'; bufW
[1] = 'y';
2393 n
= GetTextFaceW(dc
, 2, bufW
);
2394 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
2395 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
2397 n
= GetTextFaceW(dc
, 0, NULL
);
2398 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2400 DeleteObject(SelectObject(dc
, g
));
2401 ReleaseDC(NULL
, dc
);
2404 static void test_orientation(void)
2406 static const char test_str
[11] = "Test String";
2409 HFONT hfont
, old_hfont
;
2412 if (!is_truetype_font_installed("Arial"))
2414 skip("Arial is not installed\n");
2418 hdc
= CreateCompatibleDC(0);
2419 memset(&lf
, 0, sizeof(lf
));
2420 lstrcpyA(lf
.lfFaceName
, "Arial");
2422 lf
.lfOrientation
= lf
.lfEscapement
= 900;
2423 hfont
= create_font("orientation", &lf
);
2424 old_hfont
= SelectObject(hdc
, hfont
);
2425 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
2426 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
2427 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
2428 SelectObject(hdc
, old_hfont
);
2429 DeleteObject(hfont
);
2439 test_outline_font();
2440 test_bitmap_font_metrics();
2441 test_GdiGetCharDimensions();
2442 test_GetCharABCWidths();
2443 test_text_extents();
2444 test_GetGlyphIndices();
2445 test_GetKerningPairs();
2446 test_GetOutlineTextMetrics();
2447 test_SetTextJustification();
2448 test_font_charset();
2449 test_GetFontUnicodeRanges();
2450 test_nonexistent_font();
2453 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2454 * I'd like to avoid them in this test.
2456 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
2457 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
2458 if (is_truetype_font_installed("Arial Black") &&
2459 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2461 test_EnumFontFamilies("", ANSI_CHARSET
);
2462 test_EnumFontFamilies("", SYMBOL_CHARSET
);
2463 test_EnumFontFamilies("", DEFAULT_CHARSET
);
2466 skip("Arial Black or Symbol/Wingdings is not installed\n");
2467 test_GetTextMetrics();
2468 test_GdiRealizationInfo();