2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
41 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
42 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
43 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
44 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
45 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
46 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
47 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
48 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
50 static HMODULE hgdi32 = 0;
52 static void init(void)
54 hgdi32 = GetModuleHandleA("gdi32.dll");
56 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
57 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
58 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
59 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
60 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
61 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
62 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
63 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
64 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
65 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
68 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
70 if (type != TRUETYPE_FONTTYPE) return 1;
75 static BOOL is_truetype_font_installed(const char *name)
80 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
87 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
92 static BOOL is_font_installed(const char *name)
97 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
104 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
112 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
113 /* NT4 tries to be clever and only returns the minimum length */
114 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
116 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
117 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
118 ok(lf->lfHeight == getobj_lf.lfHeight ||
119 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
120 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
121 ok(lf->lfWidth == getobj_lf.lfWidth ||
122 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
123 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
124 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
125 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
126 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
127 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
128 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
129 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
130 ok(lf->lfWeight == getobj_lf.lfWeight ||
131 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
132 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
133 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
134 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
135 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
136 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
137 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
138 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
139 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
140 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
141 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
142 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
143 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
146 static HFONT create_font(const char* test, const LOGFONTA* lf)
148 HFONT hfont = CreateFontIndirectA(lf);
149 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
151 check_font(test, lf, hfont);
155 static void test_logfont(void)
160 memset(&lf, 0, sizeof lf);
162 lf.lfCharSet = ANSI_CHARSET;
163 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
164 lf.lfWeight = FW_DONTCARE;
167 lf.lfQuality = DEFAULT_QUALITY;
169 lstrcpyA(lf.lfFaceName, "Arial");
170 hfont = create_font("Arial", &lf);
173 memset(&lf, 'A', sizeof(lf));
174 hfont = CreateFontIndirectA(&lf);
175 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
177 lf.lfFaceName[LF_FACESIZE - 1] = 0;
178 check_font("AAA...", &lf, hfont);
182 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
184 if (type & RASTER_FONTTYPE)
186 LOGFONT *lf = (LOGFONT *)lParam;
188 return 0; /* stop enumeration */
191 return 1; /* continue enumeration */
194 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
196 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
197 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
198 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
199 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
200 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
201 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
202 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
203 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
204 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
205 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
206 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
207 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
208 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
209 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
210 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
211 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
212 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
213 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
214 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
215 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
218 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
219 LONG lfWidth, const char *test_str,
220 INT test_str_len, const TEXTMETRICA *tm_orig,
221 const SIZE *size_orig, INT width_of_A_orig,
222 INT scale_x, INT scale_y)
225 OUTLINETEXTMETRIC otm;
228 INT width_of_A, cx, cy;
234 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
236 GetObjectA(hfont, sizeof(lf), &lf);
238 if (GetOutlineTextMetricsA(hdc, 0, NULL))
240 otm.otmSize = sizeof(otm) / 2;
241 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
242 ok(ret == sizeof(otm)/2 /* XP */ ||
243 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
245 memset(&otm, 0x1, sizeof(otm));
246 otm.otmSize = sizeof(otm);
247 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
248 ok(ret == sizeof(otm) /* XP */ ||
249 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
251 memset(&tm, 0x2, sizeof(tm));
252 ret = GetTextMetricsA(hdc, &tm);
253 ok(ret, "GetTextMetricsA failed\n");
254 /* the structure size is aligned */
255 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
257 ok(0, "tm != otm\n");
258 compare_tm(&tm, &otm.otmTextMetrics);
261 tm = otm.otmTextMetrics;
262 if (0) /* these metrics are scaled too, but with rounding errors */
264 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
265 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
267 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
268 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
269 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
270 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
271 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
272 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
276 ret = GetTextMetricsA(hdc, &tm);
277 ok(ret, "GetTextMetricsA failed\n");
280 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
281 cy = tm.tmHeight / tm_orig->tmHeight;
282 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
283 lfHeight, scale_x, scale_y, cx, cy);
284 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
285 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
286 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
287 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
288 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
290 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
294 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
297 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
299 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
301 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
302 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
304 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
306 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);
309 /* Test how GDI scales bitmap font metrics */
310 static void test_bitmap_font(void)
312 static const char test_str[11] = "Test String";
315 HFONT hfont, old_hfont;
318 INT ret, i, width_orig, height_orig, scale, lfWidth;
322 /* "System" has only 1 pixel size defined, otherwise the test breaks */
323 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
327 trace("no bitmap fonts were found, skipping the test\n");
331 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
333 height_orig = bitmap_lf.lfHeight;
334 lfWidth = bitmap_lf.lfWidth;
336 hfont = create_font("bitmap", &bitmap_lf);
337 old_hfont = SelectObject(hdc, hfont);
338 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
339 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
340 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
341 SelectObject(hdc, old_hfont);
344 bitmap_lf.lfHeight = 0;
345 bitmap_lf.lfWidth = 4;
346 hfont = create_font("bitmap", &bitmap_lf);
347 old_hfont = SelectObject(hdc, hfont);
348 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
349 SelectObject(hdc, old_hfont);
352 bitmap_lf.lfHeight = height_orig;
353 bitmap_lf.lfWidth = lfWidth;
355 /* test fractional scaling */
356 for (i = 1; i <= height_orig * 6; i++)
360 bitmap_lf.lfHeight = i;
361 hfont = create_font("fractional", &bitmap_lf);
362 scale = (i + height_orig - 1) / height_orig;
363 nearest_height = scale * height_orig;
364 /* Only jump to the next height if the difference <= 25% original height */
365 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
366 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
367 so we'll not test this particular height. */
368 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
369 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
370 old_hfont = SelectObject(hdc, hfont);
371 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
372 SelectObject(hdc, old_hfont);
376 /* test integer scaling 3x2 */
377 bitmap_lf.lfHeight = height_orig * 2;
378 bitmap_lf.lfWidth *= 3;
379 hfont = create_font("3x2", &bitmap_lf);
380 old_hfont = SelectObject(hdc, hfont);
381 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
382 SelectObject(hdc, old_hfont);
385 /* test integer scaling 3x3 */
386 bitmap_lf.lfHeight = height_orig * 3;
387 bitmap_lf.lfWidth = 0;
388 hfont = create_font("3x3", &bitmap_lf);
389 old_hfont = SelectObject(hdc, hfont);
390 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
391 SelectObject(hdc, old_hfont);
397 /* Test how GDI scales outline font metrics */
398 static void test_outline_font(void)
400 static const char test_str[11] = "Test String";
403 HFONT hfont, old_hfont, old_hfont_2;
404 OUTLINETEXTMETRICA otm;
406 INT width_orig, height_orig, lfWidth;
409 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
410 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
414 if (!is_truetype_font_installed("Arial"))
416 skip("Arial is not installed\n");
420 hdc = CreateCompatibleDC(0);
422 memset(&lf, 0, sizeof(lf));
423 strcpy(lf.lfFaceName, "Arial");
425 hfont = create_font("outline", &lf);
426 old_hfont = SelectObject(hdc, hfont);
427 otm.otmSize = sizeof(otm);
428 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
429 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
430 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
432 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
433 SelectObject(hdc, old_hfont);
436 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
437 lf.lfHeight = otm.otmEMSquare;
438 lf.lfHeight = -lf.lfHeight;
439 hfont = create_font("outline", &lf);
440 old_hfont = SelectObject(hdc, hfont);
441 otm.otmSize = sizeof(otm);
442 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
443 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
444 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
445 SelectObject(hdc, old_hfont);
448 height_orig = otm.otmTextMetrics.tmHeight;
449 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
451 /* test integer scaling 3x2 */
452 lf.lfHeight = height_orig * 2;
453 lf.lfWidth = lfWidth * 3;
454 hfont = create_font("3x2", &lf);
455 old_hfont = SelectObject(hdc, hfont);
456 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
457 SelectObject(hdc, old_hfont);
460 /* test integer scaling 3x3 */
461 lf.lfHeight = height_orig * 3;
462 lf.lfWidth = lfWidth * 3;
463 hfont = create_font("3x3", &lf);
464 old_hfont = SelectObject(hdc, hfont);
465 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
466 SelectObject(hdc, old_hfont);
469 /* test integer scaling 1x1 */
470 lf.lfHeight = height_orig * 1;
471 lf.lfWidth = lfWidth * 1;
472 hfont = create_font("1x1", &lf);
473 old_hfont = SelectObject(hdc, hfont);
474 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
475 SelectObject(hdc, old_hfont);
478 /* test integer scaling 1x1 */
479 lf.lfHeight = height_orig;
481 hfont = create_font("1x1", &lf);
482 old_hfont = SelectObject(hdc, hfont);
483 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 /* with an identity matrix */
486 memset(&gm, 0, sizeof(gm));
487 SetLastError(0xdeadbeef);
488 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
489 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
490 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
491 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
492 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
493 /* with a custom matrix */
494 memset(&gm, 0, sizeof(gm));
495 SetLastError(0xdeadbeef);
496 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
497 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
498 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
499 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
500 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
502 /* Test that changing the DC transformation affects only the font
503 * selected on this DC and doesn't affect the same font selected on
506 hdc_2 = CreateCompatibleDC(0);
507 old_hfont_2 = SelectObject(hdc_2, hfont);
508 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
510 SetMapMode(hdc, MM_ANISOTROPIC);
512 /* font metrics on another DC should be unchanged */
513 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
515 /* test restrictions of compatibility mode GM_COMPATIBLE */
516 /* part 1: rescaling only X should not change font scaling on screen.
517 So compressing the X axis by 2 is not done, and this
518 appears as X scaling of 2 that no one requested. */
519 SetWindowExtEx(hdc, 100, 100, NULL);
520 SetViewportExtEx(hdc, 50, 100, NULL);
521 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* part 2: rescaling only Y should change font scaling.
526 As also X is scaled by a factor of 2, but this is not
527 requested by the DC transformation, we get a scaling factor
528 of 2 in the X coordinate. */
529 SetViewportExtEx(hdc, 100, 200, NULL);
530 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
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);
534 /* restore scaling */
535 SetMapMode(hdc, MM_TEXT);
537 /* font metrics on another DC should be unchanged */
538 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
540 SelectObject(hdc_2, old_hfont_2);
543 if (!SetGraphicsMode(hdc, GM_ADVANCED))
545 SelectObject(hdc, old_hfont);
548 skip("GM_ADVANCED is not supported on this platform\n");
559 SetLastError(0xdeadbeef);
560 ret = SetWorldTransform(hdc, &xform);
561 ok(ret, "SetWorldTransform error %u\n", GetLastError());
563 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
565 /* with an identity matrix */
566 memset(&gm, 0, sizeof(gm));
567 SetLastError(0xdeadbeef);
568 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
569 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
570 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
571 pt.x = width_orig; pt.y = 0;
573 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
574 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
575 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
576 /* with a custom matrix */
577 memset(&gm, 0, sizeof(gm));
578 SetLastError(0xdeadbeef);
579 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
580 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
581 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
582 pt.x = width_orig; pt.y = 0;
584 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
585 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
586 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
588 SetLastError(0xdeadbeef);
589 ret = SetMapMode(hdc, MM_LOMETRIC);
590 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
592 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
594 /* with an identity matrix */
595 memset(&gm, 0, sizeof(gm));
596 SetLastError(0xdeadbeef);
597 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
598 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
599 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
600 pt.x = width_orig; pt.y = 0;
602 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
603 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
604 /* with a custom matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
612 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
615 SetLastError(0xdeadbeef);
616 ret = SetMapMode(hdc, MM_TEXT);
617 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
619 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 /* with an identity matrix */
622 memset(&gm, 0, sizeof(gm));
623 SetLastError(0xdeadbeef);
624 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
625 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
626 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
627 pt.x = width_orig; pt.y = 0;
629 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
630 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
631 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
632 /* with a custom matrix */
633 memset(&gm, 0, sizeof(gm));
634 SetLastError(0xdeadbeef);
635 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
636 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
637 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
638 pt.x = width_orig; pt.y = 0;
640 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
641 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
642 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
644 SelectObject(hdc, old_hfont);
649 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
651 LOGFONT *lf = (LOGFONT *)lParam;
653 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
656 return 0; /* stop enumeration */
658 return 1; /* continue enumeration */
661 static void test_bitmap_font_metrics(void)
663 static const struct font_data
665 const char face_name[LF_FACESIZE];
666 int weight, height, ascent, descent, int_leading, ext_leading;
667 int ave_char_width, max_char_width, dpi;
671 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
672 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
673 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
674 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
675 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
676 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
677 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
679 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
680 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
681 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
684 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
685 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
687 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
688 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
689 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
690 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
693 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
694 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
695 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
696 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
697 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
698 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
699 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
700 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
701 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
702 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
703 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
705 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
706 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
707 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
710 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
711 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
712 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
713 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
714 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
716 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
717 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
719 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
722 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
723 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
724 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
726 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
727 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
728 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
730 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
731 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
732 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
734 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
735 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
737 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
738 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
739 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
740 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
741 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
742 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
743 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
744 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
745 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
746 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
747 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
748 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
749 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
750 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
751 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
752 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
753 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
755 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
757 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
758 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
759 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
761 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
762 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
765 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
766 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
768 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
769 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
770 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
772 /* The 120dpi version still has its dpi marked as 96 */
773 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
775 /* FIXME: add "Terminal" */
779 HFONT hfont, old_hfont;
783 hdc = CreateCompatibleDC(0);
786 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
790 memset(&lf, 0, sizeof(lf));
792 lf.lfHeight = fd[i].height;
793 strcpy(lf.lfFaceName, fd[i].face_name);
795 for(bit = 0; bit < 32; bit++)
803 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
804 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
806 lf.lfCharSet = csi.ciCharset;
807 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
810 hfont = create_font(lf.lfFaceName, &lf);
811 old_hfont = SelectObject(hdc, hfont);
812 bRet = GetTextMetrics(hdc, &tm);
813 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
814 if(fd[i].dpi == tm.tmDigitizedAspectX)
816 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
817 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);
818 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);
819 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);
820 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);
821 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);
822 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);
823 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);
825 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
826 that make the max width bigger */
827 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
828 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);
830 SelectObject(hdc, old_hfont);
838 static void test_GdiGetCharDimensions(void)
844 LONG avgwidth, height;
845 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
847 if (!pGdiGetCharDimensions)
849 win_skip("GdiGetCharDimensions not available on this platform\n");
853 hdc = CreateCompatibleDC(NULL);
855 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
856 avgwidth = ((size.cx / 26) + 1) / 2;
858 ret = pGdiGetCharDimensions(hdc, &tm, &height);
859 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
860 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
862 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
863 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
865 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
866 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
869 ret = pGdiGetCharDimensions(hdc, NULL, &height);
870 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
871 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
876 static void test_GetCharABCWidths(void)
878 static const WCHAR str[] = {'a',0};
887 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
889 win_skip("GetCharABCWidthsW/I not available on this platform\n");
893 memset(&lf, 0, sizeof(lf));
894 strcpy(lf.lfFaceName, "System");
897 hfont = CreateFontIndirectA(&lf);
899 hfont = SelectObject(hdc, hfont);
901 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
902 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
904 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
905 ok(!ret, "GetCharABCWidthsI should have failed\n");
907 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
908 ok(!ret, "GetCharABCWidthsI should have failed\n");
910 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
911 ok(ret, "GetCharABCWidthsI should have succeeded\n");
913 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
914 ok(!ret, "GetCharABCWidthsW should have failed\n");
916 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
917 ok(!ret, "GetCharABCWidthsW should have failed\n");
919 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
920 ok(!ret, "GetCharABCWidthsW should have failed\n");
922 hfont = SelectObject(hdc, hfont);
924 ReleaseDC(NULL, hdc);
927 static void test_text_extents(void)
929 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
931 INT i, len, fit1, fit2;
939 memset(&lf, 0, sizeof(lf));
940 strcpy(lf.lfFaceName, "Arial");
943 hfont = CreateFontIndirectA(&lf);
945 hfont = SelectObject(hdc, hfont);
946 GetTextMetricsA(hdc, &tm);
947 GetTextExtentPointA(hdc, "o", 1, &sz);
948 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
950 SetLastError(0xdeadbeef);
951 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
952 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
954 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
955 hfont = SelectObject(hdc, hfont);
962 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
963 extents[0] = 1; /* So that the increasing sequence test will fail
964 if the extents array is untouched. */
965 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
966 GetTextExtentPointW(hdc, wt, len, &sz2);
968 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
969 /* Because of the '\n' in the string GetTextExtentExPoint and
970 GetTextExtentPoint return different widths under Win2k, but
971 under WinXP they return the same width. So we don't test that
974 for (i = 1; i < len; ++i)
975 ok(extents[i-1] <= extents[i],
976 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
978 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
979 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
980 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
981 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
982 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
983 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
984 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
985 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
986 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
987 ok(extents[0] == extents[2] && extents[1] == extents[3],
988 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
989 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
990 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
991 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
992 HeapFree(GetProcessHeap(), 0, extents);
994 hfont = SelectObject(hdc, hfont);
996 ReleaseDC(NULL, hdc);
999 static void test_GetGlyphIndices(void)
1006 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1007 WORD glyphs[(sizeof(testtext)/2)-1];
1011 if (!pGetGlyphIndicesW) {
1012 win_skip("GetGlyphIndicesW not available on platform\n");
1018 memset(&lf, 0, sizeof(lf));
1019 strcpy(lf.lfFaceName, "System");
1021 lf.lfCharSet = ANSI_CHARSET;
1023 hfont = CreateFontIndirectA(&lf);
1024 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1025 if (textm.tmCharSet == ANSI_CHARSET)
1027 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1028 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1029 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1030 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1032 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1033 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1034 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1035 textm.tmDefaultChar, glyphs[4]);
1038 /* FIXME: Write tests for non-ANSI charsets. */
1039 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1041 if(!is_font_installed("Tahoma"))
1043 skip("Tahoma is not installed so skipping this test\n");
1046 memset(&lf, 0, sizeof(lf));
1047 strcpy(lf.lfFaceName, "Tahoma");
1050 hfont = CreateFontIndirectA(&lf);
1051 hOldFont = SelectObject(hdc, hfont);
1052 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1053 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1054 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1055 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1056 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1058 testtext[0] = textm.tmDefaultChar;
1059 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1060 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1061 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1062 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1063 DeleteObject(SelectObject(hdc, hOldFont));
1066 static void test_GetKerningPairs(void)
1068 static const struct kerning_data
1070 const char face_name[LF_FACESIZE];
1072 /* some interesting fields from OUTLINETEXTMETRIC */
1073 LONG tmHeight, tmAscent, tmDescent;
1078 UINT otmsCapEmHeight;
1083 UINT otmusMinimumPPEM;
1084 /* small subset of kerning pairs to test */
1085 DWORD total_kern_pairs;
1086 const KERNINGPAIR kern_pair[26];
1089 {"Arial", 12, 12, 9, 3,
1090 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1093 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1094 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1095 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1096 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1097 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1098 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1099 {933,970,+1},{933,972,-1}
1102 {"Arial", -34, 39, 32, 7,
1103 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1106 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1107 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1108 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1109 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1110 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1111 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1112 {933,970,+2},{933,972,-3}
1115 { "Arial", 120, 120, 97, 23,
1116 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1119 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1120 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1121 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1122 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1123 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1124 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1125 {933,970,+6},{933,972,-10}
1128 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1129 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1130 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1133 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1134 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1135 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1136 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1137 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1138 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1139 {933,970,+54},{933,972,-83}
1145 HFONT hfont, hfont_old;
1146 KERNINGPAIR *kern_pair;
1148 DWORD total_kern_pairs, ret, i, n, matches;
1152 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1153 * which may render this test unusable, so we're trying to avoid that.
1155 SetLastError(0xdeadbeef);
1156 GetKerningPairsW(hdc, 0, NULL);
1157 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1159 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1164 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1166 OUTLINETEXTMETRICW otm;
1169 if (!is_font_installed(kd[i].face_name))
1171 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1175 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1177 memset(&lf, 0, sizeof(lf));
1178 strcpy(lf.lfFaceName, kd[i].face_name);
1179 lf.lfHeight = kd[i].height;
1180 hfont = CreateFontIndirect(&lf);
1183 hfont_old = SelectObject(hdc, hfont);
1185 SetLastError(0xdeadbeef);
1186 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1187 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1188 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1190 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1191 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1192 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1193 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1194 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1195 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1197 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1198 kd[i].otmEMSquare, otm.otmEMSquare);
1199 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1200 kd[i].otmAscent, otm.otmAscent);
1201 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1202 kd[i].otmDescent, otm.otmDescent);
1203 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1204 kd[i].otmLineGap, otm.otmLineGap);
1205 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1206 kd[i].otmMacDescent, otm.otmMacDescent);
1207 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1208 kd[i].otmMacAscent, otm.otmMacAscent);
1210 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1211 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1212 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1213 kd[i].otmsXHeight, otm.otmsXHeight);
1214 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1215 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1216 kd[i].otmMacLineGap, otm.otmMacLineGap);
1217 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1218 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1221 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1222 trace("total_kern_pairs %u\n", total_kern_pairs);
1223 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1225 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1226 SetLastError(0xdeadbeef);
1227 ret = GetKerningPairsW(hdc, 0, kern_pair);
1228 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1229 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1230 ok(ret == 0, "got %lu, expected 0\n", ret);
1233 ret = GetKerningPairsW(hdc, 100, NULL);
1234 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1236 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1237 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1239 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1240 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1244 for (n = 0; n < ret; n++)
1248 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1249 trace("{'%c','%c',%d},\n",
1250 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1252 for (j = 0; j < kd[i].total_kern_pairs; j++)
1254 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1255 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1257 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1258 "pair %d:%d got %d, expected %d\n",
1259 kern_pair[n].wFirst, kern_pair[n].wSecond,
1260 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1266 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1267 matches, kd[i].total_kern_pairs);
1269 HeapFree(GetProcessHeap(), 0, kern_pair);
1271 SelectObject(hdc, hfont_old);
1272 DeleteObject(hfont);
1278 static void test_height_selection(void)
1280 static const struct font_data
1282 const char face_name[LF_FACESIZE];
1283 int requested_height;
1284 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1287 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1288 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1289 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1290 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1291 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1292 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1293 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1294 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1295 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1296 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1300 HFONT hfont, old_hfont;
1304 hdc = CreateCompatibleDC(0);
1307 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1309 if (!is_truetype_font_installed(fd[i].face_name))
1311 skip("%s is not installed\n", fd[i].face_name);
1315 memset(&lf, 0, sizeof(lf));
1316 lf.lfHeight = fd[i].requested_height;
1317 lf.lfWeight = fd[i].weight;
1318 strcpy(lf.lfFaceName, fd[i].face_name);
1320 hfont = CreateFontIndirect(&lf);
1323 old_hfont = SelectObject(hdc, hfont);
1324 ret = GetTextMetrics(hdc, &tm);
1325 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1326 if(fd[i].dpi == tm.tmDigitizedAspectX)
1328 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1329 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1330 ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1331 ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1332 ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1333 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1334 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1336 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1339 SelectObject(hdc, old_hfont);
1340 DeleteObject(hfont);
1346 static void test_GetOutlineTextMetrics(void)
1348 OUTLINETEXTMETRIC *otm;
1350 HFONT hfont, hfont_old;
1352 DWORD ret, otm_size;
1355 if (!is_font_installed("Arial"))
1357 skip("Arial is not installed\n");
1363 memset(&lf, 0, sizeof(lf));
1364 strcpy(lf.lfFaceName, "Arial");
1366 lf.lfWeight = FW_NORMAL;
1367 lf.lfPitchAndFamily = DEFAULT_PITCH;
1368 lf.lfQuality = PROOF_QUALITY;
1369 hfont = CreateFontIndirect(&lf);
1372 hfont_old = SelectObject(hdc, hfont);
1373 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1374 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1376 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1378 memset(otm, 0xAA, otm_size);
1379 SetLastError(0xdeadbeef);
1380 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1381 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1382 ok(ret == 1 /* Win9x */ ||
1383 ret == otm->otmSize /* XP*/,
1384 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1385 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1387 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1388 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1389 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1390 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1393 memset(otm, 0xAA, otm_size);
1394 SetLastError(0xdeadbeef);
1395 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1396 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1397 ok(ret == 1 /* Win9x */ ||
1398 ret == otm->otmSize /* XP*/,
1399 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1400 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1402 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1403 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1404 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1405 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1408 /* ask about truncated data */
1409 memset(otm, 0xAA, otm_size);
1410 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1411 SetLastError(0xdeadbeef);
1412 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1413 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1414 ok(ret == 1 /* Win9x */ ||
1415 ret == otm->otmSize /* XP*/,
1416 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1417 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1419 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1420 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1421 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1423 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1425 HeapFree(GetProcessHeap(), 0, otm);
1427 SelectObject(hdc, hfont_old);
1428 DeleteObject(hfont);
1433 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1437 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1438 areaWidth = clientArea->right - clientArea->left,
1440 BOOL lastExtent = FALSE;
1441 PSTR pFirstChar, pLastChar;
1447 int GetTextExtentExPointWWidth;
1450 GetTextMetricsA(hdc, &tm);
1451 y = clientArea->top;
1454 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1460 /* if not at the end of the string, ... */
1461 if (*str == '\0') break;
1462 /* ... add the next word to the current extent */
1463 while (*str != '\0' && *str++ != tm.tmBreakChar);
1465 SetTextJustification(hdc, 0, 0);
1466 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1467 } while ((int) size.cx < areaWidth);
1469 /* ignore trailing break chars */
1471 while (*(pLastChar - 1) == tm.tmBreakChar)
1477 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1479 SetTextJustification(hdc, 0, 0);
1480 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1482 /* do not justify the last extent */
1483 if (*str != '\0' && breakCount > 0)
1485 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1486 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1487 justifiedWidth = size.cx;
1489 else lastExtent = TRUE;
1491 /* catch errors and report them */
1492 if (!lastExtent && (justifiedWidth != areaWidth))
1494 memset(error[nErrors].extent, 0, 100);
1495 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1496 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1502 } while (*str && y < clientArea->bottom);
1504 for (e = 0; e < nErrors; e++)
1506 /* The width returned by GetTextExtentPoint32() is exactly the same
1507 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1508 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1509 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1510 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1514 static void test_SetTextJustification(void)
1521 static char testText[] =
1522 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1523 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1524 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1525 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1526 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1527 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1528 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1530 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1531 GetClientRect( hwnd, &clientArea );
1532 hdc = GetDC( hwnd );
1534 memset(&lf, 0, sizeof lf);
1535 lf.lfCharSet = ANSI_CHARSET;
1536 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1537 lf.lfWeight = FW_DONTCARE;
1539 lf.lfQuality = DEFAULT_QUALITY;
1540 lstrcpyA(lf.lfFaceName, "Times New Roman");
1541 hfont = create_font("Times New Roman", &lf);
1542 SelectObject(hdc, hfont);
1544 testJustification(hdc, testText, &clientArea);
1546 DeleteObject(hfont);
1547 ReleaseDC(hwnd, hdc);
1548 DestroyWindow(hwnd);
1551 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1555 HFONT hfont, hfont_old;
1562 assert(count <= 128);
1564 memset(&lf, 0, sizeof(lf));
1566 lf.lfCharSet = charset;
1568 lstrcpyA(lf.lfFaceName, "Arial");
1569 SetLastError(0xdeadbeef);
1570 hfont = CreateFontIndirectA(&lf);
1571 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1574 hfont_old = SelectObject(hdc, hfont);
1576 cs = GetTextCharsetInfo(hdc, &fs, 0);
1577 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1579 SetLastError(0xdeadbeef);
1580 ret = GetTextFaceA(hdc, sizeof(name), name);
1581 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1583 if (charset == SYMBOL_CHARSET)
1585 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1586 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1590 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1591 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1594 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1596 trace("Can't find codepage for charset %d\n", cs);
1600 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1605 WCHAR unicode_buf[128];
1607 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1609 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1611 SetLastError(0xdeadbeef);
1612 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1613 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1619 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1621 SetLastError(0xdeadbeef);
1622 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1623 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1626 SelectObject(hdc, hfont_old);
1627 DeleteObject(hfont);
1634 static void test_font_charset(void)
1636 static struct charset_data
1640 WORD font_idxA[128], font_idxW[128];
1643 { ANSI_CHARSET, 1252 },
1644 { RUSSIAN_CHARSET, 1251 },
1645 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1649 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1651 win_skip("Skipping the font charset test on a Win9x platform\n");
1655 if (!is_font_installed("Arial"))
1657 skip("Arial is not installed\n");
1661 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1663 if (cd[i].charset == SYMBOL_CHARSET)
1665 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1667 skip("Symbol or Wingdings is not installed\n");
1671 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1672 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1673 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1676 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1679 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1680 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1683 skip("Symbol or Wingdings is not installed\n");
1686 static void test_GetFontUnicodeRanges(void)
1690 HFONT hfont, hfont_old;
1694 if (!pGetFontUnicodeRanges)
1696 win_skip("GetFontUnicodeRanges not available before W2K\n");
1700 memset(&lf, 0, sizeof(lf));
1701 lstrcpyA(lf.lfFaceName, "Arial");
1702 hfont = create_font("Arial", &lf);
1705 hfont_old = SelectObject(hdc, hfont);
1707 size = pGetFontUnicodeRanges(NULL, NULL);
1708 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1710 size = pGetFontUnicodeRanges(hdc, NULL);
1711 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1713 gs = HeapAlloc(GetProcessHeap(), 0, size);
1715 size = pGetFontUnicodeRanges(hdc, gs);
1716 ok(size, "GetFontUnicodeRanges failed\n");
1718 for (i = 0; i < gs->cRanges; i++)
1719 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1721 trace("found %u ranges\n", gs->cRanges);
1723 HeapFree(GetProcessHeap(), 0, gs);
1725 SelectObject(hdc, hfont_old);
1726 DeleteObject(hfont);
1727 ReleaseDC(NULL, hdc);
1730 #define MAX_ENUM_FONTS 4096
1732 struct enum_font_data
1735 LOGFONT lf[MAX_ENUM_FONTS];
1738 struct enum_font_dataW
1741 LOGFONTW lf[MAX_ENUM_FONTS];
1744 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1746 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1748 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1750 if (type != TRUETYPE_FONTTYPE) return 1;
1752 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1753 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1755 if (efd->total < MAX_ENUM_FONTS)
1756 efd->lf[efd->total++] = *lf;
1758 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1763 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1765 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1767 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1769 if (type != TRUETYPE_FONTTYPE) return 1;
1771 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1772 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1774 if (efd->total < MAX_ENUM_FONTS)
1775 efd->lf[efd->total++] = *lf;
1777 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1782 static void get_charset_stats(struct enum_font_data *efd,
1783 int *ansi_charset, int *symbol_charset,
1784 int *russian_charset)
1789 *symbol_charset = 0;
1790 *russian_charset = 0;
1792 for (i = 0; i < efd->total; i++)
1794 switch (efd->lf[i].lfCharSet)
1799 case SYMBOL_CHARSET:
1800 (*symbol_charset)++;
1802 case RUSSIAN_CHARSET:
1803 (*russian_charset)++;
1809 static void get_charset_statsW(struct enum_font_dataW *efd,
1810 int *ansi_charset, int *symbol_charset,
1811 int *russian_charset)
1816 *symbol_charset = 0;
1817 *russian_charset = 0;
1819 for (i = 0; i < efd->total; i++)
1821 switch (efd->lf[i].lfCharSet)
1826 case SYMBOL_CHARSET:
1827 (*symbol_charset)++;
1829 case RUSSIAN_CHARSET:
1830 (*russian_charset)++;
1836 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1838 struct enum_font_data efd;
1839 struct enum_font_dataW efdw;
1842 int i, ret, ansi_charset, symbol_charset, russian_charset;
1844 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1846 if (*font_name && !is_truetype_font_installed(font_name))
1848 skip("%s is not installed\n", font_name);
1854 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1855 * while EnumFontFamiliesEx doesn't.
1857 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1860 * Use EnumFontFamiliesW since win98 crashes when the
1861 * second parameter is NULL using EnumFontFamilies
1864 SetLastError(0xdeadbeef);
1865 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1866 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1869 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1870 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1871 ansi_charset, symbol_charset, russian_charset);
1872 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1873 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1874 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1875 ok(russian_charset > 0 ||
1876 broken(russian_charset == 0), /* NT4 */
1877 "NULL family should enumerate RUSSIAN_CHARSET\n");
1881 SetLastError(0xdeadbeef);
1882 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1883 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1886 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1887 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1888 ansi_charset, symbol_charset, russian_charset);
1889 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1890 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1891 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1892 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1897 SetLastError(0xdeadbeef);
1898 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1899 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1900 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1901 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1902 ansi_charset, symbol_charset, russian_charset,
1903 *font_name ? font_name : "<empty>");
1905 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1907 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1908 for (i = 0; i < efd.total; i++)
1910 /* FIXME: remove completely once Wine is fixed */
1911 if (efd.lf[i].lfCharSet != font_charset)
1914 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1917 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1918 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1919 font_name, efd.lf[i].lfFaceName);
1922 memset(&lf, 0, sizeof(lf));
1923 lf.lfCharSet = ANSI_CHARSET;
1924 lstrcpy(lf.lfFaceName, font_name);
1926 SetLastError(0xdeadbeef);
1927 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1928 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1929 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1930 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1931 ansi_charset, symbol_charset, russian_charset,
1932 *font_name ? font_name : "<empty>");
1933 if (font_charset == SYMBOL_CHARSET)
1936 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1938 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1942 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1943 for (i = 0; i < efd.total; i++)
1945 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1947 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1948 font_name, efd.lf[i].lfFaceName);
1952 /* DEFAULT_CHARSET should enumerate all available charsets */
1953 memset(&lf, 0, sizeof(lf));
1954 lf.lfCharSet = DEFAULT_CHARSET;
1955 lstrcpy(lf.lfFaceName, font_name);
1957 SetLastError(0xdeadbeef);
1958 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1959 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1960 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1961 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1962 ansi_charset, symbol_charset, russian_charset,
1963 *font_name ? font_name : "<empty>");
1964 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1965 for (i = 0; i < efd.total; i++)
1968 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1969 font_name, efd.lf[i].lfFaceName);
1973 switch (font_charset)
1976 ok(ansi_charset > 0,
1977 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1979 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1980 ok(russian_charset > 0,
1981 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1983 case SYMBOL_CHARSET:
1985 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1987 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1988 ok(!russian_charset,
1989 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1991 case DEFAULT_CHARSET:
1992 ok(ansi_charset > 0,
1993 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1994 ok(symbol_charset > 0,
1995 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1996 ok(russian_charset > 0,
1997 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2003 ok(ansi_charset > 0,
2004 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2005 ok(symbol_charset > 0,
2006 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2007 ok(russian_charset > 0,
2008 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2011 memset(&lf, 0, sizeof(lf));
2012 lf.lfCharSet = SYMBOL_CHARSET;
2013 lstrcpy(lf.lfFaceName, font_name);
2015 SetLastError(0xdeadbeef);
2016 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2017 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2018 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2019 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2020 ansi_charset, symbol_charset, russian_charset,
2021 *font_name ? font_name : "<empty>");
2022 if (*font_name && font_charset == ANSI_CHARSET)
2023 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2026 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2027 for (i = 0; i < efd.total; i++)
2029 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2031 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2032 font_name, efd.lf[i].lfFaceName);
2036 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2037 ok(symbol_charset > 0,
2038 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2039 ok(!russian_charset,
2040 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2046 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2048 HFONT hfont, hfont_prev;
2050 GLYPHMETRICS gm1, gm2;
2053 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2055 if(!pGetGlyphIndicesA)
2058 /* negative widths are handled just as positive ones */
2059 lf2.lfWidth = -lf->lfWidth;
2061 SetLastError(0xdeadbeef);
2062 hfont = CreateFontIndirectA(lf);
2063 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2064 check_font("original", lf, hfont);
2066 hfont_prev = SelectObject(hdc, hfont);
2068 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2069 if (ret == GDI_ERROR || idx == 0xffff)
2071 SelectObject(hdc, hfont_prev);
2072 DeleteObject(hfont);
2073 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2077 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2078 memset(&gm1, 0xab, sizeof(gm1));
2079 SetLastError(0xdeadbeef);
2080 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2081 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2083 SelectObject(hdc, hfont_prev);
2084 DeleteObject(hfont);
2086 SetLastError(0xdeadbeef);
2087 hfont = CreateFontIndirectA(&lf2);
2088 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2089 check_font("negative width", &lf2, hfont);
2091 hfont_prev = SelectObject(hdc, hfont);
2093 memset(&gm2, 0xbb, sizeof(gm2));
2094 SetLastError(0xdeadbeef);
2095 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2096 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2098 SelectObject(hdc, hfont_prev);
2099 DeleteObject(hfont);
2101 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2102 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2103 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2104 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2105 gm1.gmCellIncX == gm2.gmCellIncX &&
2106 gm1.gmCellIncY == gm2.gmCellIncY,
2107 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2108 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2109 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2110 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2111 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2114 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2115 #include "pshpack2.h"
2119 SHORT xAvgCharWidth;
2120 USHORT usWeightClass;
2121 USHORT usWidthClass;
2123 SHORT ySubscriptXSize;
2124 SHORT ySubscriptYSize;
2125 SHORT ySubscriptXOffset;
2126 SHORT ySubscriptYOffset;
2127 SHORT ySuperscriptXSize;
2128 SHORT ySuperscriptYSize;
2129 SHORT ySuperscriptXOffset;
2130 SHORT ySuperscriptYOffset;
2131 SHORT yStrikeoutSize;
2132 SHORT yStrikeoutPosition;
2135 ULONG ulUnicodeRange1;
2136 ULONG ulUnicodeRange2;
2137 ULONG ulUnicodeRange3;
2138 ULONG ulUnicodeRange4;
2141 USHORT usFirstCharIndex;
2142 USHORT usLastCharIndex;
2143 /* According to the Apple spec, original version didn't have the below fields,
2144 * version numbers were taked from the OpenType spec.
2146 /* version 0 (TrueType 1.5) */
2147 USHORT sTypoAscender;
2148 USHORT sTypoDescender;
2149 USHORT sTypoLineGap;
2151 USHORT usWinDescent;
2152 /* version 1 (TrueType 1.66) */
2153 ULONG ulCodePageRange1;
2154 ULONG ulCodePageRange2;
2155 /* version 2 (OpenType 1.2) */
2158 USHORT usDefaultChar;
2160 USHORT usMaxContext;
2162 #include "poppack.h"
2164 #ifdef WORDS_BIGENDIAN
2165 #define GET_BE_WORD(x) (x)
2166 #define GET_BE_DWORD(x) (x)
2168 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2169 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2172 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2173 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2174 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2175 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2176 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2189 } cmap_encoding_record;
2197 BYTE glyph_ids[256];
2207 USHORT search_range;
2208 USHORT entry_selector;
2211 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2214 USHORT start_count[seg_countx2 / 2];
2215 USHORT id_delta[seg_countx2 / 2];
2216 USHORT id_range_offset[seg_countx2 / 2];
2226 USHORT id_range_offset;
2227 } cmap_format_4_seg;
2229 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2231 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2232 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2233 os2->panose.bWeight, os2->panose.bProportion);
2236 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2239 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2243 for(i = 0; i < 256; i++)
2245 if(cmap->glyph_ids[i] == 0) continue;
2247 if(*first == 256) *first = i;
2249 if(*first == 256) return FALSE;
2253 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2255 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2256 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2257 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2258 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2259 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2262 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2265 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2266 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2267 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2271 for(i = 0; i < seg_count; i++)
2274 cmap_format_4_seg seg;
2276 get_seg4(cmap, i, &seg);
2277 for(code = seg.start_count; code <= seg.end_count; code++)
2279 if(seg.id_range_offset == 0)
2280 index = (seg.id_delta + code) & 0xffff;
2283 index = seg.id_range_offset / 2
2284 + code - seg.start_count
2287 /* some fonts have broken last segment */
2288 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2289 index = GET_BE_WORD(glyph_ids[index]);
2292 trace("segment %04x/%04x index %04x points to nowhere\n",
2293 seg.start_count, seg.end_count, index);
2296 if(index) index += seg.id_delta;
2298 if(*first == 0x10000)
2299 *last = *first = code;
2305 if(*first == 0x10000) return FALSE;
2309 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2312 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2314 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2316 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2317 return (BYTE *)header + GET_BE_DWORD(record->offset);
2330 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2333 cmap_header *header;
2338 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2339 ok(size != GDI_ERROR, "no cmap table found\n");
2340 if(size == GDI_ERROR) return FALSE;
2342 header = HeapAlloc(GetProcessHeap(), 0, size);
2343 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2344 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2345 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2347 cmap = get_cmap(header, 3, 1);
2349 *cmap_type = cmap_ms_unicode;
2352 cmap = get_cmap(header, 3, 0);
2353 if(cmap) *cmap_type = cmap_ms_symbol;
2357 *cmap_type = cmap_none;
2361 format = GET_BE_WORD(*(WORD *)cmap);
2365 r = get_first_last_from_cmap0(cmap, first, last);
2368 r = get_first_last_from_cmap4(cmap, first, last, size);
2371 trace("unhandled cmap format %d\n", format);
2376 HeapFree(GetProcessHeap(), 0, header);
2380 static void test_text_metrics(const LOGFONTA *lf)
2383 HFONT hfont, hfont_old;
2387 const char *font_name = lf->lfFaceName;
2388 DWORD cmap_first = 0, cmap_last = 0;
2389 cmap_type cmap_type;
2393 SetLastError(0xdeadbeef);
2394 hfont = CreateFontIndirectA(lf);
2395 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2397 hfont_old = SelectObject(hdc, hfont);
2399 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2400 if (size == GDI_ERROR)
2402 trace("OS/2 chunk was not found\n");
2405 if (size > sizeof(tt_os2))
2407 trace("got too large OS/2 chunk of size %u\n", size);
2408 size = sizeof(tt_os2);
2411 memset(&tt_os2, 0, sizeof(tt_os2));
2412 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2413 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2415 SetLastError(0xdeadbeef);
2416 ret = GetTextMetricsA(hdc, &tmA);
2417 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2419 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2421 skip("Unable to retrieve first and last glyphs from cmap\n");
2425 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2426 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2427 UINT os2_first_char, os2_last_char, default_char, break_char;
2431 version = GET_BE_WORD(tt_os2.version);
2433 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2434 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2435 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2436 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2438 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2439 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2440 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2442 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2447 case 1257: /* Baltic */
2448 expect_last_W = 0xf8fd;
2451 expect_last_W = 0xf0ff;
2453 expect_break_W = 0x20;
2454 expect_default_W = expect_break_W - 1;
2455 expect_first_A = 0x1e;
2456 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2460 expect_first_W = cmap_first;
2461 expect_last_W = min(cmap_last, os2_last_char);
2462 if(os2_first_char <= 1)
2463 expect_break_W = os2_first_char + 2;
2464 else if(os2_first_char > 0xff)
2465 expect_break_W = 0x20;
2467 expect_break_W = os2_first_char;
2468 expect_default_W = expect_break_W - 1;
2469 expect_first_A = expect_default_W - 1;
2470 expect_last_A = min(expect_last_W, 0xff);
2472 expect_break_A = expect_break_W;
2473 expect_default_A = expect_default_W;
2475 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2476 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2477 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2478 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2479 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2481 ok(tmA.tmFirstChar == expect_first_A ||
2482 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2483 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2484 ok(tmA.tmLastChar == expect_last_A ||
2485 tmA.tmLastChar == 0xff /* win9x */,
2486 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2487 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2488 font_name, tmA.tmBreakChar, expect_break_A);
2489 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2490 font_name, tmA.tmDefaultChar, expect_default_A);
2493 SetLastError(0xdeadbeef);
2494 ret = GetTextMetricsW(hdc, &tmW);
2495 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2496 "GetTextMetricsW error %u\n", GetLastError());
2499 /* Wine uses the os2 first char */
2500 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2501 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2502 font_name, tmW.tmFirstChar, expect_first_W);
2504 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2505 font_name, tmW.tmFirstChar, expect_first_W);
2507 /* Wine uses the os2 last char */
2508 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2509 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2510 font_name, tmW.tmLastChar, expect_last_W);
2512 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2513 font_name, tmW.tmLastChar, expect_last_W);
2514 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2515 font_name, tmW.tmBreakChar, expect_break_W);
2516 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2517 font_name, tmW.tmDefaultChar, expect_default_W);
2519 /* Test the aspect ratio while we have tmW */
2520 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2521 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2522 tmW.tmDigitizedAspectX, ret);
2523 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2524 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2525 tmW.tmDigitizedAspectX, ret);
2529 /* test FF_ values */
2530 switch(tt_os2.panose.bFamilyType)
2534 case PAN_FAMILY_TEXT_DISPLAY:
2535 case PAN_FAMILY_PICTORIAL:
2537 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2538 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2540 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2543 switch(tt_os2.panose.bSerifStyle)
2548 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2551 case PAN_SERIF_COVE:
2552 case PAN_SERIF_OBTUSE_COVE:
2553 case PAN_SERIF_SQUARE_COVE:
2554 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2555 case PAN_SERIF_SQUARE:
2556 case PAN_SERIF_THIN:
2557 case PAN_SERIF_BONE:
2558 case PAN_SERIF_EXAGGERATED:
2559 case PAN_SERIF_TRIANGLE:
2560 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2563 case PAN_SERIF_NORMAL_SANS:
2564 case PAN_SERIF_OBTUSE_SANS:
2565 case PAN_SERIF_PERP_SANS:
2566 case PAN_SERIF_FLARED:
2567 case PAN_SERIF_ROUNDED:
2568 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2573 case PAN_FAMILY_SCRIPT:
2574 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2577 case PAN_FAMILY_DECORATIVE:
2578 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2582 test_negative_width(hdc, lf);
2585 SelectObject(hdc, hfont_old);
2586 DeleteObject(hfont);
2591 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2593 INT *enumed = (INT *)lParam;
2595 if (type == TRUETYPE_FONTTYPE)
2598 test_text_metrics(lf);
2603 static void test_GetTextMetrics(void)
2609 /* Report only once */
2610 if(!pGetGlyphIndicesA)
2611 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2615 memset(&lf, 0, sizeof(lf));
2616 lf.lfCharSet = DEFAULT_CHARSET;
2618 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2619 trace("Tested metrics of %d truetype fonts\n", enumed);
2624 static void test_nonexistent_font(void)
2632 { "Times New Roman Baltic", 186 },
2633 { "Times New Roman CE", 238 },
2634 { "Times New Roman CYR", 204 },
2635 { "Times New Roman Greek", 161 },
2636 { "Times New Roman TUR", 162 }
2642 INT cs, expected_cs, i;
2643 char buf[LF_FACESIZE];
2645 if (!is_truetype_font_installed("Arial") ||
2646 !is_truetype_font_installed("Times New Roman"))
2648 skip("Arial or Times New Roman not installed\n");
2652 expected_cs = GetACP();
2653 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2655 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2658 expected_cs = csi.ciCharset;
2659 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2663 memset(&lf, 0, sizeof(lf));
2665 lf.lfWeight = FW_REGULAR;
2666 lf.lfCharSet = ANSI_CHARSET;
2667 lf.lfPitchAndFamily = FF_SWISS;
2668 strcpy(lf.lfFaceName, "Nonexistent font");
2669 hfont = CreateFontIndirectA(&lf);
2670 hfont = SelectObject(hdc, hfont);
2671 GetTextFaceA(hdc, sizeof(buf), buf);
2672 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2673 cs = GetTextCharset(hdc);
2674 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2675 DeleteObject(SelectObject(hdc, hfont));
2677 memset(&lf, 0, sizeof(lf));
2679 lf.lfWeight = FW_DONTCARE;
2680 strcpy(lf.lfFaceName, "Nonexistent font");
2681 hfont = CreateFontIndirectA(&lf);
2682 hfont = SelectObject(hdc, hfont);
2683 GetTextFaceA(hdc, sizeof(buf), buf);
2684 todo_wine /* Wine uses Arial for all substitutions */
2685 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2686 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2687 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2689 cs = GetTextCharset(hdc);
2690 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2691 DeleteObject(SelectObject(hdc, hfont));
2693 memset(&lf, 0, sizeof(lf));
2695 lf.lfWeight = FW_REGULAR;
2696 strcpy(lf.lfFaceName, "Nonexistent font");
2697 hfont = CreateFontIndirectA(&lf);
2698 hfont = SelectObject(hdc, hfont);
2699 GetTextFaceA(hdc, sizeof(buf), buf);
2700 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2701 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2702 cs = GetTextCharset(hdc);
2703 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2704 DeleteObject(SelectObject(hdc, hfont));
2706 memset(&lf, 0, sizeof(lf));
2708 lf.lfWeight = FW_DONTCARE;
2709 strcpy(lf.lfFaceName, "Times New Roman");
2710 hfont = CreateFontIndirectA(&lf);
2711 hfont = SelectObject(hdc, hfont);
2712 GetTextFaceA(hdc, sizeof(buf), buf);
2713 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2714 cs = GetTextCharset(hdc);
2715 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2716 DeleteObject(SelectObject(hdc, hfont));
2718 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2720 memset(&lf, 0, sizeof(lf));
2722 lf.lfWeight = FW_REGULAR;
2723 strcpy(lf.lfFaceName, font_subst[i].name);
2724 hfont = CreateFontIndirectA(&lf);
2725 hfont = SelectObject(hdc, hfont);
2726 cs = GetTextCharset(hdc);
2727 if (font_subst[i].charset == expected_cs)
2729 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2730 GetTextFaceA(hdc, sizeof(buf), buf);
2731 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2735 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2736 GetTextFaceA(hdc, sizeof(buf), buf);
2737 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2738 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2740 DeleteObject(SelectObject(hdc, hfont));
2742 memset(&lf, 0, sizeof(lf));
2744 lf.lfWeight = FW_DONTCARE;
2745 strcpy(lf.lfFaceName, font_subst[i].name);
2746 hfont = CreateFontIndirectA(&lf);
2747 hfont = SelectObject(hdc, hfont);
2748 GetTextFaceA(hdc, sizeof(buf), buf);
2749 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2750 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2751 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2752 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2753 "got %s for font %s\n", buf, font_subst[i].name);
2754 cs = GetTextCharset(hdc);
2755 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2756 DeleteObject(SelectObject(hdc, hfont));
2762 static void test_GdiRealizationInfo(void)
2767 HFONT hfont, hfont_old;
2770 if(!pGdiRealizationInfo)
2772 win_skip("GdiRealizationInfo not available\n");
2778 memset(info, 0xcc, sizeof(info));
2779 r = pGdiRealizationInfo(hdc, info);
2780 ok(r != 0, "ret 0\n");
2781 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2782 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2784 if (!is_truetype_font_installed("Arial"))
2786 skip("skipping GdiRealizationInfo with truetype font\n");
2790 memset(&lf, 0, sizeof(lf));
2791 strcpy(lf.lfFaceName, "Arial");
2793 lf.lfWeight = FW_NORMAL;
2794 hfont = CreateFontIndirectA(&lf);
2795 hfont_old = SelectObject(hdc, hfont);
2797 memset(info, 0xcc, sizeof(info));
2798 r = pGdiRealizationInfo(hdc, info);
2799 ok(r != 0, "ret 0\n");
2800 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2801 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2803 DeleteObject(SelectObject(hdc, hfont_old));
2809 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2810 the nul in the count of characters copied when the face name buffer is not
2811 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2812 always includes it. */
2813 static void test_GetTextFace(void)
2815 static const char faceA[] = "Tahoma";
2816 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2819 char bufA[LF_FACESIZE];
2820 WCHAR bufW[LF_FACESIZE];
2825 if(!is_font_installed("Tahoma"))
2827 skip("Tahoma is not installed so skipping this test\n");
2832 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2833 f = CreateFontIndirectA(&fA);
2834 ok(f != NULL, "CreateFontIndirectA failed\n");
2837 g = SelectObject(dc, f);
2838 n = GetTextFaceA(dc, sizeof bufA, bufA);
2839 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2840 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2842 /* Play with the count arg. */
2844 n = GetTextFaceA(dc, 0, bufA);
2845 ok(n == 0, "GetTextFaceA returned %d\n", n);
2846 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2849 n = GetTextFaceA(dc, 1, bufA);
2850 ok(n == 0, "GetTextFaceA returned %d\n", n);
2851 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2853 bufA[0] = 'x'; bufA[1] = 'y';
2854 n = GetTextFaceA(dc, 2, bufA);
2855 ok(n == 1, "GetTextFaceA returned %d\n", n);
2856 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2858 n = GetTextFaceA(dc, 0, NULL);
2859 ok(n == sizeof faceA ||
2860 broken(n == 0), /* win98, winMe */
2861 "GetTextFaceA returned %d\n", n);
2863 DeleteObject(SelectObject(dc, g));
2864 ReleaseDC(NULL, dc);
2867 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2868 SetLastError(0xdeadbeef);
2869 f = CreateFontIndirectW(&fW);
2870 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2872 win_skip("CreateFontIndirectW is not implemented\n");
2875 ok(f != NULL, "CreateFontIndirectW failed\n");
2878 g = SelectObject(dc, f);
2879 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2880 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2881 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2883 /* Play with the count arg. */
2885 n = GetTextFaceW(dc, 0, bufW);
2886 ok(n == 0, "GetTextFaceW returned %d\n", n);
2887 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2890 n = GetTextFaceW(dc, 1, bufW);
2891 ok(n == 1, "GetTextFaceW returned %d\n", n);
2892 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2894 bufW[0] = 'x'; bufW[1] = 'y';
2895 n = GetTextFaceW(dc, 2, bufW);
2896 ok(n == 2, "GetTextFaceW returned %d\n", n);
2897 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2899 n = GetTextFaceW(dc, 0, NULL);
2900 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2902 DeleteObject(SelectObject(dc, g));
2903 ReleaseDC(NULL, dc);
2906 static void test_orientation(void)
2908 static const char test_str[11] = "Test String";
2911 HFONT hfont, old_hfont;
2914 if (!is_truetype_font_installed("Arial"))
2916 skip("Arial is not installed\n");
2920 hdc = CreateCompatibleDC(0);
2921 memset(&lf, 0, sizeof(lf));
2922 lstrcpyA(lf.lfFaceName, "Arial");
2924 lf.lfOrientation = lf.lfEscapement = 900;
2925 hfont = create_font("orientation", &lf);
2926 old_hfont = SelectObject(hdc, hfont);
2927 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2928 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2929 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2930 SelectObject(hdc, old_hfont);
2931 DeleteObject(hfont);
2935 static void test_oemcharset(void)
2939 HFONT hfont, old_hfont;
2942 hdc = CreateCompatibleDC(0);
2943 ZeroMemory(&lf, sizeof(lf));
2945 lf.lfCharSet = OEM_CHARSET;
2946 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
2947 lstrcpyA(lf.lfFaceName, "Terminal");
2948 hfont = CreateFontIndirectA(&lf);
2949 old_hfont = SelectObject(hdc, hfont);
2950 charset = GetTextCharset(hdc);
2952 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
2953 hfont = SelectObject(hdc, old_hfont);
2954 GetObjectA(hfont, sizeof(clf), &clf);
2955 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
2956 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
2957 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
2958 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
2959 DeleteObject(hfont);
2963 static void test_GetGlyphOutline(void)
2965 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2969 HFONT hfont, old_hfont;
2972 if (!is_truetype_font_installed("Tahoma"))
2974 skip("Tahoma is not installed\n");
2978 hdc = CreateCompatibleDC(0);
2979 memset(&lf, 0, sizeof(lf));
2981 lstrcpyA(lf.lfFaceName, "Tahoma");
2982 SetLastError(0xdeadbeef);
2983 hfont = CreateFontIndirectA(&lf);
2984 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2985 old_hfont = SelectObject(hdc, hfont);
2987 memset(&gm, 0, sizeof(gm));
2988 SetLastError(0xdeadbeef);
2989 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2990 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2992 memset(&gm, 0, sizeof(gm));
2993 SetLastError(0xdeadbeef);
2994 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2995 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2996 ok(GetLastError() == 0xdeadbeef ||
2997 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2998 "expected 0xdeadbeef, got %u\n", GetLastError());
3000 memset(&gm, 0, sizeof(gm));
3001 SetLastError(0xdeadbeef);
3002 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3003 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3004 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3006 memset(&gm, 0, sizeof(gm));
3007 SetLastError(0xdeadbeef);
3008 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3009 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3011 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3012 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3015 /* test for needed buffer size request on space char */
3016 memset(&gm, 0, sizeof(gm));
3017 SetLastError(0xdeadbeef);
3018 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3019 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3020 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3022 /* requesting buffer size for space char + error */
3023 memset(&gm, 0, sizeof(gm));
3024 SetLastError(0xdeadbeef);
3025 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3026 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3028 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3029 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3032 SelectObject(hdc, old_hfont);
3033 DeleteObject(hfont);
3037 /* bug #9995: there is a limit to the character width that can be specified */
3038 static void test_GetTextMetrics2(const char *fontname, int font_height)
3044 int ave_width, height, width, ratio, scale;
3046 if (!is_truetype_font_installed( fontname)) {
3047 skip("%s is not installed\n", fontname);
3050 hdc = CreateCompatibleDC(0);
3051 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3052 /* select width = 0 */
3053 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3054 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3055 DEFAULT_QUALITY, VARIABLE_PITCH,
3057 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3058 of = SelectObject( hdc, hf);
3059 ret = GetTextMetricsA( hdc, &tm);
3060 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3061 height = tm.tmHeight;
3062 ave_width = tm.tmAveCharWidth;
3063 SelectObject( hdc, of);
3066 trace("height %d, ave width %d\n", height, ave_width);
3068 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3070 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3071 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3072 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3073 ok(hf != 0, "CreateFont failed\n");
3074 of = SelectObject(hdc, hf);
3075 ret = GetTextMetrics(hdc, &tm);
3076 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3077 SelectObject(hdc, of);
3080 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3086 ratio = width / height;
3087 scale = width / ave_width;
3089 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3090 width, height, ratio, width, ave_width, scale);
3092 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3095 static void test_CreateFontIndirect(void)
3097 LOGFONTA lf, getobj_lf;
3100 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3102 memset(&lf, 0, sizeof(lf));
3103 lf.lfCharSet = ANSI_CHARSET;
3104 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3107 lf.lfQuality = DEFAULT_QUALITY;
3108 lf.lfItalic = FALSE;
3109 lf.lfWeight = FW_DONTCARE;
3111 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3113 lstrcpyA(lf.lfFaceName, TestName[i]);
3114 hfont = CreateFontIndirectA(&lf);
3115 ok(hfont != 0, "CreateFontIndirectA failed\n");
3116 SetLastError(0xdeadbeef);
3117 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3118 ok(ret, "GetObject failed: %d\n", GetLastError());
3119 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3120 ok(lf.lfWeight == getobj_lf.lfWeight ||
3121 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3122 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3123 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3124 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3125 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3126 DeleteObject(hfont);
3130 static void test_CreateFontIndirectEx(void)
3132 ENUMLOGFONTEXDVA lfex;
3135 if (!pCreateFontIndirectExA)
3137 win_skip("CreateFontIndirectExA is not available\n");
3141 if (!is_truetype_font_installed("Arial"))
3143 skip("Arial is not installed\n");
3147 SetLastError(0xdeadbeef);
3148 hfont = pCreateFontIndirectExA(NULL);
3149 ok(hfont == NULL, "got %p\n", hfont);
3150 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3152 memset(&lfex, 0, sizeof(lfex));
3153 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3154 hfont = pCreateFontIndirectExA(&lfex);
3155 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3157 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3158 DeleteObject(hfont);
3161 static void free_font(void *font)
3163 UnmapViewOfFile(font);
3166 static void *load_font(const char *font_name, DWORD *font_size)
3168 char file_name[MAX_PATH];
3169 HANDLE file, mapping;
3172 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3173 strcat(file_name, "\\fonts\\");
3174 strcat(file_name, font_name);
3176 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3177 if (file == INVALID_HANDLE_VALUE) return NULL;
3179 *font_size = GetFileSize(file, NULL);
3181 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3188 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3191 CloseHandle(mapping);
3195 static void test_AddFontMemResource(void)
3198 DWORD font_size, num_fonts;
3202 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3204 win_skip("AddFontMemResourceEx is not available on this platform\n");
3208 font = load_font("sserife.fon", &font_size);
3211 skip("Unable to locate and load font sserife.fon\n");
3215 SetLastError(0xdeadbeef);
3216 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3217 ok(!ret, "AddFontMemResourceEx should fail\n");
3218 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3219 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3222 SetLastError(0xdeadbeef);
3223 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3224 ok(!ret, "AddFontMemResourceEx should fail\n");
3225 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3226 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3229 SetLastError(0xdeadbeef);
3230 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3231 ok(!ret, "AddFontMemResourceEx should fail\n");
3232 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3233 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3236 SetLastError(0xdeadbeef);
3237 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3238 ok(!ret, "AddFontMemResourceEx should fail\n");
3239 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3240 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3243 SetLastError(0xdeadbeef);
3244 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3245 ok(!ret, "AddFontMemResourceEx should fail\n");
3246 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3247 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3250 SetLastError(0xdeadbeef);
3251 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3252 ok(!ret, "AddFontMemResourceEx should fail\n");
3253 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3254 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3257 num_fonts = 0xdeadbeef;
3258 SetLastError(0xdeadbeef);
3259 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3260 ok(!ret, "AddFontMemResourceEx should fail\n");
3261 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3262 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3264 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3266 if (0) /* hangs under windows 2000 */
3268 num_fonts = 0xdeadbeef;
3269 SetLastError(0xdeadbeef);
3270 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3271 ok(!ret, "AddFontMemResourceEx should fail\n");
3272 ok(GetLastError() == 0xdeadbeef,
3273 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3275 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3278 num_fonts = 0xdeadbeef;
3279 SetLastError(0xdeadbeef);
3280 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3281 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3282 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3283 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3287 SetLastError(0xdeadbeef);
3288 bRet = pRemoveFontMemResourceEx(ret);
3289 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3291 /* test invalid pointer to number of loaded fonts */
3292 font = load_font("sserife.fon", &font_size);
3293 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3295 SetLastError(0xdeadbeef);
3296 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3297 ok(!ret, "AddFontMemResourceEx should fail\n");
3298 ok(GetLastError() == 0xdeadbeef,
3299 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3302 SetLastError(0xdeadbeef);
3303 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3304 ok(!ret, "AddFontMemResourceEx should fail\n");
3305 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3306 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3318 test_outline_font();
3319 test_bitmap_font_metrics();
3320 test_GdiGetCharDimensions();
3321 test_GetCharABCWidths();
3322 test_text_extents();
3323 test_GetGlyphIndices();
3324 test_GetKerningPairs();
3325 test_GetOutlineTextMetrics();
3326 test_SetTextJustification();
3327 test_font_charset();
3328 test_GetFontUnicodeRanges();
3329 test_nonexistent_font();
3331 test_height_selection();
3332 test_AddFontMemResource();
3334 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3335 * I'd like to avoid them in this test.
3337 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3338 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3339 if (is_truetype_font_installed("Arial Black") &&
3340 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3342 test_EnumFontFamilies("", ANSI_CHARSET);
3343 test_EnumFontFamilies("", SYMBOL_CHARSET);
3344 test_EnumFontFamilies("", DEFAULT_CHARSET);
3347 skip("Arial Black or Symbol/Wingdings is not installed\n");
3348 test_GetTextMetrics();
3349 test_GdiRealizationInfo();
3351 test_GetGlyphOutline();
3352 test_GetTextMetrics2("Tahoma", -11);
3353 test_GetTextMetrics2("Tahoma", -55);
3354 test_GetTextMetrics2("Tahoma", -110);
3355 test_GetTextMetrics2("Arial", -11);
3356 test_GetTextMetrics2("Arial", -55);
3357 test_GetTextMetrics2("Arial", -110);
3358 test_CreateFontIndirect();
3359 test_CreateFontIndirectEx();