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