[ROSTESTS]
[reactos.git] / rostests / winetests / gdi32 / font.c
1 /*
2 * Unit test suite for fonts
3 *
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include <stdarg.h>
23 #include <assert.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
30
31 #include "wine/test.h"
32
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
35
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)
38
39 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
41 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
42 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
43 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
44 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
45 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
46 HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
47
48 static HMODULE hgdi32 = 0;
49
50 static void init(void)
51 {
52 hgdi32 = GetModuleHandleA("gdi32.dll");
53
54 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
55 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
56 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
57 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
58 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
59 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
60 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
61 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
62 }
63
64 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
65 {
66 if (type != TRUETYPE_FONTTYPE) return 1;
67
68 return 0;
69 }
70
71 static BOOL is_truetype_font_installed(const char *name)
72 {
73 HDC hdc = GetDC(0);
74 BOOL ret = FALSE;
75
76 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
77 ret = TRUE;
78
79 ReleaseDC(0, hdc);
80 return ret;
81 }
82
83 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
84 {
85 return 0;
86 }
87
88 static BOOL is_font_installed(const char *name)
89 {
90 HDC hdc = GetDC(0);
91 BOOL ret = FALSE;
92
93 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
94 ret = TRUE;
95
96 ReleaseDC(0, hdc);
97 return ret;
98 }
99
100 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
101 {
102 LOGFONTA getobj_lf;
103 int ret, minlen = 0;
104
105 if (!hfont)
106 return;
107
108 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
109 /* NT4 tries to be clever and only returns the minimum length */
110 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
111 minlen++;
112 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
113 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
114 ok(lf->lfHeight == getobj_lf.lfHeight ||
115 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
116 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
117 ok(lf->lfWidth == getobj_lf.lfWidth ||
118 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
119 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
120 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
121 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
122 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
123 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
124 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
125 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
126 ok(lf->lfWeight == getobj_lf.lfWeight ||
127 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
128 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
129 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
130 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
131 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
132 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
133 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
134 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
135 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
136 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
137 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
138 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
139 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
140 }
141
142 static HFONT create_font(const char* test, const LOGFONTA* lf)
143 {
144 HFONT hfont = CreateFontIndirectA(lf);
145 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
146 if (hfont)
147 check_font(test, lf, hfont);
148 return hfont;
149 }
150
151 static void test_logfont(void)
152 {
153 LOGFONTA lf;
154 HFONT hfont;
155
156 memset(&lf, 0, sizeof lf);
157
158 lf.lfCharSet = ANSI_CHARSET;
159 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
160 lf.lfWeight = FW_DONTCARE;
161 lf.lfHeight = 16;
162 lf.lfWidth = 16;
163 lf.lfQuality = DEFAULT_QUALITY;
164
165 lstrcpyA(lf.lfFaceName, "Arial");
166 hfont = create_font("Arial", &lf);
167 DeleteObject(hfont);
168
169 memset(&lf, 'A', sizeof(lf));
170 hfont = CreateFontIndirectA(&lf);
171 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
172
173 lf.lfFaceName[LF_FACESIZE - 1] = 0;
174 check_font("AAA...", &lf, hfont);
175 DeleteObject(hfont);
176 }
177
178 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
179 {
180 if (type & RASTER_FONTTYPE)
181 {
182 LOGFONT *lf = (LOGFONT *)lParam;
183 *lf = *elf;
184 return 0; /* stop enumeration */
185 }
186
187 return 1; /* continue enumeration */
188 }
189
190 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
191 {
192 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
193 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
194 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
195 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
196 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
197 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
198 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
199 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
200 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
201 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
202 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
203 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
204 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
205 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
206 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
207 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
208 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
209 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
210 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
211 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
212 }
213
214 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
215 LONG lfWidth, const char *test_str,
216 INT test_str_len, const TEXTMETRICA *tm_orig,
217 const SIZE *size_orig, INT width_of_A_orig,
218 INT scale_x, INT scale_y)
219 {
220 LOGFONTA lf;
221 OUTLINETEXTMETRIC otm;
222 TEXTMETRICA tm;
223 SIZE size;
224 INT width_of_A, cx, cy;
225 UINT ret;
226
227 if (!hfont)
228 return;
229
230 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
231
232 GetObjectA(hfont, sizeof(lf), &lf);
233
234 if (GetOutlineTextMetricsA(hdc, 0, NULL))
235 {
236 otm.otmSize = sizeof(otm) / 2;
237 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
238 ok(ret == sizeof(otm)/2 /* XP */ ||
239 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
240
241 memset(&otm, 0x1, sizeof(otm));
242 otm.otmSize = sizeof(otm);
243 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
244 ok(ret == sizeof(otm) /* XP */ ||
245 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
246
247 memset(&tm, 0x2, sizeof(tm));
248 ret = GetTextMetricsA(hdc, &tm);
249 ok(ret, "GetTextMetricsA failed\n");
250 /* the structure size is aligned */
251 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
252 {
253 ok(0, "tm != otm\n");
254 compare_tm(&tm, &otm.otmTextMetrics);
255 }
256
257 tm = otm.otmTextMetrics;
258 if (0) /* these metrics are scaled too, but with rounding errors */
259 {
260 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
261 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
262 }
263 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
264 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
265 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
266 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
267 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
268 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
269 }
270 else
271 {
272 ret = GetTextMetricsA(hdc, &tm);
273 ok(ret, "GetTextMetricsA failed\n");
274 }
275
276 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
277 cy = tm.tmHeight / tm_orig->tmHeight;
278 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
279 lfHeight, scale_x, scale_y, cx, cy);
280 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
281 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
282 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
283 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
284 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
285
286 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
287 if (lf.lfHeight)
288 {
289 if (lf.lfWidth)
290 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
291 }
292 else
293 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
294
295 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
296
297 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
298 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
299
300 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
301
302 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);
303 }
304
305 /* Test how GDI scales bitmap font metrics */
306 static void test_bitmap_font(void)
307 {
308 static const char test_str[11] = "Test String";
309 HDC hdc;
310 LOGFONTA bitmap_lf;
311 HFONT hfont, old_hfont;
312 TEXTMETRICA tm_orig;
313 SIZE size_orig;
314 INT ret, i, width_orig, height_orig, scale, lfWidth;
315
316 if(!winetest_interactive)
317 {
318 skip("reactos bug 5401: Skipping bitmap font tests!\n");
319 return;
320 }
321
322 hdc = GetDC(0);
323
324 /* "System" has only 1 pixel size defined, otherwise the test breaks */
325 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
326 if (ret)
327 {
328 ReleaseDC(0, hdc);
329 trace("no bitmap fonts were found, skipping the test\n");
330 return;
331 }
332
333 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
334
335 height_orig = bitmap_lf.lfHeight;
336 lfWidth = bitmap_lf.lfWidth;
337
338 hfont = create_font("bitmap", &bitmap_lf);
339 old_hfont = SelectObject(hdc, hfont);
340 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
341 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
342 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
343 SelectObject(hdc, old_hfont);
344 DeleteObject(hfont);
345
346 bitmap_lf.lfHeight = 0;
347 bitmap_lf.lfWidth = 4;
348 hfont = create_font("bitmap", &bitmap_lf);
349 old_hfont = SelectObject(hdc, hfont);
350 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
351 SelectObject(hdc, old_hfont);
352 DeleteObject(hfont);
353
354 bitmap_lf.lfHeight = height_orig;
355 bitmap_lf.lfWidth = lfWidth;
356
357 /* test fractional scaling */
358 for (i = 1; i <= height_orig * 6; i++)
359 {
360 INT nearest_height;
361
362 bitmap_lf.lfHeight = i;
363 hfont = create_font("fractional", &bitmap_lf);
364 scale = (i + height_orig - 1) / height_orig;
365 nearest_height = scale * height_orig;
366 /* Only jump to the next height if the difference <= 25% original height */
367 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
368 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
369 so we'll not test this particular height. */
370 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
371 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
372 old_hfont = SelectObject(hdc, hfont);
373 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
374 SelectObject(hdc, old_hfont);
375 DeleteObject(hfont);
376 }
377
378 /* test integer scaling 3x2 */
379 bitmap_lf.lfHeight = height_orig * 2;
380 bitmap_lf.lfWidth *= 3;
381 hfont = create_font("3x2", &bitmap_lf);
382 old_hfont = SelectObject(hdc, hfont);
383 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
384 SelectObject(hdc, old_hfont);
385 DeleteObject(hfont);
386
387 /* test integer scaling 3x3 */
388 bitmap_lf.lfHeight = height_orig * 3;
389 bitmap_lf.lfWidth = 0;
390 hfont = create_font("3x3", &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, 3);
393 SelectObject(hdc, old_hfont);
394 DeleteObject(hfont);
395
396 ReleaseDC(0, hdc);
397 }
398
399 /* Test how GDI scales outline font metrics */
400 static void test_outline_font(void)
401 {
402 static const char test_str[11] = "Test String";
403 HDC hdc, hdc_2;
404 LOGFONTA lf;
405 HFONT hfont, old_hfont, old_hfont_2;
406 OUTLINETEXTMETRICA otm;
407 SIZE size_orig;
408 INT width_orig, height_orig, lfWidth;
409 XFORM xform;
410 GLYPHMETRICS gm;
411 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
412 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
413 POINT pt;
414 INT ret;
415
416 if(!winetest_interactive)
417 {
418 skip("reactos bug 5401: Skipping outline font tests!\n");
419 return;
420 }
421
422 if (!is_truetype_font_installed("Arial"))
423 {
424 skip("Arial is not installed\n");
425 return;
426 }
427
428 hdc = CreateCompatibleDC(0);
429
430 memset(&lf, 0, sizeof(lf));
431 strcpy(lf.lfFaceName, "Arial");
432 lf.lfHeight = 72;
433 hfont = create_font("outline", &lf);
434 old_hfont = SelectObject(hdc, hfont);
435 otm.otmSize = sizeof(otm);
436 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
437 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
438 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
439
440 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
441 SelectObject(hdc, old_hfont);
442 DeleteObject(hfont);
443
444 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
445 lf.lfHeight = otm.otmEMSquare;
446 lf.lfHeight = -lf.lfHeight;
447 hfont = create_font("outline", &lf);
448 old_hfont = SelectObject(hdc, hfont);
449 otm.otmSize = sizeof(otm);
450 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
451 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
452 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
453 SelectObject(hdc, old_hfont);
454 DeleteObject(hfont);
455
456 height_orig = otm.otmTextMetrics.tmHeight;
457 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
458
459 /* test integer scaling 3x2 */
460 lf.lfHeight = height_orig * 2;
461 lf.lfWidth = lfWidth * 3;
462 hfont = create_font("3x2", &lf);
463 old_hfont = SelectObject(hdc, hfont);
464 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
465 SelectObject(hdc, old_hfont);
466 DeleteObject(hfont);
467
468 /* test integer scaling 3x3 */
469 lf.lfHeight = height_orig * 3;
470 lf.lfWidth = lfWidth * 3;
471 hfont = create_font("3x3", &lf);
472 old_hfont = SelectObject(hdc, hfont);
473 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
474 SelectObject(hdc, old_hfont);
475 DeleteObject(hfont);
476
477 /* test integer scaling 1x1 */
478 lf.lfHeight = height_orig * 1;
479 lf.lfWidth = lfWidth * 1;
480 hfont = create_font("1x1", &lf);
481 old_hfont = SelectObject(hdc, hfont);
482 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
483 SelectObject(hdc, old_hfont);
484 DeleteObject(hfont);
485
486 /* test integer scaling 1x1 */
487 lf.lfHeight = height_orig;
488 lf.lfWidth = 0;
489 hfont = create_font("1x1", &lf);
490 old_hfont = SelectObject(hdc, hfont);
491 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
492
493 /* with an identity matrix */
494 memset(&gm, 0, sizeof(gm));
495 SetLastError(0xdeadbeef);
496 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
497 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
498 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
499 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
500 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
501 /* with a custom matrix */
502 memset(&gm, 0, sizeof(gm));
503 SetLastError(0xdeadbeef);
504 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
505 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
506 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
507 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
508 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
509
510 /* Test that changing the DC transformation affects only the font
511 * selected on this DC and doesn't affect the same font selected on
512 * another DC.
513 */
514 hdc_2 = CreateCompatibleDC(0);
515 old_hfont_2 = SelectObject(hdc_2, hfont);
516 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
517
518 SetMapMode(hdc, MM_ANISOTROPIC);
519
520 /* font metrics on another DC should be unchanged */
521 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
522
523 /* test restrictions of compatibility mode GM_COMPATIBLE */
524 /* part 1: rescaling only X should not change font scaling on screen.
525 So compressing the X axis by 2 is not done, and this
526 appears as X scaling of 2 that no one requested. */
527 SetWindowExtEx(hdc, 100, 100, NULL);
528 SetViewportExtEx(hdc, 50, 100, NULL);
529 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
530 /* font metrics on another DC should be unchanged */
531 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
532
533 /* part 2: rescaling only Y should change font scaling.
534 As also X is scaled by a factor of 2, but this is not
535 requested by the DC transformation, we get a scaling factor
536 of 2 in the X coordinate. */
537 SetViewportExtEx(hdc, 100, 200, NULL);
538 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
539 /* font metrics on another DC should be unchanged */
540 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
541
542 /* restore scaling */
543 SetMapMode(hdc, MM_TEXT);
544
545 /* font metrics on another DC should be unchanged */
546 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
547
548 SelectObject(hdc_2, old_hfont_2);
549 DeleteDC(hdc_2);
550
551 if (!SetGraphicsMode(hdc, GM_ADVANCED))
552 {
553 SelectObject(hdc, old_hfont);
554 DeleteObject(hfont);
555 DeleteDC(hdc);
556 skip("GM_ADVANCED is not supported on this platform\n");
557 return;
558 }
559
560 xform.eM11 = 20.0f;
561 xform.eM12 = 0.0f;
562 xform.eM21 = 0.0f;
563 xform.eM22 = 20.0f;
564 xform.eDx = 0.0f;
565 xform.eDy = 0.0f;
566
567 SetLastError(0xdeadbeef);
568 ret = SetWorldTransform(hdc, &xform);
569 ok(ret, "SetWorldTransform error %u\n", GetLastError());
570
571 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
572
573 /* with an identity matrix */
574 memset(&gm, 0, sizeof(gm));
575 SetLastError(0xdeadbeef);
576 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
577 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
578 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
579 pt.x = width_orig; pt.y = 0;
580 LPtoDP(hdc, &pt, 1);
581 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
582 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
583 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
584 /* with a custom matrix */
585 memset(&gm, 0, sizeof(gm));
586 SetLastError(0xdeadbeef);
587 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
588 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
589 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
590 pt.x = width_orig; pt.y = 0;
591 LPtoDP(hdc, &pt, 1);
592 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
593 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
594 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
595
596 SetLastError(0xdeadbeef);
597 ret = SetMapMode(hdc, MM_LOMETRIC);
598 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
599
600 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
601
602 /* with an identity matrix */
603 memset(&gm, 0, sizeof(gm));
604 SetLastError(0xdeadbeef);
605 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
606 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
607 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
608 pt.x = width_orig; pt.y = 0;
609 LPtoDP(hdc, &pt, 1);
610 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
611 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
612 /* with a custom matrix */
613 memset(&gm, 0, sizeof(gm));
614 SetLastError(0xdeadbeef);
615 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
616 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
617 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
618 pt.x = width_orig; pt.y = 0;
619 LPtoDP(hdc, &pt, 1);
620 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
621 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
622
623 SetLastError(0xdeadbeef);
624 ret = SetMapMode(hdc, MM_TEXT);
625 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
626
627 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
628
629 /* with an identity matrix */
630 memset(&gm, 0, sizeof(gm));
631 SetLastError(0xdeadbeef);
632 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
633 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
634 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
635 pt.x = width_orig; pt.y = 0;
636 LPtoDP(hdc, &pt, 1);
637 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
638 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
639 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
640 /* with a custom matrix */
641 memset(&gm, 0, sizeof(gm));
642 SetLastError(0xdeadbeef);
643 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
644 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
645 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
646 pt.x = width_orig; pt.y = 0;
647 LPtoDP(hdc, &pt, 1);
648 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
649 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
650 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
651
652 SelectObject(hdc, old_hfont);
653 DeleteObject(hfont);
654 DeleteDC(hdc);
655 }
656
657 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
658 {
659 LOGFONT *lf = (LOGFONT *)lParam;
660
661 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
662 {
663 *lf = *elf;
664 return 0; /* stop enumeration */
665 }
666 return 1; /* continue enumeration */
667 }
668
669 static void test_bitmap_font_metrics(void)
670 {
671 static const struct font_data
672 {
673 const char face_name[LF_FACESIZE];
674 int weight, height, ascent, descent, int_leading, ext_leading;
675 int ave_char_width, max_char_width, dpi;
676 DWORD ansi_bitfield;
677 } fd[] =
678 {
679 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
680 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
681 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
682 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
683 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
684 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
685 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
687 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
688 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
689 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
690
691 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
693 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
694 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
695 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
696 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
697 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
698 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
699
700 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
701 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
702 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
703 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
704 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
705 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
706 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
707 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
709 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
710 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
711 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
712 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
713 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
714 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
716 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
717
718 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
719 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
720 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
721 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
722 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
723 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
724 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
725 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
726 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
727 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
728 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
729
730 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
731 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
732 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
733
734 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
735 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
736 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
737
738 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
739 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
740 /*
741 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
742 * require a new system.sfd for that font
743 */
744 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
745
746 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
747 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
748
749 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
750 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
751 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
752 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
753 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
754 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
755 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
756 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
757 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
758 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
759 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
760 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
761 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
762 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
765 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
766
767 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
768 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
769 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
770 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
771 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
772 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
773 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
774 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
775 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
776 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
777 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
778 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
779
780 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
781 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
782 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
783
784 /* The 120dpi version still has its dpi marked as 96 */
785 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
786
787 /* FIXME: add "Terminal" */
788 };
789 HDC hdc;
790 LOGFONT lf;
791 HFONT hfont, old_hfont;
792 TEXTMETRIC tm;
793 INT ret, i;
794
795 hdc = CreateCompatibleDC(0);
796 assert(hdc);
797
798 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
799 {
800 int bit;
801
802 memset(&lf, 0, sizeof(lf));
803
804 lf.lfHeight = fd[i].height;
805 strcpy(lf.lfFaceName, fd[i].face_name);
806
807 for(bit = 0; bit < 32; bit++)
808 {
809 DWORD fs[2];
810 CHARSETINFO csi;
811
812 fs[0] = 1L << bit;
813 fs[1] = 0;
814 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
815 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
816
817 lf.lfCharSet = csi.ciCharset;
818 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
819 if (ret) continue;
820
821 hfont = create_font(lf.lfFaceName, &lf);
822 old_hfont = SelectObject(hdc, hfont);
823 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
824 if(fd[i].dpi == tm.tmDigitizedAspectX)
825 {
826 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
827 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);
828 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);
829 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);
830 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);
831 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);
832 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);
833 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);
834
835 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
836 that make the max width bigger */
837 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
838 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);
839 }
840 SelectObject(hdc, old_hfont);
841 DeleteObject(hfont);
842 }
843 }
844
845 DeleteDC(hdc);
846 }
847
848 static void test_GdiGetCharDimensions(void)
849 {
850 HDC hdc;
851 TEXTMETRICW tm;
852 LONG ret;
853 SIZE size;
854 LONG avgwidth, height;
855 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
856
857 if (!pGdiGetCharDimensions)
858 {
859 win_skip("GdiGetCharDimensions not available on this platform\n");
860 return;
861 }
862
863 hdc = CreateCompatibleDC(NULL);
864
865 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
866 avgwidth = ((size.cx / 26) + 1) / 2;
867
868 ret = pGdiGetCharDimensions(hdc, &tm, &height);
869 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
870 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
871
872 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
873 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
874
875 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
876 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
877
878 height = 0;
879 ret = pGdiGetCharDimensions(hdc, NULL, &height);
880 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
881 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
882
883 DeleteDC(hdc);
884 }
885
886 static void test_GetCharABCWidths(void)
887 {
888 static const WCHAR str[] = {'a',0};
889 BOOL ret;
890 HDC hdc;
891 LOGFONTA lf;
892 HFONT hfont;
893 ABC abc[1];
894 WORD glyphs[1];
895 DWORD nb;
896
897 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
898 {
899 win_skip("GetCharABCWidthsW/I not available on this platform\n");
900 return;
901 }
902
903 memset(&lf, 0, sizeof(lf));
904 strcpy(lf.lfFaceName, "System");
905 lf.lfHeight = 20;
906
907 hfont = CreateFontIndirectA(&lf);
908 hdc = GetDC(0);
909 hfont = SelectObject(hdc, hfont);
910
911 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
912 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
913
914 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
915 ok(!ret, "GetCharABCWidthsI should have failed\n");
916
917 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
918 ok(!ret, "GetCharABCWidthsI should have failed\n");
919
920 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
921 ok(ret, "GetCharABCWidthsI should have succeeded\n");
922
923 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
924 ok(!ret, "GetCharABCWidthsW should have failed\n");
925
926 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
927 ok(!ret, "GetCharABCWidthsW should have failed\n");
928
929 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
930 ok(!ret, "GetCharABCWidthsW should have failed\n");
931
932 hfont = SelectObject(hdc, hfont);
933 DeleteObject(hfont);
934 ReleaseDC(NULL, hdc);
935 }
936
937 static void test_text_extents(void)
938 {
939 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
940 LPINT extents;
941 INT i, len, fit1, fit2;
942 LOGFONTA lf;
943 TEXTMETRICA tm;
944 HDC hdc;
945 HFONT hfont;
946 SIZE sz;
947 SIZE sz1, sz2;
948
949 memset(&lf, 0, sizeof(lf));
950 strcpy(lf.lfFaceName, "Arial");
951 lf.lfHeight = 20;
952
953 hfont = CreateFontIndirectA(&lf);
954 hdc = GetDC(0);
955 hfont = SelectObject(hdc, hfont);
956 GetTextMetricsA(hdc, &tm);
957 GetTextExtentPointA(hdc, "o", 1, &sz);
958 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
959
960 SetLastError(0xdeadbeef);
961 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
962 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
963 {
964 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
965 hfont = SelectObject(hdc, hfont);
966 DeleteObject(hfont);
967 ReleaseDC(0, hdc);
968 return;
969 }
970
971 len = lstrlenW(wt);
972 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
973 extents[0] = 1; /* So that the increasing sequence test will fail
974 if the extents array is untouched. */
975 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
976 GetTextExtentPointW(hdc, wt, len, &sz2);
977 ok(sz1.cy == sz2.cy,
978 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
979 /* Because of the '\n' in the string GetTextExtentExPoint and
980 GetTextExtentPoint return different widths under Win2k, but
981 under WinXP they return the same width. So we don't test that
982 here. */
983
984 for (i = 1; i < len; ++i)
985 ok(extents[i-1] <= extents[i],
986 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
987 i);
988 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
989 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
990 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
991 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
992 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
993 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
994 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
995 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
996 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
997 ok(extents[0] == extents[2] && extents[1] == extents[3],
998 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
999 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1000 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1001 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1002 HeapFree(GetProcessHeap(), 0, extents);
1003
1004 hfont = SelectObject(hdc, hfont);
1005 DeleteObject(hfont);
1006 ReleaseDC(NULL, hdc);
1007 }
1008
1009 static void test_GetGlyphIndices(void)
1010 {
1011 HDC hdc;
1012 HFONT hfont;
1013 DWORD charcount;
1014 LOGFONTA lf;
1015 DWORD flags = 0;
1016 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1017 WORD glyphs[(sizeof(testtext)/2)-1];
1018 TEXTMETRIC textm;
1019 HFONT hOldFont;
1020
1021 if (!pGetGlyphIndicesW) {
1022 win_skip("GetGlyphIndicesW not available on platform\n");
1023 return;
1024 }
1025
1026 hdc = GetDC(0);
1027
1028 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1029 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1030 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1031 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1032 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1033 flags = 0;
1034 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1035 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1036 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1037 textm.tmDefaultChar, glyphs[4]);
1038
1039 if(!is_font_installed("Tahoma"))
1040 {
1041 skip("Tahoma is not installed so skipping this test\n");
1042 return;
1043 }
1044 memset(&lf, 0, sizeof(lf));
1045 strcpy(lf.lfFaceName, "Tahoma");
1046 lf.lfHeight = 20;
1047
1048 hfont = CreateFontIndirectA(&lf);
1049 hOldFont = SelectObject(hdc, hfont);
1050 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1051 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1052 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1053 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1054 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1055 flags = 0;
1056 testtext[0] = textm.tmDefaultChar;
1057 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1058 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1059 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1060 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1061 DeleteObject(SelectObject(hdc, hOldFont));
1062 }
1063
1064 static void test_GetKerningPairs(void)
1065 {
1066 static const struct kerning_data
1067 {
1068 const char face_name[LF_FACESIZE];
1069 LONG height;
1070 /* some interesting fields from OUTLINETEXTMETRIC */
1071 LONG tmHeight, tmAscent, tmDescent;
1072 UINT otmEMSquare;
1073 INT otmAscent;
1074 INT otmDescent;
1075 UINT otmLineGap;
1076 UINT otmsCapEmHeight;
1077 UINT otmsXHeight;
1078 INT otmMacAscent;
1079 INT otmMacDescent;
1080 UINT otmMacLineGap;
1081 UINT otmusMinimumPPEM;
1082 /* small subset of kerning pairs to test */
1083 DWORD total_kern_pairs;
1084 const KERNINGPAIR kern_pair[26];
1085 } kd[] =
1086 {
1087 {"Arial", 12, 12, 9, 3,
1088 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1089 26,
1090 {
1091 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1092 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1093 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1094 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1095 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1096 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1097 {933,970,+1},{933,972,-1}
1098 }
1099 },
1100 {"Arial", -34, 39, 32, 7,
1101 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1102 26,
1103 {
1104 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1105 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1106 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1107 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1108 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1109 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1110 {933,970,+2},{933,972,-3}
1111 }
1112 },
1113 { "Arial", 120, 120, 97, 23,
1114 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1115 26,
1116 {
1117 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1118 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1119 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1120 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1121 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1122 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1123 {933,970,+6},{933,972,-10}
1124 }
1125 },
1126 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1127 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1128 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1129 26,
1130 {
1131 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1132 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1133 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1134 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1135 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1136 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1137 {933,970,+54},{933,972,-83}
1138 }
1139 }
1140 #endif
1141 };
1142 LOGFONT lf;
1143 HFONT hfont, hfont_old;
1144 KERNINGPAIR *kern_pair;
1145 HDC hdc;
1146 DWORD total_kern_pairs, ret, i, n, matches;
1147
1148 hdc = GetDC(0);
1149
1150 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1151 * which may render this test unusable, so we're trying to avoid that.
1152 */
1153 SetLastError(0xdeadbeef);
1154 GetKerningPairsW(hdc, 0, NULL);
1155 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1156 {
1157 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1158 ReleaseDC(0, hdc);
1159 return;
1160 }
1161
1162 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1163 {
1164 OUTLINETEXTMETRICW otm;
1165
1166 if (!is_font_installed(kd[i].face_name))
1167 {
1168 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1169 continue;
1170 }
1171
1172 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1173
1174 memset(&lf, 0, sizeof(lf));
1175 strcpy(lf.lfFaceName, kd[i].face_name);
1176 lf.lfHeight = kd[i].height;
1177 hfont = CreateFontIndirect(&lf);
1178 assert(hfont != 0);
1179
1180 hfont_old = SelectObject(hdc, hfont);
1181
1182 SetLastError(0xdeadbeef);
1183 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1184 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1185
1186 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1187 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1188 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1189 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1190 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1191 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1192
1193 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1194 kd[i].otmEMSquare, otm.otmEMSquare);
1195 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1196 kd[i].otmAscent, otm.otmAscent);
1197 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1198 kd[i].otmDescent, otm.otmDescent);
1199 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1200 kd[i].otmLineGap, otm.otmLineGap);
1201 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1202 kd[i].otmMacDescent, otm.otmMacDescent);
1203 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1204 kd[i].otmMacAscent, otm.otmMacAscent);
1205 todo_wine {
1206 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1207 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1208 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1209 kd[i].otmsXHeight, otm.otmsXHeight);
1210 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1211 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1212 kd[i].otmMacLineGap, otm.otmMacLineGap);
1213 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1214 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1215 }
1216
1217 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1218 trace("total_kern_pairs %u\n", total_kern_pairs);
1219 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1220
1221 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1222 SetLastError(0xdeadbeef);
1223 ret = GetKerningPairsW(hdc, 0, kern_pair);
1224 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1225 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1226 ok(ret == 0, "got %lu, expected 0\n", ret);
1227 #endif
1228
1229 ret = GetKerningPairsW(hdc, 100, NULL);
1230 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1231
1232 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1233 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1234
1235 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1236 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1237
1238 matches = 0;
1239
1240 for (n = 0; n < ret; n++)
1241 {
1242 DWORD j;
1243 #if 0
1244 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1245 trace("{'%c','%c',%d},\n",
1246 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1247 #endif
1248 for (j = 0; j < kd[i].total_kern_pairs; j++)
1249 {
1250 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1251 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1252 {
1253 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1254 "pair %d:%d got %d, expected %d\n",
1255 kern_pair[n].wFirst, kern_pair[n].wSecond,
1256 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1257 matches++;
1258 }
1259 }
1260 }
1261
1262 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1263 matches, kd[i].total_kern_pairs);
1264
1265 HeapFree(GetProcessHeap(), 0, kern_pair);
1266
1267 SelectObject(hdc, hfont_old);
1268 DeleteObject(hfont);
1269 }
1270
1271 ReleaseDC(0, hdc);
1272 }
1273
1274 static void test_height_selection(void)
1275 {
1276 static const struct font_data
1277 {
1278 const char face_name[LF_FACESIZE];
1279 int requested_height;
1280 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1281 } fd[] =
1282 {
1283 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1284 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1285 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1286 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1287 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1288 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1289 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1290 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1291 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1292 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1293 };
1294 HDC hdc;
1295 LOGFONT lf;
1296 HFONT hfont, old_hfont;
1297 TEXTMETRIC tm;
1298 INT ret, i;
1299
1300 hdc = CreateCompatibleDC(0);
1301 assert(hdc);
1302
1303 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1304 {
1305 if (!is_truetype_font_installed(fd[i].face_name))
1306 {
1307 skip("%s is not installed\n", fd[i].face_name);
1308 continue;
1309 }
1310
1311 memset(&lf, 0, sizeof(lf));
1312 lf.lfHeight = fd[i].requested_height;
1313 lf.lfWeight = fd[i].weight;
1314 strcpy(lf.lfFaceName, fd[i].face_name);
1315
1316 hfont = CreateFontIndirect(&lf);
1317 assert(hfont);
1318
1319 old_hfont = SelectObject(hdc, hfont);
1320 ret = GetTextMetrics(hdc, &tm);
1321 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1322 if(fd[i].dpi == tm.tmDigitizedAspectX)
1323 {
1324 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1325 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);
1326 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);
1327 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);
1328 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);
1329 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1330 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);
1331 #endif
1332 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);
1333 }
1334
1335 SelectObject(hdc, old_hfont);
1336 DeleteObject(hfont);
1337 }
1338
1339 DeleteDC(hdc);
1340 }
1341
1342 static void test_GetOutlineTextMetrics(void)
1343 {
1344 OUTLINETEXTMETRIC *otm;
1345 LOGFONT lf;
1346 HFONT hfont, hfont_old;
1347 HDC hdc;
1348 DWORD ret, otm_size;
1349 LPSTR unset_ptr;
1350
1351 if (!is_font_installed("Arial"))
1352 {
1353 skip("Arial is not installed\n");
1354 return;
1355 }
1356
1357 hdc = GetDC(0);
1358
1359 memset(&lf, 0, sizeof(lf));
1360 strcpy(lf.lfFaceName, "Arial");
1361 lf.lfHeight = -13;
1362 lf.lfWeight = FW_NORMAL;
1363 lf.lfPitchAndFamily = DEFAULT_PITCH;
1364 lf.lfQuality = PROOF_QUALITY;
1365 hfont = CreateFontIndirect(&lf);
1366 assert(hfont != 0);
1367
1368 hfont_old = SelectObject(hdc, hfont);
1369 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1370 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1371
1372 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1373
1374 memset(otm, 0xAA, otm_size);
1375 SetLastError(0xdeadbeef);
1376 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1377 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1378 ok(ret == 1 /* Win9x */ ||
1379 ret == otm->otmSize /* XP*/,
1380 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1381 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1382 {
1383 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1384 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1385 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1386 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1387 }
1388
1389 memset(otm, 0xAA, otm_size);
1390 SetLastError(0xdeadbeef);
1391 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1392 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1393 ok(ret == 1 /* Win9x */ ||
1394 ret == otm->otmSize /* XP*/,
1395 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1396 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1397 {
1398 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1399 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1400 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1401 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1402 }
1403
1404 /* ask about truncated data */
1405 memset(otm, 0xAA, otm_size);
1406 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1407 SetLastError(0xdeadbeef);
1408 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1409 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1410 ok(ret == 1 /* Win9x */ ||
1411 ret == otm->otmSize /* XP*/,
1412 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1413 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1414 {
1415 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1416 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1417 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1418 }
1419 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1420
1421 HeapFree(GetProcessHeap(), 0, otm);
1422
1423 SelectObject(hdc, hfont_old);
1424 DeleteObject(hfont);
1425
1426 ReleaseDC(0, hdc);
1427 }
1428
1429 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1430 {
1431 INT y,
1432 breakCount,
1433 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1434 areaWidth = clientArea->right - clientArea->left,
1435 nErrors = 0, e;
1436 BOOL lastExtent = FALSE;
1437 PSTR pFirstChar, pLastChar;
1438 SIZE size;
1439 TEXTMETRICA tm;
1440 struct err
1441 {
1442 char extent[100];
1443 int GetTextExtentExPointWWidth;
1444 } error[10];
1445
1446 GetTextMetricsA(hdc, &tm);
1447 y = clientArea->top;
1448 do {
1449 breakCount = 0;
1450 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1451 pFirstChar = str;
1452
1453 do {
1454 pLastChar = str;
1455
1456 /* if not at the end of the string, ... */
1457 if (*str == '\0') break;
1458 /* ... add the next word to the current extent */
1459 while (*str != '\0' && *str++ != tm.tmBreakChar);
1460 breakCount++;
1461 SetTextJustification(hdc, 0, 0);
1462 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1463 } while ((int) size.cx < areaWidth);
1464
1465 /* ignore trailing break chars */
1466 breakCount--;
1467 while (*(pLastChar - 1) == tm.tmBreakChar)
1468 {
1469 pLastChar--;
1470 breakCount--;
1471 }
1472
1473 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1474
1475 SetTextJustification(hdc, 0, 0);
1476 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1477
1478 /* do not justify the last extent */
1479 if (*str != '\0' && breakCount > 0)
1480 {
1481 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1482 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1483 justifiedWidth = size.cx;
1484 }
1485 else lastExtent = TRUE;
1486
1487 /* catch errors and report them */
1488 if (!lastExtent && (justifiedWidth != areaWidth))
1489 {
1490 memset(error[nErrors].extent, 0, 100);
1491 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1492 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1493 nErrors++;
1494 }
1495
1496 y += size.cy;
1497 str = pLastChar;
1498 } while (*str && y < clientArea->bottom);
1499
1500 for (e = 0; e < nErrors; e++)
1501 {
1502 /* The width returned by GetTextExtentPoint32() is exactly the same
1503 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1504 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1505 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1506 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1507 }
1508 }
1509
1510 static void test_SetTextJustification(void)
1511 {
1512 HDC hdc;
1513 RECT clientArea;
1514 LOGFONTA lf;
1515 HFONT hfont;
1516 HWND hwnd;
1517 static char testText[] =
1518 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1519 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1520 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1521 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1522 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1523 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1524 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1525
1526 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1527 GetClientRect( hwnd, &clientArea );
1528 hdc = GetDC( hwnd );
1529
1530 memset(&lf, 0, sizeof lf);
1531 lf.lfCharSet = ANSI_CHARSET;
1532 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1533 lf.lfWeight = FW_DONTCARE;
1534 lf.lfHeight = 20;
1535 lf.lfQuality = DEFAULT_QUALITY;
1536 lstrcpyA(lf.lfFaceName, "Times New Roman");
1537 hfont = create_font("Times New Roman", &lf);
1538 SelectObject(hdc, hfont);
1539
1540 testJustification(hdc, testText, &clientArea);
1541
1542 DeleteObject(hfont);
1543 ReleaseDC(hwnd, hdc);
1544 DestroyWindow(hwnd);
1545 }
1546
1547 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1548 {
1549 HDC hdc;
1550 LOGFONTA lf;
1551 HFONT hfont, hfont_old;
1552 CHARSETINFO csi;
1553 FONTSIGNATURE fs;
1554 INT cs;
1555 DWORD i, ret;
1556 char name[64];
1557
1558 assert(count <= 128);
1559
1560 memset(&lf, 0, sizeof(lf));
1561
1562 lf.lfCharSet = charset;
1563 lf.lfHeight = 10;
1564 lstrcpyA(lf.lfFaceName, "Arial");
1565 SetLastError(0xdeadbeef);
1566 hfont = CreateFontIndirectA(&lf);
1567 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1568
1569 hdc = GetDC(0);
1570 hfont_old = SelectObject(hdc, hfont);
1571
1572 cs = GetTextCharsetInfo(hdc, &fs, 0);
1573 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1574
1575 SetLastError(0xdeadbeef);
1576 ret = GetTextFaceA(hdc, sizeof(name), name);
1577 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1578
1579 if (charset == SYMBOL_CHARSET)
1580 {
1581 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1582 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1583 }
1584 else
1585 {
1586 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1587 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1588 }
1589
1590 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1591 {
1592 trace("Can't find codepage for charset %d\n", cs);
1593 ReleaseDC(0, hdc);
1594 return FALSE;
1595 }
1596 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1597
1598 if (unicode)
1599 {
1600 char ansi_buf[128];
1601 WCHAR unicode_buf[128];
1602
1603 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1604
1605 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1606
1607 SetLastError(0xdeadbeef);
1608 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1609 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1610 }
1611 else
1612 {
1613 char ansi_buf[128];
1614
1615 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1616
1617 SetLastError(0xdeadbeef);
1618 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1619 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1620 }
1621
1622 SelectObject(hdc, hfont_old);
1623 DeleteObject(hfont);
1624
1625 ReleaseDC(0, hdc);
1626
1627 return TRUE;
1628 }
1629
1630 static void test_font_charset(void)
1631 {
1632 static struct charset_data
1633 {
1634 INT charset;
1635 UINT code_page;
1636 WORD font_idxA[128], font_idxW[128];
1637 } cd[] =
1638 {
1639 { ANSI_CHARSET, 1252 },
1640 { RUSSIAN_CHARSET, 1251 },
1641 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1642 };
1643 int i;
1644
1645 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1646 {
1647 win_skip("Skipping the font charset test on a Win9x platform\n");
1648 return;
1649 }
1650
1651 if (!is_font_installed("Arial"))
1652 {
1653 skip("Arial is not installed\n");
1654 return;
1655 }
1656
1657 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1658 {
1659 if (cd[i].charset == SYMBOL_CHARSET)
1660 {
1661 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1662 {
1663 skip("Symbol or Wingdings is not installed\n");
1664 break;
1665 }
1666 }
1667 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1668 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1669 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1670 }
1671
1672 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1673 if (i > 2)
1674 {
1675 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1676 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1677 }
1678 else
1679 skip("Symbol or Wingdings is not installed\n");
1680 }
1681
1682 static void test_GetFontUnicodeRanges(void)
1683 {
1684 LOGFONTA lf;
1685 HDC hdc;
1686 HFONT hfont, hfont_old;
1687 DWORD size;
1688 GLYPHSET *gs;
1689
1690 if (!pGetFontUnicodeRanges)
1691 {
1692 win_skip("GetFontUnicodeRanges not available before W2K\n");
1693 return;
1694 }
1695
1696 memset(&lf, 0, sizeof(lf));
1697 lstrcpyA(lf.lfFaceName, "Arial");
1698 hfont = create_font("Arial", &lf);
1699
1700 hdc = GetDC(0);
1701 hfont_old = SelectObject(hdc, hfont);
1702
1703 size = pGetFontUnicodeRanges(NULL, NULL);
1704 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1705
1706 size = pGetFontUnicodeRanges(hdc, NULL);
1707 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1708
1709 gs = HeapAlloc(GetProcessHeap(), 0, size);
1710
1711 size = pGetFontUnicodeRanges(hdc, gs);
1712 ok(size, "GetFontUnicodeRanges failed\n");
1713 #if 0
1714 for (i = 0; i < gs->cRanges; i++)
1715 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1716 #endif
1717 trace("found %u ranges\n", gs->cRanges);
1718
1719 HeapFree(GetProcessHeap(), 0, gs);
1720
1721 SelectObject(hdc, hfont_old);
1722 DeleteObject(hfont);
1723 ReleaseDC(NULL, hdc);
1724 }
1725
1726 #define MAX_ENUM_FONTS 4096
1727
1728 struct enum_font_data
1729 {
1730 int total;
1731 LOGFONT lf[MAX_ENUM_FONTS];
1732 };
1733
1734 struct enum_font_dataW
1735 {
1736 int total;
1737 LOGFONTW lf[MAX_ENUM_FONTS];
1738 };
1739
1740 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1741 {
1742 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1743
1744 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1745
1746 if (type != TRUETYPE_FONTTYPE) return 1;
1747 #if 0
1748 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1749 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1750 #endif
1751 if (efd->total < MAX_ENUM_FONTS)
1752 efd->lf[efd->total++] = *lf;
1753 else
1754 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1755
1756 return 1;
1757 }
1758
1759 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1760 {
1761 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1762
1763 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1764
1765 if (type != TRUETYPE_FONTTYPE) return 1;
1766 #if 0
1767 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1768 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1769 #endif
1770 if (efd->total < MAX_ENUM_FONTS)
1771 efd->lf[efd->total++] = *lf;
1772 else
1773 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1774
1775 return 1;
1776 }
1777
1778 static void get_charset_stats(struct enum_font_data *efd,
1779 int *ansi_charset, int *symbol_charset,
1780 int *russian_charset)
1781 {
1782 int i;
1783
1784 *ansi_charset = 0;
1785 *symbol_charset = 0;
1786 *russian_charset = 0;
1787
1788 for (i = 0; i < efd->total; i++)
1789 {
1790 switch (efd->lf[i].lfCharSet)
1791 {
1792 case ANSI_CHARSET:
1793 (*ansi_charset)++;
1794 break;
1795 case SYMBOL_CHARSET:
1796 (*symbol_charset)++;
1797 break;
1798 case RUSSIAN_CHARSET:
1799 (*russian_charset)++;
1800 break;
1801 }
1802 }
1803 }
1804
1805 static void get_charset_statsW(struct enum_font_dataW *efd,
1806 int *ansi_charset, int *symbol_charset,
1807 int *russian_charset)
1808 {
1809 int i;
1810
1811 *ansi_charset = 0;
1812 *symbol_charset = 0;
1813 *russian_charset = 0;
1814
1815 for (i = 0; i < efd->total; i++)
1816 {
1817 switch (efd->lf[i].lfCharSet)
1818 {
1819 case ANSI_CHARSET:
1820 (*ansi_charset)++;
1821 break;
1822 case SYMBOL_CHARSET:
1823 (*symbol_charset)++;
1824 break;
1825 case RUSSIAN_CHARSET:
1826 (*russian_charset)++;
1827 break;
1828 }
1829 }
1830 }
1831
1832 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1833 {
1834 struct enum_font_data efd;
1835 struct enum_font_dataW efdw;
1836 LOGFONT lf;
1837 HDC hdc;
1838 int i, ret, ansi_charset, symbol_charset, russian_charset;
1839
1840 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1841
1842 if (*font_name && !is_truetype_font_installed(font_name))
1843 {
1844 skip("%s is not installed\n", font_name);
1845 return;
1846 }
1847
1848 hdc = GetDC(0);
1849
1850 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1851 * while EnumFontFamiliesEx doesn't.
1852 */
1853 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1854 {
1855 /*
1856 * Use EnumFontFamiliesW since win98 crashes when the
1857 * second parameter is NULL using EnumFontFamilies
1858 */
1859 efdw.total = 0;
1860 SetLastError(0xdeadbeef);
1861 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1862 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1863 if(ret)
1864 {
1865 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1866 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1867 ansi_charset, symbol_charset, russian_charset);
1868 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1869 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1870 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1871 ok(russian_charset > 0 ||
1872 broken(russian_charset == 0), /* NT4 */
1873 "NULL family should enumerate RUSSIAN_CHARSET\n");
1874 }
1875
1876 efdw.total = 0;
1877 SetLastError(0xdeadbeef);
1878 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1879 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1880 if(ret)
1881 {
1882 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1883 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1884 ansi_charset, symbol_charset, russian_charset);
1885 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1886 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1887 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1888 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1889 }
1890 }
1891
1892 efd.total = 0;
1893 SetLastError(0xdeadbeef);
1894 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1895 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1896 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1897 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1898 ansi_charset, symbol_charset, russian_charset,
1899 *font_name ? font_name : "<empty>");
1900 if (*font_name)
1901 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1902 else
1903 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1904 for (i = 0; i < efd.total; i++)
1905 {
1906 /* FIXME: remove completely once Wine is fixed */
1907 if (efd.lf[i].lfCharSet != font_charset)
1908 {
1909 todo_wine
1910 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1911 }
1912 else
1913 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1914 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1915 font_name, efd.lf[i].lfFaceName);
1916 }
1917
1918 memset(&lf, 0, sizeof(lf));
1919 lf.lfCharSet = ANSI_CHARSET;
1920 lstrcpy(lf.lfFaceName, font_name);
1921 efd.total = 0;
1922 SetLastError(0xdeadbeef);
1923 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1924 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1925 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1926 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1927 ansi_charset, symbol_charset, russian_charset,
1928 *font_name ? font_name : "<empty>");
1929 if (font_charset == SYMBOL_CHARSET)
1930 {
1931 if (*font_name)
1932 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1933 else
1934 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1935 }
1936 else
1937 {
1938 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1939 for (i = 0; i < efd.total; i++)
1940 {
1941 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1942 if (*font_name)
1943 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1944 font_name, efd.lf[i].lfFaceName);
1945 }
1946 }
1947
1948 /* DEFAULT_CHARSET should enumerate all available charsets */
1949 memset(&lf, 0, sizeof(lf));
1950 lf.lfCharSet = DEFAULT_CHARSET;
1951 lstrcpy(lf.lfFaceName, font_name);
1952 efd.total = 0;
1953 SetLastError(0xdeadbeef);
1954 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1955 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1956 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1957 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1958 ansi_charset, symbol_charset, russian_charset,
1959 *font_name ? font_name : "<empty>");
1960 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1961 for (i = 0; i < efd.total; i++)
1962 {
1963 if (*font_name)
1964 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1965 font_name, efd.lf[i].lfFaceName);
1966 }
1967 if (*font_name)
1968 {
1969 switch (font_charset)
1970 {
1971 case ANSI_CHARSET:
1972 ok(ansi_charset > 0,
1973 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1974 ok(!symbol_charset,
1975 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1976 ok(russian_charset > 0,
1977 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1978 break;
1979 case SYMBOL_CHARSET:
1980 ok(!ansi_charset,
1981 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1982 ok(symbol_charset,
1983 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1984 ok(!russian_charset,
1985 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1986 break;
1987 case DEFAULT_CHARSET:
1988 ok(ansi_charset > 0,
1989 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1990 ok(symbol_charset > 0,
1991 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1992 ok(russian_charset > 0,
1993 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1994 break;
1995 }
1996 }
1997 else
1998 {
1999 ok(ansi_charset > 0,
2000 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2001 ok(symbol_charset > 0,
2002 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2003 ok(russian_charset > 0,
2004 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2005 }
2006
2007 memset(&lf, 0, sizeof(lf));
2008 lf.lfCharSet = SYMBOL_CHARSET;
2009 lstrcpy(lf.lfFaceName, font_name);
2010 efd.total = 0;
2011 SetLastError(0xdeadbeef);
2012 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2013 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2014 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2015 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2016 ansi_charset, symbol_charset, russian_charset,
2017 *font_name ? font_name : "<empty>");
2018 if (*font_name && font_charset == ANSI_CHARSET)
2019 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2020 else
2021 {
2022 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2023 for (i = 0; i < efd.total; i++)
2024 {
2025 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2026 if (*font_name)
2027 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2028 font_name, efd.lf[i].lfFaceName);
2029 }
2030
2031 ok(!ansi_charset,
2032 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2033 ok(symbol_charset > 0,
2034 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2035 ok(!russian_charset,
2036 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2037 }
2038
2039 ReleaseDC(0, hdc);
2040 }
2041
2042 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2043 {
2044 HFONT hfont, hfont_prev;
2045 DWORD ret;
2046 GLYPHMETRICS gm1, gm2;
2047 LOGFONTA lf2 = *lf;
2048 WORD idx;
2049 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2050
2051 if(!pGetGlyphIndicesA)
2052 return;
2053
2054 /* negative widths are handled just as positive ones */
2055 lf2.lfWidth = -lf->lfWidth;
2056
2057 SetLastError(0xdeadbeef);
2058 hfont = CreateFontIndirectA(lf);
2059 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2060 check_font("original", lf, hfont);
2061
2062 hfont_prev = SelectObject(hdc, hfont);
2063
2064 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2065 if (ret == GDI_ERROR || idx == 0xffff)
2066 {
2067 SelectObject(hdc, hfont_prev);
2068 DeleteObject(hfont);
2069 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2070 return;
2071 }
2072
2073 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2074 memset(&gm1, 0xab, sizeof(gm1));
2075 SetLastError(0xdeadbeef);
2076 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2077 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2078
2079 SelectObject(hdc, hfont_prev);
2080 DeleteObject(hfont);
2081
2082 SetLastError(0xdeadbeef);
2083 hfont = CreateFontIndirectA(&lf2);
2084 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2085 check_font("negative width", &lf2, hfont);
2086
2087 hfont_prev = SelectObject(hdc, hfont);
2088
2089 memset(&gm2, 0xbb, sizeof(gm2));
2090 SetLastError(0xdeadbeef);
2091 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2092 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2093
2094 SelectObject(hdc, hfont_prev);
2095 DeleteObject(hfont);
2096
2097 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2098 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2099 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2100 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2101 gm1.gmCellIncX == gm2.gmCellIncX &&
2102 gm1.gmCellIncY == gm2.gmCellIncY,
2103 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2104 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2105 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2106 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2107 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2108 }
2109
2110 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2111 #include "pshpack2.h"
2112 typedef struct
2113 {
2114 USHORT version;
2115 SHORT xAvgCharWidth;
2116 USHORT usWeightClass;
2117 USHORT usWidthClass;
2118 SHORT fsType;
2119 SHORT ySubscriptXSize;
2120 SHORT ySubscriptYSize;
2121 SHORT ySubscriptXOffset;
2122 SHORT ySubscriptYOffset;
2123 SHORT ySuperscriptXSize;
2124 SHORT ySuperscriptYSize;
2125 SHORT ySuperscriptXOffset;
2126 SHORT ySuperscriptYOffset;
2127 SHORT yStrikeoutSize;
2128 SHORT yStrikeoutPosition;
2129 SHORT sFamilyClass;
2130 PANOSE panose;
2131 ULONG ulUnicodeRange1;
2132 ULONG ulUnicodeRange2;
2133 ULONG ulUnicodeRange3;
2134 ULONG ulUnicodeRange4;
2135 CHAR achVendID[4];
2136 USHORT fsSelection;
2137 USHORT usFirstCharIndex;
2138 USHORT usLastCharIndex;
2139 /* According to the Apple spec, original version didn't have the below fields,
2140 * version numbers were taked from the OpenType spec.
2141 */
2142 /* version 0 (TrueType 1.5) */
2143 USHORT sTypoAscender;
2144 USHORT sTypoDescender;
2145 USHORT sTypoLineGap;
2146 USHORT usWinAscent;
2147 USHORT usWinDescent;
2148 /* version 1 (TrueType 1.66) */
2149 ULONG ulCodePageRange1;
2150 ULONG ulCodePageRange2;
2151 /* version 2 (OpenType 1.2) */
2152 SHORT sxHeight;
2153 SHORT sCapHeight;
2154 USHORT usDefaultChar;
2155 USHORT usBreakChar;
2156 USHORT usMaxContext;
2157 } TT_OS2_V2;
2158 #include "poppack.h"
2159
2160 #ifdef WORDS_BIGENDIAN
2161 #define GET_BE_WORD(x) (x)
2162 #define GET_BE_DWORD(x) (x)
2163 #else
2164 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2165 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2166 #endif
2167
2168 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2169 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2170 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2171 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2172 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2173
2174 typedef struct
2175 {
2176 USHORT version;
2177 USHORT num_tables;
2178 } cmap_header;
2179
2180 typedef struct
2181 {
2182 USHORT plat_id;
2183 USHORT enc_id;
2184 ULONG offset;
2185 } cmap_encoding_record;
2186
2187 typedef struct
2188 {
2189 USHORT format;
2190 USHORT length;
2191 USHORT language;
2192
2193 BYTE glyph_ids[256];
2194 } cmap_format_0;
2195
2196 typedef struct
2197 {
2198 USHORT format;
2199 USHORT length;
2200 USHORT language;
2201
2202 USHORT seg_countx2;
2203 USHORT search_range;
2204 USHORT entry_selector;
2205 USHORT range_shift;
2206
2207 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2208 /* Then follows:
2209 USHORT pad;
2210 USHORT start_count[seg_countx2 / 2];
2211 USHORT id_delta[seg_countx2 / 2];
2212 USHORT id_range_offset[seg_countx2 / 2];
2213 USHORT glyph_ids[];
2214 */
2215 } cmap_format_4;
2216
2217 typedef struct
2218 {
2219 USHORT end_count;
2220 USHORT start_count;
2221 USHORT id_delta;
2222 USHORT id_range_offset;
2223 } cmap_format_4_seg;
2224
2225 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2226 {
2227 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2228 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2229 os2->panose.bWeight, os2->panose.bProportion);
2230 }
2231
2232 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2233 {
2234 int i;
2235 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2236
2237 *first = 256;
2238
2239 for(i = 0; i < 256; i++)
2240 {
2241 if(cmap->glyph_ids[i] == 0) continue;
2242 *last = i;
2243 if(*first == 256) *first = i;
2244 }
2245 if(*first == 256) return FALSE;
2246 return TRUE;
2247 }
2248
2249 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2250 {
2251 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2252 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2253 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2254 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2255 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2256 }
2257
2258 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2259 {
2260 int i;
2261 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2262 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2263 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2264
2265 *first = 0x10000;
2266
2267 for(i = 0; i < seg_count; i++)
2268 {
2269 DWORD code, index;
2270 cmap_format_4_seg seg;
2271
2272 get_seg4(cmap, i, &seg);
2273 for(code = seg.start_count; code <= seg.end_count; code++)
2274 {
2275 if(seg.id_range_offset == 0)
2276 index = (seg.id_delta + code) & 0xffff;
2277 else
2278 {
2279 index = seg.id_range_offset / 2
2280 + code - seg.start_count
2281 + i - seg_count;
2282
2283 /* some fonts have broken last segment */
2284 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2285 index = GET_BE_WORD(glyph_ids[index]);
2286 else
2287 {
2288 trace("segment %04x/%04x index %04x points to nowhere\n",
2289 seg.start_count, seg.end_count, index);
2290 index = 0;
2291 }
2292 if(index) index += seg.id_delta;
2293 }
2294 if(*first == 0x10000)
2295 *last = *first = code;
2296 else if(index)
2297 *last = code;
2298 }
2299 }
2300
2301 if(*first == 0x10000) return FALSE;
2302 return TRUE;
2303 }
2304
2305 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2306 {
2307 USHORT i;
2308 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2309
2310 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2311 {
2312 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2313 return (BYTE *)header + GET_BE_DWORD(record->offset);
2314 record++;
2315 }
2316 return NULL;
2317 }
2318
2319 typedef enum
2320 {
2321 cmap_none,
2322 cmap_ms_unicode,
2323 cmap_ms_symbol
2324 } cmap_type;
2325
2326 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2327 {
2328 LONG size, ret;
2329 cmap_header *header;
2330 void *cmap;
2331 BOOL r = FALSE;
2332 WORD format;
2333
2334 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2335 ok(size != GDI_ERROR, "no cmap table found\n");
2336 if(size == GDI_ERROR) return FALSE;
2337
2338 header = HeapAlloc(GetProcessHeap(), 0, size);
2339 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2340 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2341 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2342
2343 cmap = get_cmap(header, 3, 1);
2344 if(cmap)
2345 *cmap_type = cmap_ms_unicode;
2346 else
2347 {
2348 cmap = get_cmap(header, 3, 0);
2349 if(cmap) *cmap_type = cmap_ms_symbol;
2350 }
2351 if(!cmap)
2352 {
2353 *cmap_type = cmap_none;
2354 goto end;
2355 }
2356
2357 format = GET_BE_WORD(*(WORD *)cmap);
2358 switch(format)
2359 {
2360 case 0:
2361 r = get_first_last_from_cmap0(cmap, first, last);
2362 break;
2363 case 4:
2364 r = get_first_last_from_cmap4(cmap, first, last, size);
2365 break;
2366 default:
2367 trace("unhandled cmap format %d\n", format);
2368 break;
2369 }
2370
2371 end:
2372 HeapFree(GetProcessHeap(), 0, header);
2373 return r;
2374 }
2375
2376 static void test_text_metrics(const LOGFONTA *lf)
2377 {
2378 HDC hdc;
2379 HFONT hfont, hfont_old;
2380 TEXTMETRICA tmA;
2381 TT_OS2_V2 tt_os2;
2382 LONG size, ret;
2383 const char *font_name = lf->lfFaceName;
2384 DWORD cmap_first = 0, cmap_last = 0;
2385 cmap_type cmap_type;
2386
2387 hdc = GetDC(0);
2388
2389 SetLastError(0xdeadbeef);
2390 hfont = CreateFontIndirectA(lf);
2391 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2392
2393 hfont_old = SelectObject(hdc, hfont);
2394
2395 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2396 if (size == GDI_ERROR)
2397 {
2398 trace("OS/2 chunk was not found\n");
2399 goto end_of_test;
2400 }
2401 if (size > sizeof(tt_os2))
2402 {
2403 trace("got too large OS/2 chunk of size %u\n", size);
2404 size = sizeof(tt_os2);
2405 }
2406
2407 memset(&tt_os2, 0, sizeof(tt_os2));
2408 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2409 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2410
2411 SetLastError(0xdeadbeef);
2412 ret = GetTextMetricsA(hdc, &tmA);
2413 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2414
2415 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2416 {
2417 skip("Unable to retrieve first and last glyphs from cmap\n");
2418 }
2419 else
2420 {
2421 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2422 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2423 UINT os2_first_char, os2_last_char, default_char, break_char;
2424 USHORT version;
2425 TEXTMETRICW tmW;
2426
2427 version = GET_BE_WORD(tt_os2.version);
2428
2429 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2430 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2431 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2432 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2433
2434 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2435 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2436 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2437
2438 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2439 {
2440 expect_first_W = 0;
2441 switch(GetACP())
2442 {
2443 case 1257: /* Baltic */
2444 expect_last_W = 0xf8fd;
2445 break;
2446 default:
2447 expect_last_W = 0xf0ff;
2448 }
2449 expect_break_W = 0x20;
2450 expect_default_W = expect_break_W - 1;
2451 expect_first_A = 0x1e;
2452 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2453 }
2454 else
2455 {
2456 expect_first_W = cmap_first;
2457 expect_last_W = min(cmap_last, os2_last_char);
2458 if(os2_first_char <= 1)
2459 expect_break_W = os2_first_char + 2;
2460 else if(os2_first_char > 0xff)
2461 expect_break_W = 0x20;
2462 else
2463 expect_break_W = os2_first_char;
2464 expect_default_W = expect_break_W - 1;
2465 expect_first_A = expect_default_W - 1;
2466 expect_last_A = min(expect_last_W, 0xff);
2467 }
2468 expect_break_A = expect_break_W;
2469 expect_default_A = expect_default_W;
2470
2471 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2472 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2473 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2474 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2475 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2476 else
2477 ok(tmA.tmFirstChar == expect_first_A ||
2478 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2479 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2480 ok(tmA.tmLastChar == expect_last_A ||
2481 tmA.tmLastChar == 0xff /* win9x */,
2482 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2483 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2484 font_name, tmA.tmBreakChar, expect_break_A);
2485 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2486 font_name, tmA.tmDefaultChar, expect_default_A);
2487
2488
2489 SetLastError(0xdeadbeef);
2490 ret = GetTextMetricsW(hdc, &tmW);
2491 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2492 "GetTextMetricsW error %u\n", GetLastError());
2493 if (ret)
2494 {
2495 /* Wine uses the os2 first char */
2496 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2497 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2498 font_name, tmW.tmFirstChar, expect_first_W);
2499 else
2500 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2501 font_name, tmW.tmFirstChar, expect_first_W);
2502
2503 /* Wine uses the os2 last char */
2504 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2505 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2506 font_name, tmW.tmLastChar, expect_last_W);
2507 else
2508 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2509 font_name, tmW.tmLastChar, expect_last_W);
2510 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2511 font_name, tmW.tmBreakChar, expect_break_W);
2512 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2513 font_name, tmW.tmDefaultChar, expect_default_W);
2514
2515 /* Test the aspect ratio while we have tmW */
2516 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2517 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2518 tmW.tmDigitizedAspectX, ret);
2519 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2520 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2521 tmW.tmDigitizedAspectX, ret);
2522 }
2523 }
2524
2525 /* test FF_ values */
2526 switch(tt_os2.panose.bFamilyType)
2527 {
2528 case PAN_ANY:
2529 case PAN_NO_FIT:
2530 case PAN_FAMILY_TEXT_DISPLAY:
2531 case PAN_FAMILY_PICTORIAL:
2532 default:
2533 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2534 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2535 {
2536 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2537 break;
2538 }
2539 switch(tt_os2.panose.bSerifStyle)
2540 {
2541 case PAN_ANY:
2542 case PAN_NO_FIT:
2543 default:
2544 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2545 break;
2546
2547 case PAN_SERIF_COVE:
2548 case PAN_SERIF_OBTUSE_COVE:
2549 case PAN_SERIF_SQUARE_COVE:
2550 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2551 case PAN_SERIF_SQUARE:
2552 case PAN_SERIF_THIN:
2553 case PAN_SERIF_BONE:
2554 case PAN_SERIF_EXAGGERATED:
2555 case PAN_SERIF_TRIANGLE:
2556 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2557 break;
2558
2559 case PAN_SERIF_NORMAL_SANS:
2560 case PAN_SERIF_OBTUSE_SANS:
2561 case PAN_SERIF_PERP_SANS:
2562 case PAN_SERIF_FLARED:
2563 case PAN_SERIF_ROUNDED:
2564 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2565 break;
2566 }
2567 break;
2568
2569 case PAN_FAMILY_SCRIPT:
2570 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2571 break;
2572
2573 case PAN_FAMILY_DECORATIVE:
2574 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2575 break;
2576 }
2577
2578 test_negative_width(hdc, lf);
2579
2580 end_of_test:
2581 SelectObject(hdc, hfont_old);
2582 DeleteObject(hfont);
2583
2584 ReleaseDC(0, hdc);
2585 }
2586
2587 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2588 {
2589 INT *enumed = (INT *)lParam;
2590
2591 if (type == TRUETYPE_FONTTYPE)
2592 {
2593 (*enumed)++;
2594 test_text_metrics(lf);
2595 }
2596 return 1;
2597 }
2598
2599 static void test_GetTextMetrics(void)
2600 {
2601 LOGFONTA lf;
2602 HDC hdc;
2603 INT enumed;
2604
2605 /* Report only once */
2606 if(!pGetGlyphIndicesA)
2607 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2608
2609 hdc = GetDC(0);
2610
2611 memset(&lf, 0, sizeof(lf));
2612 lf.lfCharSet = DEFAULT_CHARSET;
2613 enumed = 0;
2614 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2615 trace("Tested metrics of %d truetype fonts\n", enumed);
2616
2617 ReleaseDC(0, hdc);
2618 }
2619
2620 static void test_nonexistent_font(void)
2621 {
2622 static const struct
2623 {
2624 const char *name;
2625 int charset;
2626 } font_subst[] =
2627 {
2628 { "Times New Roman Baltic", 186 },
2629 { "Times New Roman CE", 238 },
2630 { "Times New Roman CYR", 204 },
2631 { "Times New Roman Greek", 161 },
2632 { "Times New Roman TUR", 162 }
2633 };
2634 LOGFONTA lf;
2635 HDC hdc;
2636 HFONT hfont;
2637 CHARSETINFO csi;
2638 INT cs, expected_cs, i;
2639 char buf[LF_FACESIZE];
2640
2641 if (!is_truetype_font_installed("Arial") ||
2642 !is_truetype_font_installed("Times New Roman"))
2643 {
2644 skip("Arial or Times New Roman not installed\n");
2645 return;
2646 }
2647
2648 expected_cs = GetACP();
2649 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2650 {
2651 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2652 return;
2653 }
2654 expected_cs = csi.ciCharset;
2655 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2656
2657 hdc = GetDC(0);
2658
2659 memset(&lf, 0, sizeof(lf));
2660 lf.lfHeight = 100;
2661 lf.lfWeight = FW_REGULAR;
2662 lf.lfCharSet = ANSI_CHARSET;
2663 lf.lfPitchAndFamily = FF_SWISS;
2664 strcpy(lf.lfFaceName, "Nonexistent font");
2665 hfont = CreateFontIndirectA(&lf);
2666 hfont = SelectObject(hdc, hfont);
2667 GetTextFaceA(hdc, sizeof(buf), buf);
2668 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2669 cs = GetTextCharset(hdc);
2670 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2671 DeleteObject(SelectObject(hdc, hfont));
2672
2673 memset(&lf, 0, sizeof(lf));
2674 lf.lfHeight = -13;
2675 lf.lfWeight = FW_DONTCARE;
2676 strcpy(lf.lfFaceName, "Nonexistent font");
2677 hfont = CreateFontIndirectA(&lf);
2678 hfont = SelectObject(hdc, hfont);
2679 GetTextFaceA(hdc, sizeof(buf), buf);
2680 todo_wine /* Wine uses Arial for all substitutions */
2681 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2682 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2683 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2684 "Got %s\n", buf);
2685 cs = GetTextCharset(hdc);
2686 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2687 DeleteObject(SelectObject(hdc, hfont));
2688
2689 memset(&lf, 0, sizeof(lf));
2690 lf.lfHeight = -13;
2691 lf.lfWeight = FW_REGULAR;
2692 strcpy(lf.lfFaceName, "Nonexistent font");
2693 hfont = CreateFontIndirectA(&lf);
2694 hfont = SelectObject(hdc, hfont);
2695 GetTextFaceA(hdc, sizeof(buf), buf);
2696 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2697 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2698 cs = GetTextCharset(hdc);
2699 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2700 DeleteObject(SelectObject(hdc, hfont));
2701
2702 memset(&lf, 0, sizeof(lf));
2703 lf.lfHeight = -13;
2704 lf.lfWeight = FW_DONTCARE;
2705 strcpy(lf.lfFaceName, "Times New Roman");
2706 hfont = CreateFontIndirectA(&lf);
2707 hfont = SelectObject(hdc, hfont);
2708 GetTextFaceA(hdc, sizeof(buf), buf);
2709 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2710 cs = GetTextCharset(hdc);
2711 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2712 DeleteObject(SelectObject(hdc, hfont));
2713
2714 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2715 {
2716 memset(&lf, 0, sizeof(lf));
2717 lf.lfHeight = -13;
2718 lf.lfWeight = FW_REGULAR;
2719 strcpy(lf.lfFaceName, font_subst[i].name);
2720 hfont = CreateFontIndirectA(&lf);
2721 hfont = SelectObject(hdc, hfont);
2722 cs = GetTextCharset(hdc);
2723 if (font_subst[i].charset == expected_cs)
2724 {
2725 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2726 GetTextFaceA(hdc, sizeof(buf), buf);
2727 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2728 }
2729 else
2730 {
2731 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2732 GetTextFaceA(hdc, sizeof(buf), buf);
2733 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2734 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2735 }
2736 DeleteObject(SelectObject(hdc, hfont));
2737
2738 memset(&lf, 0, sizeof(lf));
2739 lf.lfHeight = -13;
2740 lf.lfWeight = FW_DONTCARE;
2741 strcpy(lf.lfFaceName, font_subst[i].name);
2742 hfont = CreateFontIndirectA(&lf);
2743 hfont = SelectObject(hdc, hfont);
2744 GetTextFaceA(hdc, sizeof(buf), buf);
2745 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2746 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2747 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2748 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2749 "got %s for font %s\n", buf, font_subst[i].name);
2750 cs = GetTextCharset(hdc);
2751 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2752 DeleteObject(SelectObject(hdc, hfont));
2753 }
2754
2755 ReleaseDC(0, hdc);
2756 }
2757
2758 static void test_GdiRealizationInfo(void)
2759 {
2760 HDC hdc;
2761 DWORD info[4];
2762 BOOL r;
2763 HFONT hfont, hfont_old;
2764 LOGFONTA lf;
2765
2766 if(!pGdiRealizationInfo)
2767 {
2768 win_skip("GdiRealizationInfo not available\n");
2769 return;
2770 }
2771
2772 hdc = GetDC(0);
2773
2774 memset(info, 0xcc, sizeof(info));
2775 r = pGdiRealizationInfo(hdc, info);
2776 ok(r != 0, "ret 0\n");
2777 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2778 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2779
2780 if (!is_truetype_font_installed("Arial"))
2781 {
2782 skip("skipping GdiRealizationInfo with truetype font\n");
2783 goto end;
2784 }
2785
2786 memset(&lf, 0, sizeof(lf));
2787 strcpy(lf.lfFaceName, "Arial");
2788 lf.lfHeight = 20;
2789 lf.lfWeight = FW_NORMAL;
2790 hfont = CreateFontIndirectA(&lf);
2791 hfont_old = SelectObject(hdc, hfont);
2792
2793 memset(info, 0xcc, sizeof(info));
2794 r = pGdiRealizationInfo(hdc, info);
2795 ok(r != 0, "ret 0\n");
2796 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2797 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2798
2799 DeleteObject(SelectObject(hdc, hfont_old));
2800
2801 end:
2802 ReleaseDC(0, hdc);
2803 }
2804
2805 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2806 the nul in the count of characters copied when the face name buffer is not
2807 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2808 always includes it. */
2809 static void test_GetTextFace(void)
2810 {
2811 static const char faceA[] = "Tahoma";
2812 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2813 LOGFONTA fA = {0};
2814 LOGFONTW fW = {0};
2815 char bufA[LF_FACESIZE];
2816 WCHAR bufW[LF_FACESIZE];
2817 HFONT f, g;
2818 HDC dc;
2819 int n;
2820
2821 if(!is_font_installed("Tahoma"))
2822 {
2823 skip("Tahoma is not installed so skipping this test\n");
2824 return;
2825 }
2826
2827 /* 'A' case. */
2828 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2829 f = CreateFontIndirectA(&fA);
2830 ok(f != NULL, "CreateFontIndirectA failed\n");
2831
2832 dc = GetDC(NULL);
2833 g = SelectObject(dc, f);
2834 n = GetTextFaceA(dc, sizeof bufA, bufA);
2835 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2836 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2837
2838 /* Play with the count arg. */
2839 bufA[0] = 'x';
2840 n = GetTextFaceA(dc, 0, bufA);
2841 ok(n == 0, "GetTextFaceA returned %d\n", n);
2842 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2843
2844 bufA[0] = 'x';
2845 n = GetTextFaceA(dc, 1, bufA);
2846 ok(n == 0, "GetTextFaceA returned %d\n", n);
2847 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2848
2849 bufA[0] = 'x'; bufA[1] = 'y';
2850 n = GetTextFaceA(dc, 2, bufA);
2851 ok(n == 1, "GetTextFaceA returned %d\n", n);
2852 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2853
2854 n = GetTextFaceA(dc, 0, NULL);
2855 ok(n == sizeof faceA ||
2856 broken(n == 0), /* win98, winMe */
2857 "GetTextFaceA returned %d\n", n);
2858
2859 DeleteObject(SelectObject(dc, g));
2860 ReleaseDC(NULL, dc);
2861
2862 /* 'W' case. */
2863 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2864 SetLastError(0xdeadbeef);
2865 f = CreateFontIndirectW(&fW);
2866 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2867 {
2868 win_skip("CreateFontIndirectW is not implemented\n");
2869 return;
2870 }
2871 ok(f != NULL, "CreateFontIndirectW failed\n");
2872
2873 dc = GetDC(NULL);
2874 g = SelectObject(dc, f);
2875 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2876 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2877 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2878
2879 /* Play with the count arg. */
2880 bufW[0] = 'x';
2881 n = GetTextFaceW(dc, 0, bufW);
2882 ok(n == 0, "GetTextFaceW returned %d\n", n);
2883 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2884
2885 bufW[0] = 'x';
2886 n = GetTextFaceW(dc, 1, bufW);
2887 ok(n == 1, "GetTextFaceW returned %d\n", n);
2888 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2889
2890 bufW[0] = 'x'; bufW[1] = 'y';
2891 n = GetTextFaceW(dc, 2, bufW);
2892 ok(n == 2, "GetTextFaceW returned %d\n", n);
2893 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2894
2895 n = GetTextFaceW(dc, 0, NULL);
2896 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2897
2898 DeleteObject(SelectObject(dc, g));
2899 ReleaseDC(NULL, dc);
2900 }
2901
2902 static void test_orientation(void)
2903 {
2904 static const char test_str[11] = "Test String";
2905 HDC hdc;
2906 LOGFONTA lf;
2907 HFONT hfont, old_hfont;
2908 SIZE size;
2909
2910 if (!is_truetype_font_installed("Arial"))
2911 {
2912 skip("Arial is not installed\n");
2913 return;
2914 }
2915
2916 hdc = CreateCompatibleDC(0);
2917 memset(&lf, 0, sizeof(lf));
2918 lstrcpyA(lf.lfFaceName, "Arial");
2919 lf.lfHeight = 72;
2920 lf.lfOrientation = lf.lfEscapement = 900;
2921 hfont = create_font("orientation", &lf);
2922 old_hfont = SelectObject(hdc, hfont);
2923 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2924 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2925 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2926 SelectObject(hdc, old_hfont);
2927 DeleteObject(hfont);
2928 DeleteDC(hdc);
2929 }
2930
2931 static void test_oemcharset(void)
2932 {
2933 HDC hdc;
2934 LOGFONTA lf, clf;
2935 HFONT hfont, old_hfont;
2936 int charset;
2937
2938 hdc = CreateCompatibleDC(0);
2939 ZeroMemory(&lf, sizeof(lf));
2940 lf.lfHeight = 12;
2941 lf.lfCharSet = OEM_CHARSET;
2942 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
2943 lstrcpyA(lf.lfFaceName, "Terminal");
2944 hfont = CreateFontIndirectA(&lf);
2945 old_hfont = SelectObject(hdc, hfont);
2946 charset = GetTextCharset(hdc);
2947 todo_wine
2948 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
2949 hfont = SelectObject(hdc, old_hfont);
2950 GetObjectA(hfont, sizeof(clf), &clf);
2951 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
2952 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
2953 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
2954 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
2955 DeleteObject(hfont);
2956 DeleteDC(hdc);
2957 }
2958
2959 static void test_GetGlyphOutline(void)
2960 {
2961 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2962 HDC hdc;
2963 GLYPHMETRICS gm;
2964 LOGFONTA lf;
2965 HFONT hfont, old_hfont;
2966 INT ret;
2967
2968 if (!is_truetype_font_installed("Tahoma"))
2969 {
2970 skip("Tahoma is not installed\n");
2971 return;
2972 }
2973
2974 hdc = CreateCompatibleDC(0);
2975 memset(&lf, 0, sizeof(lf));
2976 lf.lfHeight = 72;
2977 lstrcpyA(lf.lfFaceName, "Tahoma");
2978 SetLastError(0xdeadbeef);
2979 hfont = CreateFontIndirectA(&lf);
2980 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2981 old_hfont = SelectObject(hdc, hfont);
2982
2983 memset(&gm, 0, sizeof(gm));
2984 SetLastError(0xdeadbeef);
2985 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2986 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2987
2988 memset(&gm, 0, sizeof(gm));
2989 SetLastError(0xdeadbeef);
2990 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2991 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2992 ok(GetLastError() == 0xdeadbeef ||
2993 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2994 "expected 0xdeadbeef, got %u\n", GetLastError());
2995
2996 memset(&gm, 0, sizeof(gm));
2997 SetLastError(0xdeadbeef);
2998 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2999 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3000 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3001
3002 memset(&gm, 0, sizeof(gm));
3003 SetLastError(0xdeadbeef);
3004 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3005 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3006 {
3007 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3008 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3009 }
3010
3011 /* test for needed buffer size request on space char */
3012 memset(&gm, 0, sizeof(gm));
3013 SetLastError(0xdeadbeef);
3014 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3015 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3016 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3017
3018 /* requesting buffer size for space char + error */
3019 memset(&gm, 0, sizeof(gm));
3020 SetLastError(0xdeadbeef);
3021 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3022 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3023 {
3024 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3025 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3026 }
3027
3028 SelectObject(hdc, old_hfont);
3029 DeleteObject(hfont);
3030 DeleteDC(hdc);
3031 }
3032
3033 /* bug #9995: there is a limit to the character width that can be specified */
3034 static void test_GetTextMetrics2(const char *fontname, int font_height)
3035 {
3036 HFONT of, hf;
3037 HDC hdc;
3038 TEXTMETRICA tm;
3039 BOOL ret;
3040 int ave_width, height, width, ratio, scale;
3041
3042 if (!is_truetype_font_installed( fontname)) {
3043 skip("%s is not installed\n", fontname);
3044 return;
3045 }
3046 hdc = CreateCompatibleDC(0);
3047 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3048 /* select width = 0 */
3049 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3050 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3051 DEFAULT_QUALITY, VARIABLE_PITCH,
3052 fontname);
3053 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3054 of = SelectObject( hdc, hf);
3055 ret = GetTextMetricsA( hdc, &tm);
3056 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3057 height = tm.tmHeight;
3058 ave_width = tm.tmAveCharWidth;
3059 SelectObject( hdc, of);
3060 DeleteObject( hf);
3061
3062 trace("height %d, ave width %d\n", height, ave_width);
3063
3064 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3065 {
3066 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3067 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3068 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3069 ok(hf != 0, "CreateFont failed\n");
3070 of = SelectObject(hdc, hf);
3071 ret = GetTextMetrics(hdc, &tm);
3072 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3073 SelectObject(hdc, of);
3074 DeleteObject(hf);
3075
3076 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3077 break;
3078 }
3079
3080 DeleteDC(hdc);
3081
3082 ratio = width / height;
3083 scale = width / ave_width;
3084
3085 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3086 width, height, ratio, width, ave_width, scale);
3087
3088 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3089 }
3090
3091 static void test_CreateFontIndirect(void)
3092 {
3093 LOGFONTA lf, getobj_lf;
3094 int ret, i;
3095 HFONT hfont;
3096 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3097
3098 memset(&lf, 0, sizeof(lf));
3099 lf.lfCharSet = ANSI_CHARSET;
3100 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3101 lf.lfHeight = 16;
3102 lf.lfWidth = 16;
3103 lf.lfQuality = DEFAULT_QUALITY;
3104 lf.lfItalic = FALSE;
3105 lf.lfWeight = FW_DONTCARE;
3106
3107 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3108 {
3109 lstrcpyA(lf.lfFaceName, TestName[i]);
3110 hfont = CreateFontIndirectA(&lf);
3111 ok(hfont != 0, "CreateFontIndirectA failed\n");
3112 SetLastError(0xdeadbeef);
3113 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3114 ok(ret, "GetObject failed: %d\n", GetLastError());
3115 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3116 ok(lf.lfWeight == getobj_lf.lfWeight ||
3117 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3118 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3119 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3120 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3121 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3122 DeleteObject(hfont);
3123 }
3124 }
3125
3126 static void test_CreateFontIndirectEx(void)
3127 {
3128 ENUMLOGFONTEXDVA lfex;
3129 HFONT hfont;
3130
3131 if (!pCreateFontIndirectExA)
3132 {
3133 win_skip("CreateFontIndirectExA is not available\n");
3134 return;
3135 }
3136
3137 if (!is_truetype_font_installed("Arial"))
3138 {
3139 skip("Arial is not installed\n");
3140 return;
3141 }
3142
3143 SetLastError(0xdeadbeef);
3144 hfont = pCreateFontIndirectExA(NULL);
3145 ok(hfont == NULL, "got %p\n", hfont);
3146 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3147
3148 memset(&lfex, 0, sizeof(lfex));
3149 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3150 hfont = pCreateFontIndirectExA(&lfex);
3151 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3152 if (hfont)
3153 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3154 DeleteObject(hfont);
3155 }
3156
3157 START_TEST(font)
3158 {
3159 init();
3160
3161 test_logfont();
3162 test_bitmap_font();
3163 test_outline_font();
3164 test_bitmap_font_metrics();
3165 test_GdiGetCharDimensions();
3166 test_GetCharABCWidths();
3167 test_text_extents();
3168 test_GetGlyphIndices();
3169 test_GetKerningPairs();
3170 test_GetOutlineTextMetrics();
3171 test_SetTextJustification();
3172 test_font_charset();
3173 test_GetFontUnicodeRanges();
3174 test_nonexistent_font();
3175 test_orientation();
3176 test_height_selection();
3177
3178 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3179 * I'd like to avoid them in this test.
3180 */
3181 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3182 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3183 if (is_truetype_font_installed("Arial Black") &&
3184 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3185 {
3186 test_EnumFontFamilies("", ANSI_CHARSET);
3187 test_EnumFontFamilies("", SYMBOL_CHARSET);
3188 test_EnumFontFamilies("", DEFAULT_CHARSET);
3189 }
3190 else
3191 skip("Arial Black or Symbol/Wingdings is not installed\n");
3192 test_GetTextMetrics();
3193 test_GdiRealizationInfo();
3194 test_GetTextFace();
3195 test_GetGlyphOutline();
3196 test_GetTextMetrics2("Tahoma", -11);
3197 test_GetTextMetrics2("Tahoma", -55);
3198 test_GetTextMetrics2("Tahoma", -110);
3199 test_GetTextMetrics2("Arial", -11);
3200 test_GetTextMetrics2("Arial", -55);
3201 test_GetTextMetrics2("Arial", -110);
3202 test_CreateFontIndirect();
3203 test_CreateFontIndirectEx();
3204 test_oemcharset();
3205 }