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 DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
45 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
46 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
48 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
49 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
50 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static HMODULE hgdi32 = 0;
53 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
55 static void init(void)
57 hgdi32 = GetModuleHandleA("gdi32.dll");
59 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
60 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
61 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
62 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
63 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
64 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
65 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
66 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
67 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
68 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
69 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
70 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
73 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
75 if (type != TRUETYPE_FONTTYPE) return 1;
80 static BOOL is_truetype_font_installed(const char *name)
85 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
92 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
97 static BOOL is_font_installed(const char *name)
102 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
109 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
117 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
118 /* NT4 tries to be clever and only returns the minimum length */
119 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
121 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
122 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
123 ok(lf->lfHeight == getobj_lf.lfHeight ||
124 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
125 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
126 ok(lf->lfWidth == getobj_lf.lfWidth ||
127 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
128 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
129 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
130 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
131 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
132 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
133 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
134 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
135 ok(lf->lfWeight == getobj_lf.lfWeight ||
136 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
137 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
138 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
139 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
140 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
141 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
142 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
143 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
144 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
145 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
146 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
147 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
148 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
151 static HFONT create_font(const char* test, const LOGFONTA* lf)
153 HFONT hfont = CreateFontIndirectA(lf);
154 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
156 check_font(test, lf, hfont);
160 static void test_logfont(void)
165 memset(&lf, 0, sizeof lf);
167 lf.lfCharSet = ANSI_CHARSET;
168 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
169 lf.lfWeight = FW_DONTCARE;
172 lf.lfQuality = DEFAULT_QUALITY;
174 lstrcpyA(lf.lfFaceName, "Arial");
175 hfont = create_font("Arial", &lf);
178 memset(&lf, 'A', sizeof(lf));
179 hfont = CreateFontIndirectA(&lf);
180 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
182 lf.lfFaceName[LF_FACESIZE - 1] = 0;
183 check_font("AAA...", &lf, hfont);
187 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
189 if (type & RASTER_FONTTYPE)
191 LOGFONT *lf = (LOGFONT *)lParam;
193 return 0; /* stop enumeration */
196 return 1; /* continue enumeration */
199 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
201 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
202 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
203 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
204 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
205 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
206 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
207 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
208 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
209 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
210 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
211 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
212 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
213 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
214 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
215 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
216 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
217 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
218 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
219 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
220 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
223 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
224 LONG lfWidth, const char *test_str,
225 INT test_str_len, const TEXTMETRICA *tm_orig,
226 const SIZE *size_orig, INT width_of_A_orig,
227 INT scale_x, INT scale_y)
230 OUTLINETEXTMETRIC otm;
233 INT width_of_A, cx, cy;
239 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
241 GetObjectA(hfont, sizeof(lf), &lf);
243 if (GetOutlineTextMetricsA(hdc, 0, NULL))
245 otm.otmSize = sizeof(otm) / 2;
246 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
247 ok(ret == sizeof(otm)/2 /* XP */ ||
248 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
250 memset(&otm, 0x1, sizeof(otm));
251 otm.otmSize = sizeof(otm);
252 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253 ok(ret == sizeof(otm) /* XP */ ||
254 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
256 memset(&tm, 0x2, sizeof(tm));
257 ret = GetTextMetricsA(hdc, &tm);
258 ok(ret, "GetTextMetricsA failed\n");
259 /* the structure size is aligned */
260 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
262 ok(0, "tm != otm\n");
263 compare_tm(&tm, &otm.otmTextMetrics);
266 tm = otm.otmTextMetrics;
267 if (0) /* these metrics are scaled too, but with rounding errors */
269 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
270 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
272 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
273 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
274 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
275 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
276 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
277 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
281 ret = GetTextMetricsA(hdc, &tm);
282 ok(ret, "GetTextMetricsA failed\n");
285 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
286 cy = tm.tmHeight / tm_orig->tmHeight;
287 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
288 lfHeight, scale_x, scale_y, cx, cy);
289 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
290 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
291 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
292 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
293 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
295 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
299 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
302 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
304 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
306 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
307 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
309 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
311 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);
314 /* Test how GDI scales bitmap font metrics */
315 static void test_bitmap_font(void)
317 static const char test_str[11] = "Test String";
320 HFONT hfont, old_hfont;
323 INT ret, i, width_orig, height_orig, scale, lfWidth;
327 /* "System" has only 1 pixel size defined, otherwise the test breaks */
328 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
332 trace("no bitmap fonts were found, skipping the test\n");
336 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
338 height_orig = bitmap_lf.lfHeight;
339 lfWidth = bitmap_lf.lfWidth;
341 hfont = create_font("bitmap", &bitmap_lf);
342 old_hfont = SelectObject(hdc, hfont);
343 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
344 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
345 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
346 SelectObject(hdc, old_hfont);
349 bitmap_lf.lfHeight = 0;
350 bitmap_lf.lfWidth = 4;
351 hfont = create_font("bitmap", &bitmap_lf);
352 old_hfont = SelectObject(hdc, hfont);
353 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
354 SelectObject(hdc, old_hfont);
357 bitmap_lf.lfHeight = height_orig;
358 bitmap_lf.lfWidth = lfWidth;
360 /* test fractional scaling */
361 for (i = 1; i <= height_orig * 6; i++)
365 bitmap_lf.lfHeight = i;
366 hfont = create_font("fractional", &bitmap_lf);
367 scale = (i + height_orig - 1) / height_orig;
368 nearest_height = scale * height_orig;
369 /* Only jump to the next height if the difference <= 25% original height */
370 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
371 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
372 so we'll not test this particular height. */
373 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
374 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
375 old_hfont = SelectObject(hdc, hfont);
376 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
377 SelectObject(hdc, old_hfont);
381 /* test integer scaling 3x2 */
382 bitmap_lf.lfHeight = height_orig * 2;
383 bitmap_lf.lfWidth *= 3;
384 hfont = create_font("3x2", &bitmap_lf);
385 old_hfont = SelectObject(hdc, hfont);
386 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
387 SelectObject(hdc, old_hfont);
390 /* test integer scaling 3x3 */
391 bitmap_lf.lfHeight = height_orig * 3;
392 bitmap_lf.lfWidth = 0;
393 hfont = create_font("3x3", &bitmap_lf);
394 old_hfont = SelectObject(hdc, hfont);
395 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
396 SelectObject(hdc, old_hfont);
402 /* Test how GDI scales outline font metrics */
403 static void test_outline_font(void)
405 static const char test_str[11] = "Test String";
408 HFONT hfont, old_hfont, old_hfont_2;
409 OUTLINETEXTMETRICA otm;
411 INT width_orig, height_orig, lfWidth;
414 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
418 if (!is_truetype_font_installed("Arial"))
420 skip("Arial is not installed\n");
424 hdc = CreateCompatibleDC(0);
426 memset(&lf, 0, sizeof(lf));
427 strcpy(lf.lfFaceName, "Arial");
429 hfont = create_font("outline", &lf);
430 old_hfont = SelectObject(hdc, hfont);
431 otm.otmSize = sizeof(otm);
432 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
433 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
434 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
436 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
437 SelectObject(hdc, old_hfont);
440 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
441 lf.lfHeight = otm.otmEMSquare;
442 lf.lfHeight = -lf.lfHeight;
443 hfont = create_font("outline", &lf);
444 old_hfont = SelectObject(hdc, hfont);
445 otm.otmSize = sizeof(otm);
446 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
447 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
448 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
449 SelectObject(hdc, old_hfont);
452 height_orig = otm.otmTextMetrics.tmHeight;
453 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
455 /* test integer scaling 3x2 */
456 lf.lfHeight = height_orig * 2;
457 lf.lfWidth = lfWidth * 3;
458 hfont = create_font("3x2", &lf);
459 old_hfont = SelectObject(hdc, hfont);
460 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
461 SelectObject(hdc, old_hfont);
464 /* test integer scaling 3x3 */
465 lf.lfHeight = height_orig * 3;
466 lf.lfWidth = lfWidth * 3;
467 hfont = create_font("3x3", &lf);
468 old_hfont = SelectObject(hdc, hfont);
469 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
470 SelectObject(hdc, old_hfont);
473 /* test integer scaling 1x1 */
474 lf.lfHeight = height_orig * 1;
475 lf.lfWidth = lfWidth * 1;
476 hfont = create_font("1x1", &lf);
477 old_hfont = SelectObject(hdc, hfont);
478 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
479 SelectObject(hdc, old_hfont);
482 /* test integer scaling 1x1 */
483 lf.lfHeight = height_orig;
485 hfont = create_font("1x1", &lf);
486 old_hfont = SelectObject(hdc, hfont);
487 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
489 /* with an identity matrix */
490 memset(&gm, 0, sizeof(gm));
491 SetLastError(0xdeadbeef);
492 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
493 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
495 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
496 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
497 /* with a custom matrix */
498 memset(&gm, 0, sizeof(gm));
499 SetLastError(0xdeadbeef);
500 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
501 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
502 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
503 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
504 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
506 /* Test that changing the DC transformation affects only the font
507 * selected on this DC and doesn't affect the same font selected on
510 hdc_2 = CreateCompatibleDC(0);
511 old_hfont_2 = SelectObject(hdc_2, hfont);
512 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
514 SetMapMode(hdc, MM_ANISOTROPIC);
516 /* font metrics on another DC should be unchanged */
517 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
519 /* test restrictions of compatibility mode GM_COMPATIBLE */
520 /* part 1: rescaling only X should not change font scaling on screen.
521 So compressing the X axis by 2 is not done, and this
522 appears as X scaling of 2 that no one requested. */
523 SetWindowExtEx(hdc, 100, 100, NULL);
524 SetViewportExtEx(hdc, 50, 100, NULL);
525 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
526 /* font metrics on another DC should be unchanged */
527 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
529 /* part 2: rescaling only Y should change font scaling.
530 As also X is scaled by a factor of 2, but this is not
531 requested by the DC transformation, we get a scaling factor
532 of 2 in the X coordinate. */
533 SetViewportExtEx(hdc, 100, 200, NULL);
534 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
535 /* font metrics on another DC should be unchanged */
536 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
538 /* restore scaling */
539 SetMapMode(hdc, MM_TEXT);
541 /* font metrics on another DC should be unchanged */
542 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
544 SelectObject(hdc_2, old_hfont_2);
547 if (!SetGraphicsMode(hdc, GM_ADVANCED))
549 SelectObject(hdc, old_hfont);
552 skip("GM_ADVANCED is not supported on this platform\n");
563 SetLastError(0xdeadbeef);
564 ret = SetWorldTransform(hdc, &xform);
565 ok(ret, "SetWorldTransform error %u\n", GetLastError());
567 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
569 /* with an identity matrix */
570 memset(&gm, 0, sizeof(gm));
571 SetLastError(0xdeadbeef);
572 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
573 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
574 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
575 pt.x = width_orig; pt.y = 0;
577 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
578 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
579 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
580 /* with a custom matrix */
581 memset(&gm, 0, sizeof(gm));
582 SetLastError(0xdeadbeef);
583 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
584 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
585 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
586 pt.x = width_orig; pt.y = 0;
588 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
589 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
592 SetLastError(0xdeadbeef);
593 ret = SetMapMode(hdc, MM_LOMETRIC);
594 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
596 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
598 /* with an identity matrix */
599 memset(&gm, 0, sizeof(gm));
600 SetLastError(0xdeadbeef);
601 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
602 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
604 pt.x = width_orig; pt.y = 0;
606 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
607 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
608 /* with a custom matrix */
609 memset(&gm, 0, sizeof(gm));
610 SetLastError(0xdeadbeef);
611 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
612 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
613 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
614 pt.x = width_orig; pt.y = 0;
616 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
617 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
619 SetLastError(0xdeadbeef);
620 ret = SetMapMode(hdc, MM_TEXT);
621 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
623 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
625 /* with an identity matrix */
626 memset(&gm, 0, sizeof(gm));
627 SetLastError(0xdeadbeef);
628 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
629 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
630 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
631 pt.x = width_orig; pt.y = 0;
633 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
634 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
635 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
636 /* with a custom matrix */
637 memset(&gm, 0, sizeof(gm));
638 SetLastError(0xdeadbeef);
639 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
640 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
641 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
642 pt.x = width_orig; pt.y = 0;
644 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
645 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
646 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
648 SelectObject(hdc, old_hfont);
653 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
655 LOGFONT *lf = (LOGFONT *)lParam;
657 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
660 return 0; /* stop enumeration */
662 return 1; /* continue enumeration */
665 static void test_bitmap_font_metrics(void)
667 static const struct font_data
669 const char face_name[LF_FACESIZE];
670 int weight, height, ascent, descent, int_leading, ext_leading;
671 int ave_char_width, max_char_width, dpi;
676 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
677 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
679 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
680 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
681 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
682 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
684 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
685 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
688 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
689 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
690 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
691 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
693 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
694 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
695 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
697 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
698 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
699 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
700 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
701 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
702 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
703 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
705 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
706 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
707 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
709 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
710 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
711 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
712 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
713 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
717 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
719 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
721 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
722 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
723 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
724 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
725 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
727 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
728 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
729 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
731 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
732 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
733 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
735 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
736 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
737 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
739 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
740 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
742 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
743 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
744 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
745 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1, LANG_ARABIC },
746 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
747 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
748 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1, LANG_ARABIC },
749 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
750 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_ARABIC },
751 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
752 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1, LANG_ARABIC },
753 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
754 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_ARABIC },
755 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
757 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, FS_ARABIC },
759 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
761 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, FS_ARABIC },
762 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
765 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
766 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
767 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
768 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
769 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
770 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
771 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
772 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
773 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
774 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
775 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
777 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
778 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
779 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
781 /* The 120dpi version still has its dpi marked as 96 */
782 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
784 /* FIXME: add "Terminal" */
788 HFONT hfont, old_hfont;
793 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
795 hdc = CreateCompatibleDC(0);
798 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
802 memset(&lf, 0, sizeof(lf));
804 lf.lfHeight = fd[i].height;
805 strcpy(lf.lfFaceName, fd[i].face_name);
807 for(bit = 0; bit < 32; bit++)
815 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
816 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
818 lf.lfCharSet = csi.ciCharset;
819 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
822 hfont = create_font(lf.lfFaceName, &lf);
823 old_hfont = SelectObject(hdc, hfont);
824 bRet = GetTextMetrics(hdc, &tm);
825 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
826 if(fd[i].dpi == tm.tmDigitizedAspectX)
828 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
829 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
831 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);
832 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);
833 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);
834 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);
835 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);
836 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);
837 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);
839 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
840 that make the max width bigger */
841 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
842 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);
845 skip("Skipping font metrics test for system langid 0x%x\n",
848 SelectObject(hdc, old_hfont);
856 static void test_GdiGetCharDimensions(void)
862 LONG avgwidth, height;
863 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
865 if (!pGdiGetCharDimensions)
867 win_skip("GdiGetCharDimensions not available on this platform\n");
871 hdc = CreateCompatibleDC(NULL);
873 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
874 avgwidth = ((size.cx / 26) + 1) / 2;
876 ret = pGdiGetCharDimensions(hdc, &tm, &height);
877 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
878 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
880 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
881 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
883 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
884 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
887 ret = pGdiGetCharDimensions(hdc, NULL, &height);
888 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
889 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
894 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
895 const TEXTMETRIC *lpntme,
896 DWORD FontType, LPARAM lParam)
898 if (FontType & TRUETYPE_FONTTYPE)
902 hfont = CreateFontIndirect(lpelfe);
905 *(HFONT *)lParam = hfont;
913 static void test_GetCharABCWidths(void)
915 static const WCHAR str[] = {'a',0};
936 {0xffffff, 0xffffff},
937 {0x1000000, 0x1000000},
938 {0xffffff, 0x1000000},
939 {0xffffffff, 0xffffffff}
946 BOOL r[sizeof range / sizeof range[0]];
949 {ANSI_CHARSET, 0x30, 0x30, {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
950 {SHIFTJIS_CHARSET, 0x82a0, 0x3042, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
951 {HANGEUL_CHARSET, 0x8141, 0xac02, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
952 {JOHAB_CHARSET, 0x8446, 0x3135, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
953 {GB2312_CHARSET, 0x8141, 0x4e04, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
954 {CHINESEBIG5_CHARSET, 0xa142, 0x3001, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}}
958 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsI)
960 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
964 memset(&lf, 0, sizeof(lf));
965 strcpy(lf.lfFaceName, "System");
968 hfont = CreateFontIndirectA(&lf);
970 hfont = SelectObject(hdc, hfont);
972 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
973 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
975 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
976 ok(!ret, "GetCharABCWidthsI should have failed\n");
978 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
979 ok(!ret, "GetCharABCWidthsI should have failed\n");
981 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
982 ok(ret, "GetCharABCWidthsI should have succeeded\n");
984 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
985 ok(!ret, "GetCharABCWidthsW should have failed\n");
987 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
988 ok(!ret, "GetCharABCWidthsW should have failed\n");
990 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
991 ok(!ret, "GetCharABCWidthsW should have failed\n");
993 hfont = SelectObject(hdc, hfont);
996 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1000 UINT code = 0x41, j;
1002 lf.lfFaceName[0] = '\0';
1003 lf.lfCharSet = c[i].cs;
1004 lf.lfPitchAndFamily = 0;
1005 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1007 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1011 memset(a, 0, sizeof a);
1012 memset(w, 0, sizeof w);
1013 hfont = SelectObject(hdc, hfont);
1014 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1015 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1016 memcmp(a, w, sizeof a) == 0,
1017 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1019 memset(a, 0xbb, sizeof a);
1020 ret = pGetCharABCWidthsA(hdc, code, code, a);
1021 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1022 memset(full, 0xcc, sizeof full);
1023 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1024 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1025 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1026 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1028 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1030 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1031 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1032 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1035 hfont = SelectObject(hdc, hfont);
1036 DeleteObject(hfont);
1039 ReleaseDC(NULL, hdc);
1042 static void test_text_extents(void)
1044 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1046 INT i, len, fit1, fit2;
1054 memset(&lf, 0, sizeof(lf));
1055 strcpy(lf.lfFaceName, "Arial");
1058 hfont = CreateFontIndirectA(&lf);
1060 hfont = SelectObject(hdc, hfont);
1061 GetTextMetricsA(hdc, &tm);
1062 GetTextExtentPointA(hdc, "o", 1, &sz);
1063 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1065 SetLastError(0xdeadbeef);
1066 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1067 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1069 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1070 hfont = SelectObject(hdc, hfont);
1071 DeleteObject(hfont);
1077 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1078 extents[0] = 1; /* So that the increasing sequence test will fail
1079 if the extents array is untouched. */
1080 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1081 GetTextExtentPointW(hdc, wt, len, &sz2);
1082 ok(sz1.cy == sz2.cy,
1083 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1084 /* Because of the '\n' in the string GetTextExtentExPoint and
1085 GetTextExtentPoint return different widths under Win2k, but
1086 under WinXP they return the same width. So we don't test that
1089 for (i = 1; i < len; ++i)
1090 ok(extents[i-1] <= extents[i],
1091 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1093 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1094 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1095 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1096 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1097 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1098 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1099 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1100 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1101 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1102 ok(extents[0] == extents[2] && extents[1] == extents[3],
1103 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1104 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1105 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1106 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1107 HeapFree(GetProcessHeap(), 0, extents);
1109 hfont = SelectObject(hdc, hfont);
1110 DeleteObject(hfont);
1111 ReleaseDC(NULL, hdc);
1114 static void test_GetGlyphIndices(void)
1121 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1122 WORD glyphs[(sizeof(testtext)/2)-1];
1126 if (!pGetGlyphIndicesW) {
1127 win_skip("GetGlyphIndicesW not available on platform\n");
1133 memset(&lf, 0, sizeof(lf));
1134 strcpy(lf.lfFaceName, "System");
1136 lf.lfCharSet = ANSI_CHARSET;
1138 hfont = CreateFontIndirectA(&lf);
1139 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1140 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1141 if (textm.tmCharSet == ANSI_CHARSET)
1143 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1144 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1145 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1146 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1148 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1149 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1150 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1151 textm.tmDefaultChar, glyphs[4]);
1154 /* FIXME: Write tests for non-ANSI charsets. */
1155 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1157 if(!is_font_installed("Tahoma"))
1159 skip("Tahoma is not installed so skipping this test\n");
1162 memset(&lf, 0, sizeof(lf));
1163 strcpy(lf.lfFaceName, "Tahoma");
1166 hfont = CreateFontIndirectA(&lf);
1167 hOldFont = SelectObject(hdc, hfont);
1168 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1169 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1170 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1171 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1172 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1174 testtext[0] = textm.tmDefaultChar;
1175 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1176 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1177 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1178 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1179 DeleteObject(SelectObject(hdc, hOldFont));
1182 static void test_GetKerningPairs(void)
1184 static const struct kerning_data
1186 const char face_name[LF_FACESIZE];
1188 /* some interesting fields from OUTLINETEXTMETRIC */
1189 LONG tmHeight, tmAscent, tmDescent;
1194 UINT otmsCapEmHeight;
1199 UINT otmusMinimumPPEM;
1200 /* small subset of kerning pairs to test */
1201 DWORD total_kern_pairs;
1202 const KERNINGPAIR kern_pair[26];
1205 {"Arial", 12, 12, 9, 3,
1206 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1209 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1210 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1211 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1212 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1213 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1214 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1215 {933,970,+1},{933,972,-1}
1218 {"Arial", -34, 39, 32, 7,
1219 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1222 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1223 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1224 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1225 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1226 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1227 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1228 {933,970,+2},{933,972,-3}
1231 { "Arial", 120, 120, 97, 23,
1232 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1235 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1236 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1237 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1238 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1239 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1240 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1241 {933,970,+6},{933,972,-10}
1244 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1245 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1246 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1249 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1250 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1251 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1252 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1253 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1254 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1255 {933,970,+54},{933,972,-83}
1261 HFONT hfont, hfont_old;
1262 KERNINGPAIR *kern_pair;
1264 DWORD total_kern_pairs, ret, i, n, matches;
1268 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1269 * which may render this test unusable, so we're trying to avoid that.
1271 SetLastError(0xdeadbeef);
1272 GetKerningPairsW(hdc, 0, NULL);
1273 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1275 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1280 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1282 OUTLINETEXTMETRICW otm;
1285 if (!is_font_installed(kd[i].face_name))
1287 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1291 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1293 memset(&lf, 0, sizeof(lf));
1294 strcpy(lf.lfFaceName, kd[i].face_name);
1295 lf.lfHeight = kd[i].height;
1296 hfont = CreateFontIndirect(&lf);
1299 hfont_old = SelectObject(hdc, hfont);
1301 SetLastError(0xdeadbeef);
1302 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1303 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1304 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1306 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1307 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1308 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1309 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1310 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1311 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1313 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1314 kd[i].otmEMSquare, otm.otmEMSquare);
1315 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1316 kd[i].otmAscent, otm.otmAscent);
1317 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1318 kd[i].otmDescent, otm.otmDescent);
1319 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1320 kd[i].otmLineGap, otm.otmLineGap);
1321 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1322 kd[i].otmMacDescent, otm.otmMacDescent);
1323 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1324 kd[i].otmMacAscent, otm.otmMacAscent);
1326 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1327 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1328 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1329 kd[i].otmsXHeight, otm.otmsXHeight);
1330 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1331 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1332 kd[i].otmMacLineGap, otm.otmMacLineGap);
1333 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1334 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1337 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1338 trace("total_kern_pairs %u\n", total_kern_pairs);
1339 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1341 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1342 SetLastError(0xdeadbeef);
1343 ret = GetKerningPairsW(hdc, 0, kern_pair);
1344 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1345 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1346 ok(ret == 0, "got %lu, expected 0\n", ret);
1349 ret = GetKerningPairsW(hdc, 100, NULL);
1350 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1352 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1353 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1355 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1356 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1360 for (n = 0; n < ret; n++)
1364 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1365 trace("{'%c','%c',%d},\n",
1366 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1368 for (j = 0; j < kd[i].total_kern_pairs; j++)
1370 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1371 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1373 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1374 "pair %d:%d got %d, expected %d\n",
1375 kern_pair[n].wFirst, kern_pair[n].wSecond,
1376 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1382 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1383 matches, kd[i].total_kern_pairs);
1385 HeapFree(GetProcessHeap(), 0, kern_pair);
1387 SelectObject(hdc, hfont_old);
1388 DeleteObject(hfont);
1394 static void test_height_selection(void)
1396 static const struct font_data
1398 const char face_name[LF_FACESIZE];
1399 int requested_height;
1400 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1403 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1404 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1405 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1406 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1407 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1408 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1409 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1410 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1411 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1412 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1416 HFONT hfont, old_hfont;
1420 hdc = CreateCompatibleDC(0);
1423 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1425 if (!is_truetype_font_installed(fd[i].face_name))
1427 skip("%s is not installed\n", fd[i].face_name);
1431 memset(&lf, 0, sizeof(lf));
1432 lf.lfHeight = fd[i].requested_height;
1433 lf.lfWeight = fd[i].weight;
1434 strcpy(lf.lfFaceName, fd[i].face_name);
1436 hfont = CreateFontIndirect(&lf);
1439 old_hfont = SelectObject(hdc, hfont);
1440 ret = GetTextMetrics(hdc, &tm);
1441 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1442 if(fd[i].dpi == tm.tmDigitizedAspectX)
1444 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1445 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);
1446 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);
1447 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);
1448 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);
1449 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1450 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);
1452 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);
1455 SelectObject(hdc, old_hfont);
1456 DeleteObject(hfont);
1462 static void test_GetOutlineTextMetrics(void)
1464 OUTLINETEXTMETRIC *otm;
1466 HFONT hfont, hfont_old;
1468 DWORD ret, otm_size;
1471 if (!is_font_installed("Arial"))
1473 skip("Arial is not installed\n");
1479 memset(&lf, 0, sizeof(lf));
1480 strcpy(lf.lfFaceName, "Arial");
1482 lf.lfWeight = FW_NORMAL;
1483 lf.lfPitchAndFamily = DEFAULT_PITCH;
1484 lf.lfQuality = PROOF_QUALITY;
1485 hfont = CreateFontIndirect(&lf);
1488 hfont_old = SelectObject(hdc, hfont);
1489 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1490 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1492 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1494 memset(otm, 0xAA, otm_size);
1495 SetLastError(0xdeadbeef);
1496 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1497 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1498 ok(ret == 1 /* Win9x */ ||
1499 ret == otm->otmSize /* XP*/,
1500 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1501 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1503 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1504 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1505 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1506 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1509 memset(otm, 0xAA, otm_size);
1510 SetLastError(0xdeadbeef);
1511 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1512 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1513 ok(ret == 1 /* Win9x */ ||
1514 ret == otm->otmSize /* XP*/,
1515 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1516 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1518 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1519 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1520 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1521 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1524 /* ask about truncated data */
1525 memset(otm, 0xAA, otm_size);
1526 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1527 SetLastError(0xdeadbeef);
1528 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1529 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1530 ok(ret == 1 /* Win9x */ ||
1531 ret == otm->otmSize /* XP*/,
1532 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1533 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1535 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1536 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1537 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1539 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1541 HeapFree(GetProcessHeap(), 0, otm);
1543 SelectObject(hdc, hfont_old);
1544 DeleteObject(hfont);
1549 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1553 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1554 areaWidth = clientArea->right - clientArea->left,
1556 BOOL lastExtent = FALSE;
1557 PSTR pFirstChar, pLastChar;
1563 int GetTextExtentExPointWWidth;
1566 GetTextMetricsA(hdc, &tm);
1567 y = clientArea->top;
1570 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1576 /* if not at the end of the string, ... */
1577 if (*str == '\0') break;
1578 /* ... add the next word to the current extent */
1579 while (*str != '\0' && *str++ != tm.tmBreakChar);
1581 SetTextJustification(hdc, 0, 0);
1582 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1583 } while ((int) size.cx < areaWidth);
1585 /* ignore trailing break chars */
1587 while (*(pLastChar - 1) == tm.tmBreakChar)
1593 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1595 SetTextJustification(hdc, 0, 0);
1596 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1598 /* do not justify the last extent */
1599 if (*str != '\0' && breakCount > 0)
1601 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1602 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1603 justifiedWidth = size.cx;
1605 else lastExtent = TRUE;
1607 /* catch errors and report them */
1608 if (!lastExtent && (justifiedWidth != areaWidth))
1610 memset(error[nErrors].extent, 0, 100);
1611 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1612 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1618 } while (*str && y < clientArea->bottom);
1620 for (e = 0; e < nErrors; e++)
1622 /* The width returned by GetTextExtentPoint32() is exactly the same
1623 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1624 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1625 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1626 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1630 static void test_SetTextJustification(void)
1637 static char testText[] =
1638 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1639 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1640 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1641 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1642 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1643 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1644 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1646 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1647 GetClientRect( hwnd, &clientArea );
1648 hdc = GetDC( hwnd );
1650 memset(&lf, 0, sizeof lf);
1651 lf.lfCharSet = ANSI_CHARSET;
1652 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1653 lf.lfWeight = FW_DONTCARE;
1655 lf.lfQuality = DEFAULT_QUALITY;
1656 lstrcpyA(lf.lfFaceName, "Times New Roman");
1657 hfont = create_font("Times New Roman", &lf);
1658 SelectObject(hdc, hfont);
1660 testJustification(hdc, testText, &clientArea);
1662 DeleteObject(hfont);
1663 ReleaseDC(hwnd, hdc);
1664 DestroyWindow(hwnd);
1667 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1671 HFONT hfont, hfont_old;
1678 assert(count <= 128);
1680 memset(&lf, 0, sizeof(lf));
1682 lf.lfCharSet = charset;
1684 lstrcpyA(lf.lfFaceName, "Arial");
1685 SetLastError(0xdeadbeef);
1686 hfont = CreateFontIndirectA(&lf);
1687 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1690 hfont_old = SelectObject(hdc, hfont);
1692 cs = GetTextCharsetInfo(hdc, &fs, 0);
1693 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1695 SetLastError(0xdeadbeef);
1696 ret = GetTextFaceA(hdc, sizeof(name), name);
1697 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1699 if (charset == SYMBOL_CHARSET)
1701 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1702 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1706 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1707 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1710 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1712 trace("Can't find codepage for charset %d\n", cs);
1716 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1718 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1720 skip("Font code page %d, looking for code page %d\n",
1721 pGdiGetCodePage(hdc), code_page);
1729 WCHAR unicode_buf[128];
1731 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1733 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1735 SetLastError(0xdeadbeef);
1736 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1737 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1738 count, ret, GetLastError());
1744 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1746 SetLastError(0xdeadbeef);
1747 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1748 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1749 count, ret, GetLastError());
1752 SelectObject(hdc, hfont_old);
1753 DeleteObject(hfont);
1760 static void test_font_charset(void)
1762 static struct charset_data
1766 WORD font_idxA[128], font_idxW[128];
1769 { ANSI_CHARSET, 1252 },
1770 { RUSSIAN_CHARSET, 1251 },
1771 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1775 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1777 win_skip("Skipping the font charset test on a Win9x platform\n");
1781 if (!is_font_installed("Arial"))
1783 skip("Arial is not installed\n");
1787 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1789 if (cd[i].charset == SYMBOL_CHARSET)
1791 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1793 skip("Symbol or Wingdings is not installed\n");
1797 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1798 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1799 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1802 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1805 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1806 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1809 skip("Symbol or Wingdings is not installed\n");
1812 static void test_GetFontUnicodeRanges(void)
1816 HFONT hfont, hfont_old;
1820 if (!pGetFontUnicodeRanges)
1822 win_skip("GetFontUnicodeRanges not available before W2K\n");
1826 memset(&lf, 0, sizeof(lf));
1827 lstrcpyA(lf.lfFaceName, "Arial");
1828 hfont = create_font("Arial", &lf);
1831 hfont_old = SelectObject(hdc, hfont);
1833 size = pGetFontUnicodeRanges(NULL, NULL);
1834 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1836 size = pGetFontUnicodeRanges(hdc, NULL);
1837 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1839 gs = HeapAlloc(GetProcessHeap(), 0, size);
1841 size = pGetFontUnicodeRanges(hdc, gs);
1842 ok(size, "GetFontUnicodeRanges failed\n");
1844 for (i = 0; i < gs->cRanges; i++)
1845 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1847 trace("found %u ranges\n", gs->cRanges);
1849 HeapFree(GetProcessHeap(), 0, gs);
1851 SelectObject(hdc, hfont_old);
1852 DeleteObject(hfont);
1853 ReleaseDC(NULL, hdc);
1856 #define MAX_ENUM_FONTS 4096
1858 struct enum_font_data
1861 LOGFONT lf[MAX_ENUM_FONTS];
1864 struct enum_font_dataW
1867 LOGFONTW lf[MAX_ENUM_FONTS];
1870 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1872 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1874 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1876 if (type != TRUETYPE_FONTTYPE) return 1;
1878 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1879 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1881 if (efd->total < MAX_ENUM_FONTS)
1882 efd->lf[efd->total++] = *lf;
1884 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1889 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1891 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1893 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1895 if (type != TRUETYPE_FONTTYPE) return 1;
1897 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1898 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1900 if (efd->total < MAX_ENUM_FONTS)
1901 efd->lf[efd->total++] = *lf;
1903 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1908 static void get_charset_stats(struct enum_font_data *efd,
1909 int *ansi_charset, int *symbol_charset,
1910 int *russian_charset)
1915 *symbol_charset = 0;
1916 *russian_charset = 0;
1918 for (i = 0; i < efd->total; i++)
1920 switch (efd->lf[i].lfCharSet)
1925 case SYMBOL_CHARSET:
1926 (*symbol_charset)++;
1928 case RUSSIAN_CHARSET:
1929 (*russian_charset)++;
1935 static void get_charset_statsW(struct enum_font_dataW *efd,
1936 int *ansi_charset, int *symbol_charset,
1937 int *russian_charset)
1942 *symbol_charset = 0;
1943 *russian_charset = 0;
1945 for (i = 0; i < efd->total; i++)
1947 switch (efd->lf[i].lfCharSet)
1952 case SYMBOL_CHARSET:
1953 (*symbol_charset)++;
1955 case RUSSIAN_CHARSET:
1956 (*russian_charset)++;
1962 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1964 struct enum_font_data efd;
1965 struct enum_font_dataW efdw;
1968 int i, ret, ansi_charset, symbol_charset, russian_charset;
1970 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1972 if (*font_name && !is_truetype_font_installed(font_name))
1974 skip("%s is not installed\n", font_name);
1980 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1981 * while EnumFontFamiliesEx doesn't.
1983 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1986 * Use EnumFontFamiliesW since win98 crashes when the
1987 * second parameter is NULL using EnumFontFamilies
1990 SetLastError(0xdeadbeef);
1991 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1992 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1995 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1996 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1997 ansi_charset, symbol_charset, russian_charset);
1998 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1999 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2000 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2001 ok(russian_charset > 0 ||
2002 broken(russian_charset == 0), /* NT4 */
2003 "NULL family should enumerate RUSSIAN_CHARSET\n");
2007 SetLastError(0xdeadbeef);
2008 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2009 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2012 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2013 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2014 ansi_charset, symbol_charset, russian_charset);
2015 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2016 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2017 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2018 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2023 SetLastError(0xdeadbeef);
2024 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2025 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2026 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2027 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2028 ansi_charset, symbol_charset, russian_charset,
2029 *font_name ? font_name : "<empty>");
2031 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2033 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2034 for (i = 0; i < efd.total; i++)
2036 /* FIXME: remove completely once Wine is fixed */
2037 if (efd.lf[i].lfCharSet != font_charset)
2040 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2043 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2044 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2045 font_name, efd.lf[i].lfFaceName);
2048 memset(&lf, 0, sizeof(lf));
2049 lf.lfCharSet = ANSI_CHARSET;
2050 lstrcpy(lf.lfFaceName, font_name);
2052 SetLastError(0xdeadbeef);
2053 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2054 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2055 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2056 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2057 ansi_charset, symbol_charset, russian_charset,
2058 *font_name ? font_name : "<empty>");
2059 if (font_charset == SYMBOL_CHARSET)
2062 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2064 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2068 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2069 for (i = 0; i < efd.total; i++)
2071 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2073 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2074 font_name, efd.lf[i].lfFaceName);
2078 /* DEFAULT_CHARSET should enumerate all available charsets */
2079 memset(&lf, 0, sizeof(lf));
2080 lf.lfCharSet = DEFAULT_CHARSET;
2081 lstrcpy(lf.lfFaceName, font_name);
2083 SetLastError(0xdeadbeef);
2084 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2085 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2086 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2087 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2088 ansi_charset, symbol_charset, russian_charset,
2089 *font_name ? font_name : "<empty>");
2090 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2091 for (i = 0; i < efd.total; i++)
2094 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2095 font_name, efd.lf[i].lfFaceName);
2099 switch (font_charset)
2102 ok(ansi_charset > 0,
2103 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2105 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2106 ok(russian_charset > 0,
2107 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2109 case SYMBOL_CHARSET:
2111 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2113 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2114 ok(!russian_charset,
2115 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2117 case DEFAULT_CHARSET:
2118 ok(ansi_charset > 0,
2119 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2120 ok(symbol_charset > 0,
2121 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2122 ok(russian_charset > 0,
2123 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2129 ok(ansi_charset > 0,
2130 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2131 ok(symbol_charset > 0,
2132 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2133 ok(russian_charset > 0,
2134 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2137 memset(&lf, 0, sizeof(lf));
2138 lf.lfCharSet = SYMBOL_CHARSET;
2139 lstrcpy(lf.lfFaceName, font_name);
2141 SetLastError(0xdeadbeef);
2142 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2143 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2144 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2145 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2146 ansi_charset, symbol_charset, russian_charset,
2147 *font_name ? font_name : "<empty>");
2148 if (*font_name && font_charset == ANSI_CHARSET)
2149 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2152 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2153 for (i = 0; i < efd.total; i++)
2155 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2157 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2158 font_name, efd.lf[i].lfFaceName);
2162 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2163 ok(symbol_charset > 0,
2164 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2165 ok(!russian_charset,
2166 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2172 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2174 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2176 if (type != TRUETYPE_FONTTYPE) return 1;
2178 if (efd->total < MAX_ENUM_FONTS)
2179 efd->lf[efd->total++] = *lf;
2181 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2186 static void test_EnumFontFamiliesEx_default_charset(void)
2188 struct enum_font_data efd;
2189 LOGFONT gui_font, enum_font;
2193 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2194 ok(ret, "GetObject failed.\n");
2201 memset(&enum_font, 0, sizeof(enum_font));
2202 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2203 enum_font.lfCharSet = DEFAULT_CHARSET;
2204 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2207 if (efd.total == 0) {
2208 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2211 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2213 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2214 "(%s) got charset %d expected %d\n",
2215 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2220 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2222 HFONT hfont, hfont_prev;
2224 GLYPHMETRICS gm1, gm2;
2228 if(!pGetGlyphIndicesA)
2231 /* negative widths are handled just as positive ones */
2232 lf2.lfWidth = -lf->lfWidth;
2234 SetLastError(0xdeadbeef);
2235 hfont = CreateFontIndirectA(lf);
2236 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2237 check_font("original", lf, hfont);
2239 hfont_prev = SelectObject(hdc, hfont);
2241 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2242 if (ret == GDI_ERROR || idx == 0xffff)
2244 SelectObject(hdc, hfont_prev);
2245 DeleteObject(hfont);
2246 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2250 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2251 memset(&gm1, 0xab, sizeof(gm1));
2252 SetLastError(0xdeadbeef);
2253 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2254 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2256 SelectObject(hdc, hfont_prev);
2257 DeleteObject(hfont);
2259 SetLastError(0xdeadbeef);
2260 hfont = CreateFontIndirectA(&lf2);
2261 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2262 check_font("negative width", &lf2, hfont);
2264 hfont_prev = SelectObject(hdc, hfont);
2266 memset(&gm2, 0xbb, sizeof(gm2));
2267 SetLastError(0xdeadbeef);
2268 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2269 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2271 SelectObject(hdc, hfont_prev);
2272 DeleteObject(hfont);
2274 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2275 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2276 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2277 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2278 gm1.gmCellIncX == gm2.gmCellIncX &&
2279 gm1.gmCellIncY == gm2.gmCellIncY,
2280 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2281 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2282 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2283 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2284 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2287 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2288 #include "pshpack2.h"
2292 SHORT xAvgCharWidth;
2293 USHORT usWeightClass;
2294 USHORT usWidthClass;
2296 SHORT ySubscriptXSize;
2297 SHORT ySubscriptYSize;
2298 SHORT ySubscriptXOffset;
2299 SHORT ySubscriptYOffset;
2300 SHORT ySuperscriptXSize;
2301 SHORT ySuperscriptYSize;
2302 SHORT ySuperscriptXOffset;
2303 SHORT ySuperscriptYOffset;
2304 SHORT yStrikeoutSize;
2305 SHORT yStrikeoutPosition;
2308 ULONG ulUnicodeRange1;
2309 ULONG ulUnicodeRange2;
2310 ULONG ulUnicodeRange3;
2311 ULONG ulUnicodeRange4;
2314 USHORT usFirstCharIndex;
2315 USHORT usLastCharIndex;
2316 /* According to the Apple spec, original version didn't have the below fields,
2317 * version numbers were taked from the OpenType spec.
2319 /* version 0 (TrueType 1.5) */
2320 USHORT sTypoAscender;
2321 USHORT sTypoDescender;
2322 USHORT sTypoLineGap;
2324 USHORT usWinDescent;
2325 /* version 1 (TrueType 1.66) */
2326 ULONG ulCodePageRange1;
2327 ULONG ulCodePageRange2;
2328 /* version 2 (OpenType 1.2) */
2331 USHORT usDefaultChar;
2333 USHORT usMaxContext;
2335 #include "poppack.h"
2337 #ifdef WORDS_BIGENDIAN
2338 #define GET_BE_WORD(x) (x)
2339 #define GET_BE_DWORD(x) (x)
2341 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2342 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2345 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2346 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2347 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2348 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2349 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2362 } cmap_encoding_record;
2370 BYTE glyph_ids[256];
2380 USHORT search_range;
2381 USHORT entry_selector;
2384 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2387 USHORT start_count[seg_countx2 / 2];
2388 USHORT id_delta[seg_countx2 / 2];
2389 USHORT id_range_offset[seg_countx2 / 2];
2399 USHORT id_range_offset;
2400 } cmap_format_4_seg;
2402 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2404 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2405 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2406 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2407 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2408 os2->panose.bWeight, os2->panose.bProportion);
2411 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2414 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2418 for(i = 0; i < 256; i++)
2420 if(cmap->glyph_ids[i] == 0) continue;
2422 if(*first == 256) *first = i;
2424 if(*first == 256) return FALSE;
2428 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2430 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2431 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2432 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2433 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2434 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2437 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2440 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2441 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2442 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2446 for(i = 0; i < seg_count; i++)
2449 cmap_format_4_seg seg;
2451 get_seg4(cmap, i, &seg);
2452 for(code = seg.start_count; code <= seg.end_count; code++)
2454 if(seg.id_range_offset == 0)
2455 index = (seg.id_delta + code) & 0xffff;
2458 index = seg.id_range_offset / 2
2459 + code - seg.start_count
2462 /* some fonts have broken last segment */
2463 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2464 index = GET_BE_WORD(glyph_ids[index]);
2467 trace("segment %04x/%04x index %04x points to nowhere\n",
2468 seg.start_count, seg.end_count, index);
2471 if(index) index += seg.id_delta;
2473 if(*first == 0x10000)
2474 *last = *first = code;
2480 if(*first == 0x10000) return FALSE;
2484 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2487 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2489 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2491 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2492 return (BYTE *)header + GET_BE_DWORD(record->offset);
2505 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2508 cmap_header *header;
2513 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2514 ok(size != GDI_ERROR, "no cmap table found\n");
2515 if(size == GDI_ERROR) return FALSE;
2517 header = HeapAlloc(GetProcessHeap(), 0, size);
2518 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2519 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2520 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2522 cmap = get_cmap(header, 3, 1);
2524 *cmap_type = cmap_ms_unicode;
2527 cmap = get_cmap(header, 3, 0);
2528 if(cmap) *cmap_type = cmap_ms_symbol;
2532 *cmap_type = cmap_none;
2536 format = GET_BE_WORD(*(WORD *)cmap);
2540 r = get_first_last_from_cmap0(cmap, first, last);
2543 r = get_first_last_from_cmap4(cmap, first, last, size);
2546 trace("unhandled cmap format %d\n", format);
2551 HeapFree(GetProcessHeap(), 0, header);
2555 static void test_text_metrics(const LOGFONTA *lf)
2558 HFONT hfont, hfont_old;
2562 const char *font_name = lf->lfFaceName;
2563 DWORD cmap_first = 0, cmap_last = 0;
2564 cmap_type cmap_type;
2565 BOOL sys_lang_non_english;
2567 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2570 SetLastError(0xdeadbeef);
2571 hfont = CreateFontIndirectA(lf);
2572 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2574 hfont_old = SelectObject(hdc, hfont);
2576 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2577 if (size == GDI_ERROR)
2579 trace("OS/2 chunk was not found\n");
2582 if (size > sizeof(tt_os2))
2584 trace("got too large OS/2 chunk of size %u\n", size);
2585 size = sizeof(tt_os2);
2588 memset(&tt_os2, 0, sizeof(tt_os2));
2589 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2590 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2592 SetLastError(0xdeadbeef);
2593 ret = GetTextMetricsA(hdc, &tmA);
2594 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2596 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2598 skip("Unable to retrieve first and last glyphs from cmap\n");
2602 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2603 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2604 UINT os2_first_char, os2_last_char, default_char, break_char;
2608 version = GET_BE_WORD(tt_os2.version);
2610 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2611 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2612 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2613 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2615 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2616 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2617 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2619 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2624 case 1257: /* Baltic */
2625 expect_last_W = 0xf8fd;
2628 expect_last_W = 0xf0ff;
2630 expect_break_W = 0x20;
2631 expect_default_W = expect_break_W - 1;
2632 expect_first_A = 0x1e;
2633 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2637 expect_first_W = cmap_first;
2638 expect_last_W = min(cmap_last, os2_last_char);
2639 if(os2_first_char <= 1)
2640 expect_break_W = os2_first_char + 2;
2641 else if(os2_first_char > 0xff)
2642 expect_break_W = 0x20;
2644 expect_break_W = os2_first_char;
2645 expect_default_W = expect_break_W - 1;
2646 expect_first_A = expect_default_W - 1;
2647 expect_last_A = min(expect_last_W, 0xff);
2649 expect_break_A = expect_break_W;
2650 expect_default_A = expect_default_W;
2652 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2653 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2654 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2655 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2656 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2658 ok(tmA.tmFirstChar == expect_first_A ||
2659 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2660 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2661 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2662 ok(tmA.tmLastChar == expect_last_A ||
2663 tmA.tmLastChar == 0xff /* win9x */,
2664 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2666 skip("tmLastChar is DBCS lead byte\n");
2667 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2668 font_name, tmA.tmBreakChar, expect_break_A);
2669 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2670 "A: tmDefaultChar for %s got %02x expected %02x\n",
2671 font_name, tmA.tmDefaultChar, expect_default_A);
2674 SetLastError(0xdeadbeef);
2675 ret = GetTextMetricsW(hdc, &tmW);
2676 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2677 "GetTextMetricsW error %u\n", GetLastError());
2680 /* Wine uses the os2 first char */
2681 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2682 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2683 font_name, tmW.tmFirstChar, expect_first_W);
2685 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2686 font_name, tmW.tmFirstChar, expect_first_W);
2688 /* Wine uses the os2 last char */
2689 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2690 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2691 font_name, tmW.tmLastChar, expect_last_W);
2693 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2694 font_name, tmW.tmLastChar, expect_last_W);
2695 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2696 font_name, tmW.tmBreakChar, expect_break_W);
2697 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2698 "W: tmDefaultChar for %s got %02x expected %02x\n",
2699 font_name, tmW.tmDefaultChar, expect_default_W);
2701 /* Test the aspect ratio while we have tmW */
2702 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2703 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2704 tmW.tmDigitizedAspectX, ret);
2705 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2706 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2707 tmW.tmDigitizedAspectX, ret);
2711 /* test FF_ values */
2712 switch(tt_os2.panose.bFamilyType)
2716 case PAN_FAMILY_TEXT_DISPLAY:
2717 case PAN_FAMILY_PICTORIAL:
2719 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2720 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2722 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2725 switch(tt_os2.panose.bSerifStyle)
2730 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2733 case PAN_SERIF_COVE:
2734 case PAN_SERIF_OBTUSE_COVE:
2735 case PAN_SERIF_SQUARE_COVE:
2736 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2737 case PAN_SERIF_SQUARE:
2738 case PAN_SERIF_THIN:
2739 case PAN_SERIF_BONE:
2740 case PAN_SERIF_EXAGGERATED:
2741 case PAN_SERIF_TRIANGLE:
2742 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2745 case PAN_SERIF_NORMAL_SANS:
2746 case PAN_SERIF_OBTUSE_SANS:
2747 case PAN_SERIF_PERP_SANS:
2748 case PAN_SERIF_FLARED:
2749 case PAN_SERIF_ROUNDED:
2750 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2755 case PAN_FAMILY_SCRIPT:
2756 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2759 case PAN_FAMILY_DECORATIVE:
2760 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2764 test_negative_width(hdc, lf);
2767 SelectObject(hdc, hfont_old);
2768 DeleteObject(hfont);
2773 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2775 INT *enumed = (INT *)lParam;
2777 if (type == TRUETYPE_FONTTYPE)
2780 test_text_metrics(lf);
2785 static void test_GetTextMetrics(void)
2791 /* Report only once */
2792 if(!pGetGlyphIndicesA)
2793 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2797 memset(&lf, 0, sizeof(lf));
2798 lf.lfCharSet = DEFAULT_CHARSET;
2800 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2801 trace("Tested metrics of %d truetype fonts\n", enumed);
2806 static void test_nonexistent_font(void)
2814 { "Times New Roman Baltic", 186 },
2815 { "Times New Roman CE", 238 },
2816 { "Times New Roman CYR", 204 },
2817 { "Times New Roman Greek", 161 },
2818 { "Times New Roman TUR", 162 }
2824 INT cs, expected_cs, i;
2825 char buf[LF_FACESIZE];
2827 if (!is_truetype_font_installed("Arial") ||
2828 !is_truetype_font_installed("Times New Roman"))
2830 skip("Arial or Times New Roman not installed\n");
2834 expected_cs = GetACP();
2835 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2837 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2840 expected_cs = csi.ciCharset;
2841 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2845 memset(&lf, 0, sizeof(lf));
2847 lf.lfWeight = FW_REGULAR;
2848 lf.lfCharSet = ANSI_CHARSET;
2849 lf.lfPitchAndFamily = FF_SWISS;
2850 strcpy(lf.lfFaceName, "Nonexistent font");
2851 hfont = CreateFontIndirectA(&lf);
2852 hfont = SelectObject(hdc, hfont);
2853 GetTextFaceA(hdc, sizeof(buf), buf);
2854 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2855 cs = GetTextCharset(hdc);
2856 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2857 DeleteObject(SelectObject(hdc, hfont));
2859 memset(&lf, 0, sizeof(lf));
2861 lf.lfWeight = FW_DONTCARE;
2862 strcpy(lf.lfFaceName, "Nonexistent font");
2863 hfont = CreateFontIndirectA(&lf);
2864 hfont = SelectObject(hdc, hfont);
2865 GetTextFaceA(hdc, sizeof(buf), buf);
2866 todo_wine /* Wine uses Arial for all substitutions */
2867 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2868 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2869 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2871 cs = GetTextCharset(hdc);
2872 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2873 DeleteObject(SelectObject(hdc, hfont));
2875 memset(&lf, 0, sizeof(lf));
2877 lf.lfWeight = FW_REGULAR;
2878 strcpy(lf.lfFaceName, "Nonexistent font");
2879 hfont = CreateFontIndirectA(&lf);
2880 hfont = SelectObject(hdc, hfont);
2881 GetTextFaceA(hdc, sizeof(buf), buf);
2882 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2883 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2884 cs = GetTextCharset(hdc);
2885 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2886 DeleteObject(SelectObject(hdc, hfont));
2888 memset(&lf, 0, sizeof(lf));
2890 lf.lfWeight = FW_DONTCARE;
2891 strcpy(lf.lfFaceName, "Times New Roman");
2892 hfont = CreateFontIndirectA(&lf);
2893 hfont = SelectObject(hdc, hfont);
2894 GetTextFaceA(hdc, sizeof(buf), buf);
2895 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2896 cs = GetTextCharset(hdc);
2897 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2898 DeleteObject(SelectObject(hdc, hfont));
2900 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2902 memset(&lf, 0, sizeof(lf));
2904 lf.lfWeight = FW_REGULAR;
2905 strcpy(lf.lfFaceName, font_subst[i].name);
2906 hfont = CreateFontIndirectA(&lf);
2907 hfont = SelectObject(hdc, hfont);
2908 cs = GetTextCharset(hdc);
2909 if (font_subst[i].charset == expected_cs)
2911 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2912 GetTextFaceA(hdc, sizeof(buf), buf);
2913 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2917 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2918 GetTextFaceA(hdc, sizeof(buf), buf);
2919 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2920 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2922 DeleteObject(SelectObject(hdc, hfont));
2924 memset(&lf, 0, sizeof(lf));
2926 lf.lfWeight = FW_DONTCARE;
2927 strcpy(lf.lfFaceName, font_subst[i].name);
2928 hfont = CreateFontIndirectA(&lf);
2929 hfont = SelectObject(hdc, hfont);
2930 GetTextFaceA(hdc, sizeof(buf), buf);
2931 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2932 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2933 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2934 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2935 "got %s for font %s\n", buf, font_subst[i].name);
2936 cs = GetTextCharset(hdc);
2937 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2938 DeleteObject(SelectObject(hdc, hfont));
2944 static void test_GdiRealizationInfo(void)
2949 HFONT hfont, hfont_old;
2952 if(!pGdiRealizationInfo)
2954 win_skip("GdiRealizationInfo not available\n");
2960 memset(info, 0xcc, sizeof(info));
2961 r = pGdiRealizationInfo(hdc, info);
2962 ok(r != 0, "ret 0\n");
2963 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2964 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2966 if (!is_truetype_font_installed("Arial"))
2968 skip("skipping GdiRealizationInfo with truetype font\n");
2972 memset(&lf, 0, sizeof(lf));
2973 strcpy(lf.lfFaceName, "Arial");
2975 lf.lfWeight = FW_NORMAL;
2976 hfont = CreateFontIndirectA(&lf);
2977 hfont_old = SelectObject(hdc, hfont);
2979 memset(info, 0xcc, sizeof(info));
2980 r = pGdiRealizationInfo(hdc, info);
2981 ok(r != 0, "ret 0\n");
2982 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2983 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2985 DeleteObject(SelectObject(hdc, hfont_old));
2991 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2992 the nul in the count of characters copied when the face name buffer is not
2993 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2994 always includes it. */
2995 static void test_GetTextFace(void)
2997 static const char faceA[] = "Tahoma";
2998 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3001 char bufA[LF_FACESIZE];
3002 WCHAR bufW[LF_FACESIZE];
3007 if(!is_font_installed("Tahoma"))
3009 skip("Tahoma is not installed so skipping this test\n");
3014 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3015 f = CreateFontIndirectA(&fA);
3016 ok(f != NULL, "CreateFontIndirectA failed\n");
3019 g = SelectObject(dc, f);
3020 n = GetTextFaceA(dc, sizeof bufA, bufA);
3021 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3022 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3024 /* Play with the count arg. */
3026 n = GetTextFaceA(dc, 0, bufA);
3027 ok(n == 0, "GetTextFaceA returned %d\n", n);
3028 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3031 n = GetTextFaceA(dc, 1, bufA);
3032 ok(n == 0, "GetTextFaceA returned %d\n", n);
3033 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3035 bufA[0] = 'x'; bufA[1] = 'y';
3036 n = GetTextFaceA(dc, 2, bufA);
3037 ok(n == 1, "GetTextFaceA returned %d\n", n);
3038 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3040 n = GetTextFaceA(dc, 0, NULL);
3041 ok(n == sizeof faceA ||
3042 broken(n == 0), /* win98, winMe */
3043 "GetTextFaceA returned %d\n", n);
3045 DeleteObject(SelectObject(dc, g));
3046 ReleaseDC(NULL, dc);
3049 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3050 SetLastError(0xdeadbeef);
3051 f = CreateFontIndirectW(&fW);
3052 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3054 win_skip("CreateFontIndirectW is not implemented\n");
3057 ok(f != NULL, "CreateFontIndirectW failed\n");
3060 g = SelectObject(dc, f);
3061 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3062 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3063 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3065 /* Play with the count arg. */
3067 n = GetTextFaceW(dc, 0, bufW);
3068 ok(n == 0, "GetTextFaceW returned %d\n", n);
3069 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3072 n = GetTextFaceW(dc, 1, bufW);
3073 ok(n == 1, "GetTextFaceW returned %d\n", n);
3074 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3076 bufW[0] = 'x'; bufW[1] = 'y';
3077 n = GetTextFaceW(dc, 2, bufW);
3078 ok(n == 2, "GetTextFaceW returned %d\n", n);
3079 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3081 n = GetTextFaceW(dc, 0, NULL);
3082 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3084 DeleteObject(SelectObject(dc, g));
3085 ReleaseDC(NULL, dc);
3088 static void test_orientation(void)
3090 static const char test_str[11] = "Test String";
3093 HFONT hfont, old_hfont;
3096 if (!is_truetype_font_installed("Arial"))
3098 skip("Arial is not installed\n");
3102 hdc = CreateCompatibleDC(0);
3103 memset(&lf, 0, sizeof(lf));
3104 lstrcpyA(lf.lfFaceName, "Arial");
3106 lf.lfOrientation = lf.lfEscapement = 900;
3107 hfont = create_font("orientation", &lf);
3108 old_hfont = SelectObject(hdc, hfont);
3109 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3110 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3111 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3112 SelectObject(hdc, old_hfont);
3113 DeleteObject(hfont);
3117 static void test_oemcharset(void)
3121 HFONT hfont, old_hfont;
3124 hdc = CreateCompatibleDC(0);
3125 ZeroMemory(&lf, sizeof(lf));
3127 lf.lfCharSet = OEM_CHARSET;
3128 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3129 lstrcpyA(lf.lfFaceName, "Terminal");
3130 hfont = CreateFontIndirectA(&lf);
3131 old_hfont = SelectObject(hdc, hfont);
3132 charset = GetTextCharset(hdc);
3134 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3135 hfont = SelectObject(hdc, old_hfont);
3136 GetObjectA(hfont, sizeof(clf), &clf);
3137 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3138 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3139 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3140 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3141 DeleteObject(hfont);
3145 static void test_GetGlyphOutline(void)
3148 GLYPHMETRICS gm, gm2;
3150 HFONT hfont, old_hfont;
3159 {ANSI_CHARSET, 0x30, 0x30},
3160 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3161 {HANGEUL_CHARSET, 0x8141, 0xac02},
3162 {JOHAB_CHARSET, 0x8446, 0x3135},
3163 {GB2312_CHARSET, 0x8141, 0x4e04},
3164 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3168 if (!is_truetype_font_installed("Tahoma"))
3170 skip("Tahoma is not installed\n");
3174 hdc = CreateCompatibleDC(0);
3175 memset(&lf, 0, sizeof(lf));
3177 lstrcpyA(lf.lfFaceName, "Tahoma");
3178 SetLastError(0xdeadbeef);
3179 hfont = CreateFontIndirectA(&lf);
3180 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3181 old_hfont = SelectObject(hdc, hfont);
3183 memset(&gm, 0, sizeof(gm));
3184 SetLastError(0xdeadbeef);
3185 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3186 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3188 memset(&gm, 0, sizeof(gm));
3189 SetLastError(0xdeadbeef);
3190 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3191 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3192 ok(GetLastError() == 0xdeadbeef ||
3193 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3194 "expected 0xdeadbeef, got %u\n", GetLastError());
3196 memset(&gm, 0, sizeof(gm));
3197 SetLastError(0xdeadbeef);
3198 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3199 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3200 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3202 memset(&gm, 0, sizeof(gm));
3203 SetLastError(0xdeadbeef);
3204 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3205 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3207 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3208 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3211 /* test for needed buffer size request on space char */
3212 memset(&gm, 0, sizeof(gm));
3213 SetLastError(0xdeadbeef);
3214 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3215 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3216 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3218 /* requesting buffer size for space char + error */
3219 memset(&gm, 0, sizeof(gm));
3220 SetLastError(0xdeadbeef);
3221 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3222 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3224 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3225 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3228 SelectObject(hdc, old_hfont);
3229 DeleteObject(hfont);
3231 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3233 lf.lfFaceName[0] = '\0';
3234 lf.lfCharSet = c[i].cs;
3235 lf.lfPitchAndFamily = 0;
3236 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3238 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3242 old_hfont = SelectObject(hdc, hfont);
3244 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3245 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3246 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3248 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3249 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3250 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3252 hfont = SelectObject(hdc, old_hfont);
3253 DeleteObject(hfont);
3259 /* bug #9995: there is a limit to the character width that can be specified */
3260 static void test_GetTextMetrics2(const char *fontname, int font_height)
3266 int ave_width, height, width, ratio, scale;
3268 if (!is_truetype_font_installed( fontname)) {
3269 skip("%s is not installed\n", fontname);
3272 hdc = CreateCompatibleDC(0);
3273 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3274 /* select width = 0 */
3275 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3276 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3277 DEFAULT_QUALITY, VARIABLE_PITCH,
3279 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3280 of = SelectObject( hdc, hf);
3281 ret = GetTextMetricsA( hdc, &tm);
3282 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3283 height = tm.tmHeight;
3284 ave_width = tm.tmAveCharWidth;
3285 SelectObject( hdc, of);
3288 trace("height %d, ave width %d\n", height, ave_width);
3290 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3292 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3293 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3294 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3295 ok(hf != 0, "CreateFont failed\n");
3296 of = SelectObject(hdc, hf);
3297 ret = GetTextMetrics(hdc, &tm);
3298 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3299 SelectObject(hdc, of);
3302 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3308 ratio = width / height;
3309 scale = width / ave_width;
3311 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3312 width, height, ratio, width, ave_width, scale);
3314 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3317 static void test_CreateFontIndirect(void)
3319 LOGFONTA lf, getobj_lf;
3322 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3324 memset(&lf, 0, sizeof(lf));
3325 lf.lfCharSet = ANSI_CHARSET;
3326 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3329 lf.lfQuality = DEFAULT_QUALITY;
3330 lf.lfItalic = FALSE;
3331 lf.lfWeight = FW_DONTCARE;
3333 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3335 lstrcpyA(lf.lfFaceName, TestName[i]);
3336 hfont = CreateFontIndirectA(&lf);
3337 ok(hfont != 0, "CreateFontIndirectA failed\n");
3338 SetLastError(0xdeadbeef);
3339 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3340 ok(ret, "GetObject failed: %d\n", GetLastError());
3341 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3342 ok(lf.lfWeight == getobj_lf.lfWeight ||
3343 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3344 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3345 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3346 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3347 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3348 DeleteObject(hfont);
3352 static void test_CreateFontIndirectEx(void)
3354 ENUMLOGFONTEXDVA lfex;
3357 if (!pCreateFontIndirectExA)
3359 win_skip("CreateFontIndirectExA is not available\n");
3363 if (!is_truetype_font_installed("Arial"))
3365 skip("Arial is not installed\n");
3369 SetLastError(0xdeadbeef);
3370 hfont = pCreateFontIndirectExA(NULL);
3371 ok(hfont == NULL, "got %p\n", hfont);
3372 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3374 memset(&lfex, 0, sizeof(lfex));
3375 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3376 hfont = pCreateFontIndirectExA(&lfex);
3377 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3379 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3380 DeleteObject(hfont);
3383 static void free_font(void *font)
3385 UnmapViewOfFile(font);
3388 static void *load_font(const char *font_name, DWORD *font_size)
3390 char file_name[MAX_PATH];
3391 HANDLE file, mapping;
3394 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3395 strcat(file_name, "\\fonts\\");
3396 strcat(file_name, font_name);
3398 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3399 if (file == INVALID_HANDLE_VALUE) return NULL;
3401 *font_size = GetFileSize(file, NULL);
3403 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3410 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3413 CloseHandle(mapping);
3417 static void test_AddFontMemResource(void)
3420 DWORD font_size, num_fonts;
3424 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3426 win_skip("AddFontMemResourceEx is not available on this platform\n");
3430 font = load_font("sserife.fon", &font_size);
3433 skip("Unable to locate and load font sserife.fon\n");
3437 SetLastError(0xdeadbeef);
3438 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3439 ok(!ret, "AddFontMemResourceEx should fail\n");
3440 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3441 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3444 SetLastError(0xdeadbeef);
3445 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3446 ok(!ret, "AddFontMemResourceEx should fail\n");
3447 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3448 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3451 SetLastError(0xdeadbeef);
3452 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3453 ok(!ret, "AddFontMemResourceEx should fail\n");
3454 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3455 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3458 SetLastError(0xdeadbeef);
3459 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3460 ok(!ret, "AddFontMemResourceEx should fail\n");
3461 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3462 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3465 SetLastError(0xdeadbeef);
3466 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3467 ok(!ret, "AddFontMemResourceEx should fail\n");
3468 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3469 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3472 SetLastError(0xdeadbeef);
3473 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3474 ok(!ret, "AddFontMemResourceEx should fail\n");
3475 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3476 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3479 num_fonts = 0xdeadbeef;
3480 SetLastError(0xdeadbeef);
3481 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3482 ok(!ret, "AddFontMemResourceEx should fail\n");
3483 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3484 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3486 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3488 if (0) /* hangs under windows 2000 */
3490 num_fonts = 0xdeadbeef;
3491 SetLastError(0xdeadbeef);
3492 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3493 ok(!ret, "AddFontMemResourceEx should fail\n");
3494 ok(GetLastError() == 0xdeadbeef,
3495 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3497 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3500 num_fonts = 0xdeadbeef;
3501 SetLastError(0xdeadbeef);
3502 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3503 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3504 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3505 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3509 SetLastError(0xdeadbeef);
3510 bRet = pRemoveFontMemResourceEx(ret);
3511 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3513 /* test invalid pointer to number of loaded fonts */
3514 font = load_font("sserife.fon", &font_size);
3515 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3517 SetLastError(0xdeadbeef);
3518 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3519 ok(!ret, "AddFontMemResourceEx should fail\n");
3520 ok(GetLastError() == 0xdeadbeef,
3521 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3524 SetLastError(0xdeadbeef);
3525 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3526 ok(!ret, "AddFontMemResourceEx should fail\n");
3527 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3528 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3534 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3538 if (type != TRUETYPE_FONTTYPE) return 1;
3540 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3542 lf = (LOGFONT *)lparam;
3547 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3552 if (type != TRUETYPE_FONTTYPE) return 1;
3554 lf = (LOGFONT *)lparam;
3555 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3558 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3565 static void test_EnumFonts(void)
3571 if (!is_truetype_font_installed("Arial"))
3573 skip("Arial is not installed\n");
3577 /* Windows uses localized font face names, so Arial Bold won't be found */
3578 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3580 skip("User locale is not English, skipping the test\n");
3584 hdc = CreateCompatibleDC(0);
3586 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3587 ok(!ret, "font Arial is not enumerated\n");
3588 ret = strcmp(lf.lfFaceName, "Arial");
3589 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3590 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3592 lstrcpy(lf.lfFaceName, "Arial");
3593 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3594 ok(!ret, "font Arial is not enumerated\n");
3595 ret = strcmp(lf.lfFaceName, "Arial");
3596 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3597 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3599 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3600 ok(!ret, "font Arial Bold is not enumerated\n");
3601 ret = strcmp(lf.lfFaceName, "Arial");
3602 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3603 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3605 lstrcpy(lf.lfFaceName, "Arial Bold");
3606 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3607 ok(ret, "font Arial Bold should not be enumerated\n");
3609 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3610 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3611 ret = strcmp(lf.lfFaceName, "Arial");
3612 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3613 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3615 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3616 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3617 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3619 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3620 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3622 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3623 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3624 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3635 test_outline_font();
3636 test_bitmap_font_metrics();
3637 test_GdiGetCharDimensions();
3638 test_GetCharABCWidths();
3639 test_text_extents();
3640 test_GetGlyphIndices();
3641 test_GetKerningPairs();
3642 test_GetOutlineTextMetrics();
3643 test_SetTextJustification();
3644 test_font_charset();
3645 test_GetFontUnicodeRanges();
3646 test_nonexistent_font();
3648 test_height_selection();
3649 test_AddFontMemResource();
3652 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3653 * I'd like to avoid them in this test.
3655 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3656 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3657 if (is_truetype_font_installed("Arial Black") &&
3658 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3660 test_EnumFontFamilies("", ANSI_CHARSET);
3661 test_EnumFontFamilies("", SYMBOL_CHARSET);
3662 test_EnumFontFamilies("", DEFAULT_CHARSET);
3665 skip("Arial Black or Symbol/Wingdings is not installed\n");
3666 test_EnumFontFamiliesEx_default_charset();
3667 test_GetTextMetrics();
3668 test_GdiRealizationInfo();
3670 test_GetGlyphOutline();
3671 test_GetTextMetrics2("Tahoma", -11);
3672 test_GetTextMetrics2("Tahoma", -55);
3673 test_GetTextMetrics2("Tahoma", -110);
3674 test_GetTextMetrics2("Arial", -11);
3675 test_GetTextMetrics2("Arial", -55);
3676 test_GetTextMetrics2("Arial", -110);
3677 test_CreateFontIndirect();
3678 test_CreateFontIndirectEx();