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