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')
2350 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2363 } cmap_encoding_record;
2371 BYTE glyph_ids[256];
2381 USHORT search_range;
2382 USHORT entry_selector;
2385 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2388 USHORT start_count[seg_countx2 / 2];
2389 USHORT id_delta[seg_countx2 / 2];
2390 USHORT id_range_offset[seg_countx2 / 2];
2400 USHORT id_range_offset;
2401 } cmap_format_4_seg;
2403 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2405 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2406 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2407 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2408 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2409 os2->panose.bWeight, os2->panose.bProportion);
2412 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2415 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2419 for(i = 0; i < 256; i++)
2421 if(cmap->glyph_ids[i] == 0) continue;
2423 if(*first == 256) *first = i;
2425 if(*first == 256) return FALSE;
2429 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2431 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2432 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2433 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2434 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2435 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2438 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2441 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2442 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2443 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2447 for(i = 0; i < seg_count; i++)
2450 cmap_format_4_seg seg;
2452 get_seg4(cmap, i, &seg);
2453 for(code = seg.start_count; code <= seg.end_count; code++)
2455 if(seg.id_range_offset == 0)
2456 index = (seg.id_delta + code) & 0xffff;
2459 index = seg.id_range_offset / 2
2460 + code - seg.start_count
2463 /* some fonts have broken last segment */
2464 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2465 index = GET_BE_WORD(glyph_ids[index]);
2468 trace("segment %04x/%04x index %04x points to nowhere\n",
2469 seg.start_count, seg.end_count, index);
2472 if(index) index += seg.id_delta;
2474 if(*first == 0x10000)
2475 *last = *first = code;
2481 if(*first == 0x10000) return FALSE;
2485 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2488 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2490 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2492 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2493 return (BYTE *)header + GET_BE_DWORD(record->offset);
2506 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2509 cmap_header *header;
2514 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2515 ok(size != GDI_ERROR, "no cmap table found\n");
2516 if(size == GDI_ERROR) return FALSE;
2518 header = HeapAlloc(GetProcessHeap(), 0, size);
2519 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2520 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2521 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2523 cmap = get_cmap(header, 3, 1);
2525 *cmap_type = cmap_ms_unicode;
2528 cmap = get_cmap(header, 3, 0);
2529 if(cmap) *cmap_type = cmap_ms_symbol;
2533 *cmap_type = cmap_none;
2537 format = GET_BE_WORD(*(WORD *)cmap);
2541 r = get_first_last_from_cmap0(cmap, first, last);
2544 r = get_first_last_from_cmap4(cmap, first, last, size);
2547 trace("unhandled cmap format %d\n", format);
2552 HeapFree(GetProcessHeap(), 0, header);
2556 #define TT_PLATFORM_MICROSOFT 3
2557 #define TT_MS_ID_UNICODE_CS 1
2558 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2559 #define TT_NAME_ID_FULL_NAME 4
2561 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2563 struct sfnt_name_header
2566 USHORT number_of_record;
2567 USHORT storage_offset;
2579 LONG size, offset, length;
2585 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2586 ok(size != GDI_ERROR, "no name table found\n");
2587 if(size == GDI_ERROR) return FALSE;
2589 data = HeapAlloc(GetProcessHeap(), 0, size);
2590 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2591 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2593 header = (void *)data;
2594 header->format = GET_BE_WORD(header->format);
2595 header->number_of_record = GET_BE_WORD(header->number_of_record);
2596 header->storage_offset = GET_BE_WORD(header->storage_offset);
2597 if (header->format != 0)
2599 trace("got format %u\n", header->format);
2602 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2604 trace("number records out of range: %d\n", header->number_of_record);
2607 if (header->storage_offset >= size)
2609 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2613 entry = (void *)&header[1];
2614 for (i = 0; i < header->number_of_record; i++)
2616 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2617 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2618 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2619 GET_BE_WORD(entry[i].name_id) != name_id)
2624 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2625 length = GET_BE_WORD(entry[i].length);
2626 if (offset + length > size)
2628 trace("entry %d is out of range\n", i);
2631 if (length >= out_size)
2633 trace("buffer too small for entry %d\n", i);
2637 name = (WCHAR *)(data + offset);
2638 for (c = 0; c < length / 2; c++)
2639 out_buf[c] = GET_BE_WORD(name[c]);
2647 HeapFree(GetProcessHeap(), 0, data);
2651 static void test_text_metrics(const LOGFONTA *lf)
2654 HFONT hfont, hfont_old;
2658 const char *font_name = lf->lfFaceName;
2659 DWORD cmap_first = 0, cmap_last = 0;
2660 cmap_type cmap_type;
2661 BOOL sys_lang_non_english;
2663 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2666 SetLastError(0xdeadbeef);
2667 hfont = CreateFontIndirectA(lf);
2668 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2670 hfont_old = SelectObject(hdc, hfont);
2672 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2673 if (size == GDI_ERROR)
2675 trace("OS/2 chunk was not found\n");
2678 if (size > sizeof(tt_os2))
2680 trace("got too large OS/2 chunk of size %u\n", size);
2681 size = sizeof(tt_os2);
2684 memset(&tt_os2, 0, sizeof(tt_os2));
2685 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2686 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2688 SetLastError(0xdeadbeef);
2689 ret = GetTextMetricsA(hdc, &tmA);
2690 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2692 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2694 skip("Unable to retrieve first and last glyphs from cmap\n");
2698 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2699 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2700 UINT os2_first_char, os2_last_char, default_char, break_char;
2704 version = GET_BE_WORD(tt_os2.version);
2706 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2707 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2708 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2709 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2711 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2712 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2713 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2715 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2720 case 1257: /* Baltic */
2721 expect_last_W = 0xf8fd;
2724 expect_last_W = 0xf0ff;
2726 expect_break_W = 0x20;
2727 expect_default_W = expect_break_W - 1;
2728 expect_first_A = 0x1e;
2729 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2733 expect_first_W = cmap_first;
2734 expect_last_W = min(cmap_last, os2_last_char);
2735 if(os2_first_char <= 1)
2736 expect_break_W = os2_first_char + 2;
2737 else if(os2_first_char > 0xff)
2738 expect_break_W = 0x20;
2740 expect_break_W = os2_first_char;
2741 expect_default_W = expect_break_W - 1;
2742 expect_first_A = expect_default_W - 1;
2743 expect_last_A = min(expect_last_W, 0xff);
2745 expect_break_A = expect_break_W;
2746 expect_default_A = expect_default_W;
2748 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2749 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2750 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2751 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2752 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2754 ok(tmA.tmFirstChar == expect_first_A ||
2755 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2756 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2757 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2758 ok(tmA.tmLastChar == expect_last_A ||
2759 tmA.tmLastChar == 0xff /* win9x */,
2760 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2762 skip("tmLastChar is DBCS lead byte\n");
2763 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2764 font_name, tmA.tmBreakChar, expect_break_A);
2765 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2766 "A: tmDefaultChar for %s got %02x expected %02x\n",
2767 font_name, tmA.tmDefaultChar, expect_default_A);
2770 SetLastError(0xdeadbeef);
2771 ret = GetTextMetricsW(hdc, &tmW);
2772 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2773 "GetTextMetricsW error %u\n", GetLastError());
2776 /* Wine uses the os2 first char */
2777 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2778 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2779 font_name, tmW.tmFirstChar, expect_first_W);
2781 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2782 font_name, tmW.tmFirstChar, expect_first_W);
2784 /* Wine uses the os2 last char */
2785 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2786 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2787 font_name, tmW.tmLastChar, expect_last_W);
2789 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2790 font_name, tmW.tmLastChar, expect_last_W);
2791 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2792 font_name, tmW.tmBreakChar, expect_break_W);
2793 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2794 "W: tmDefaultChar for %s got %02x expected %02x\n",
2795 font_name, tmW.tmDefaultChar, expect_default_W);
2797 /* Test the aspect ratio while we have tmW */
2798 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2799 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2800 tmW.tmDigitizedAspectX, ret);
2801 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2802 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2803 tmW.tmDigitizedAspectX, ret);
2807 /* test FF_ values */
2808 switch(tt_os2.panose.bFamilyType)
2812 case PAN_FAMILY_TEXT_DISPLAY:
2813 case PAN_FAMILY_PICTORIAL:
2815 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2816 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2818 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2821 switch(tt_os2.panose.bSerifStyle)
2826 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2829 case PAN_SERIF_COVE:
2830 case PAN_SERIF_OBTUSE_COVE:
2831 case PAN_SERIF_SQUARE_COVE:
2832 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2833 case PAN_SERIF_SQUARE:
2834 case PAN_SERIF_THIN:
2835 case PAN_SERIF_BONE:
2836 case PAN_SERIF_EXAGGERATED:
2837 case PAN_SERIF_TRIANGLE:
2838 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2841 case PAN_SERIF_NORMAL_SANS:
2842 case PAN_SERIF_OBTUSE_SANS:
2843 case PAN_SERIF_PERP_SANS:
2844 case PAN_SERIF_FLARED:
2845 case PAN_SERIF_ROUNDED:
2846 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2851 case PAN_FAMILY_SCRIPT:
2852 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2855 case PAN_FAMILY_DECORATIVE:
2856 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2860 test_negative_width(hdc, lf);
2863 SelectObject(hdc, hfont_old);
2864 DeleteObject(hfont);
2869 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2871 INT *enumed = (INT *)lParam;
2873 if (type == TRUETYPE_FONTTYPE)
2876 test_text_metrics(lf);
2881 static void test_GetTextMetrics(void)
2887 /* Report only once */
2888 if(!pGetGlyphIndicesA)
2889 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2893 memset(&lf, 0, sizeof(lf));
2894 lf.lfCharSet = DEFAULT_CHARSET;
2896 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2897 trace("Tested metrics of %d truetype fonts\n", enumed);
2902 static void test_nonexistent_font(void)
2910 { "Times New Roman Baltic", 186 },
2911 { "Times New Roman CE", 238 },
2912 { "Times New Roman CYR", 204 },
2913 { "Times New Roman Greek", 161 },
2914 { "Times New Roman TUR", 162 }
2920 INT cs, expected_cs, i;
2921 char buf[LF_FACESIZE];
2923 if (!is_truetype_font_installed("Arial") ||
2924 !is_truetype_font_installed("Times New Roman"))
2926 skip("Arial or Times New Roman not installed\n");
2930 expected_cs = GetACP();
2931 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2933 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2936 expected_cs = csi.ciCharset;
2937 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2941 memset(&lf, 0, sizeof(lf));
2943 lf.lfWeight = FW_REGULAR;
2944 lf.lfCharSet = ANSI_CHARSET;
2945 lf.lfPitchAndFamily = FF_SWISS;
2946 strcpy(lf.lfFaceName, "Nonexistent font");
2947 hfont = CreateFontIndirectA(&lf);
2948 hfont = SelectObject(hdc, hfont);
2949 GetTextFaceA(hdc, sizeof(buf), buf);
2950 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2951 cs = GetTextCharset(hdc);
2952 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2953 DeleteObject(SelectObject(hdc, hfont));
2955 memset(&lf, 0, sizeof(lf));
2957 lf.lfWeight = FW_DONTCARE;
2958 strcpy(lf.lfFaceName, "Nonexistent font");
2959 hfont = CreateFontIndirectA(&lf);
2960 hfont = SelectObject(hdc, hfont);
2961 GetTextFaceA(hdc, sizeof(buf), buf);
2962 todo_wine /* Wine uses Arial for all substitutions */
2963 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2964 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2965 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2967 cs = GetTextCharset(hdc);
2968 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2969 DeleteObject(SelectObject(hdc, hfont));
2971 memset(&lf, 0, sizeof(lf));
2973 lf.lfWeight = FW_REGULAR;
2974 strcpy(lf.lfFaceName, "Nonexistent font");
2975 hfont = CreateFontIndirectA(&lf);
2976 hfont = SelectObject(hdc, hfont);
2977 GetTextFaceA(hdc, sizeof(buf), buf);
2978 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2979 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2980 cs = GetTextCharset(hdc);
2981 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2982 DeleteObject(SelectObject(hdc, hfont));
2984 memset(&lf, 0, sizeof(lf));
2986 lf.lfWeight = FW_DONTCARE;
2987 strcpy(lf.lfFaceName, "Times New Roman");
2988 hfont = CreateFontIndirectA(&lf);
2989 hfont = SelectObject(hdc, hfont);
2990 GetTextFaceA(hdc, sizeof(buf), buf);
2991 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2992 cs = GetTextCharset(hdc);
2993 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2994 DeleteObject(SelectObject(hdc, hfont));
2996 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2998 memset(&lf, 0, sizeof(lf));
3000 lf.lfWeight = FW_REGULAR;
3001 strcpy(lf.lfFaceName, font_subst[i].name);
3002 hfont = CreateFontIndirectA(&lf);
3003 hfont = SelectObject(hdc, hfont);
3004 cs = GetTextCharset(hdc);
3005 if (font_subst[i].charset == expected_cs)
3007 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3008 GetTextFaceA(hdc, sizeof(buf), buf);
3009 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3013 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3014 GetTextFaceA(hdc, sizeof(buf), buf);
3015 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3016 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3018 DeleteObject(SelectObject(hdc, hfont));
3020 memset(&lf, 0, sizeof(lf));
3022 lf.lfWeight = FW_DONTCARE;
3023 strcpy(lf.lfFaceName, font_subst[i].name);
3024 hfont = CreateFontIndirectA(&lf);
3025 hfont = SelectObject(hdc, hfont);
3026 GetTextFaceA(hdc, sizeof(buf), buf);
3027 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3028 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3029 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3030 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3031 "got %s for font %s\n", buf, font_subst[i].name);
3032 cs = GetTextCharset(hdc);
3033 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3034 DeleteObject(SelectObject(hdc, hfont));
3040 static void test_GdiRealizationInfo(void)
3045 HFONT hfont, hfont_old;
3048 if(!pGdiRealizationInfo)
3050 win_skip("GdiRealizationInfo not available\n");
3056 memset(info, 0xcc, sizeof(info));
3057 r = pGdiRealizationInfo(hdc, info);
3058 ok(r != 0, "ret 0\n");
3059 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3060 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3062 if (!is_truetype_font_installed("Arial"))
3064 skip("skipping GdiRealizationInfo with truetype font\n");
3068 memset(&lf, 0, sizeof(lf));
3069 strcpy(lf.lfFaceName, "Arial");
3071 lf.lfWeight = FW_NORMAL;
3072 hfont = CreateFontIndirectA(&lf);
3073 hfont_old = SelectObject(hdc, hfont);
3075 memset(info, 0xcc, sizeof(info));
3076 r = pGdiRealizationInfo(hdc, info);
3077 ok(r != 0, "ret 0\n");
3078 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3079 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3081 DeleteObject(SelectObject(hdc, hfont_old));
3087 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3088 the nul in the count of characters copied when the face name buffer is not
3089 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3090 always includes it. */
3091 static void test_GetTextFace(void)
3093 static const char faceA[] = "Tahoma";
3094 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3097 char bufA[LF_FACESIZE];
3098 WCHAR bufW[LF_FACESIZE];
3103 if(!is_font_installed("Tahoma"))
3105 skip("Tahoma is not installed so skipping this test\n");
3110 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3111 f = CreateFontIndirectA(&fA);
3112 ok(f != NULL, "CreateFontIndirectA failed\n");
3115 g = SelectObject(dc, f);
3116 n = GetTextFaceA(dc, sizeof bufA, bufA);
3117 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3118 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3120 /* Play with the count arg. */
3122 n = GetTextFaceA(dc, 0, bufA);
3123 ok(n == 0, "GetTextFaceA returned %d\n", n);
3124 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3127 n = GetTextFaceA(dc, 1, bufA);
3128 ok(n == 0, "GetTextFaceA returned %d\n", n);
3129 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3131 bufA[0] = 'x'; bufA[1] = 'y';
3132 n = GetTextFaceA(dc, 2, bufA);
3133 ok(n == 1, "GetTextFaceA returned %d\n", n);
3134 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3136 n = GetTextFaceA(dc, 0, NULL);
3137 ok(n == sizeof faceA ||
3138 broken(n == 0), /* win98, winMe */
3139 "GetTextFaceA returned %d\n", n);
3141 DeleteObject(SelectObject(dc, g));
3142 ReleaseDC(NULL, dc);
3145 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3146 SetLastError(0xdeadbeef);
3147 f = CreateFontIndirectW(&fW);
3148 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3150 win_skip("CreateFontIndirectW is not implemented\n");
3153 ok(f != NULL, "CreateFontIndirectW failed\n");
3156 g = SelectObject(dc, f);
3157 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3158 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3159 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3161 /* Play with the count arg. */
3163 n = GetTextFaceW(dc, 0, bufW);
3164 ok(n == 0, "GetTextFaceW returned %d\n", n);
3165 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3168 n = GetTextFaceW(dc, 1, bufW);
3169 ok(n == 1, "GetTextFaceW returned %d\n", n);
3170 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3172 bufW[0] = 'x'; bufW[1] = 'y';
3173 n = GetTextFaceW(dc, 2, bufW);
3174 ok(n == 2, "GetTextFaceW returned %d\n", n);
3175 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3177 n = GetTextFaceW(dc, 0, NULL);
3178 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3180 DeleteObject(SelectObject(dc, g));
3181 ReleaseDC(NULL, dc);
3184 static void test_orientation(void)
3186 static const char test_str[11] = "Test String";
3189 HFONT hfont, old_hfont;
3192 if (!is_truetype_font_installed("Arial"))
3194 skip("Arial is not installed\n");
3198 hdc = CreateCompatibleDC(0);
3199 memset(&lf, 0, sizeof(lf));
3200 lstrcpyA(lf.lfFaceName, "Arial");
3202 lf.lfOrientation = lf.lfEscapement = 900;
3203 hfont = create_font("orientation", &lf);
3204 old_hfont = SelectObject(hdc, hfont);
3205 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3206 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3207 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3208 SelectObject(hdc, old_hfont);
3209 DeleteObject(hfont);
3213 static void test_oemcharset(void)
3217 HFONT hfont, old_hfont;
3220 hdc = CreateCompatibleDC(0);
3221 ZeroMemory(&lf, sizeof(lf));
3223 lf.lfCharSet = OEM_CHARSET;
3224 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3225 lstrcpyA(lf.lfFaceName, "Terminal");
3226 hfont = CreateFontIndirectA(&lf);
3227 old_hfont = SelectObject(hdc, hfont);
3228 charset = GetTextCharset(hdc);
3230 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3231 hfont = SelectObject(hdc, old_hfont);
3232 GetObjectA(hfont, sizeof(clf), &clf);
3233 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3234 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3235 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3236 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3237 DeleteObject(hfont);
3241 static void test_GetGlyphOutline(void)
3244 GLYPHMETRICS gm, gm2;
3246 HFONT hfont, old_hfont;
3255 {ANSI_CHARSET, 0x30, 0x30},
3256 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3257 {HANGEUL_CHARSET, 0x8141, 0xac02},
3258 {JOHAB_CHARSET, 0x8446, 0x3135},
3259 {GB2312_CHARSET, 0x8141, 0x4e04},
3260 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3264 if (!is_truetype_font_installed("Tahoma"))
3266 skip("Tahoma is not installed\n");
3270 hdc = CreateCompatibleDC(0);
3271 memset(&lf, 0, sizeof(lf));
3273 lstrcpyA(lf.lfFaceName, "Tahoma");
3274 SetLastError(0xdeadbeef);
3275 hfont = CreateFontIndirectA(&lf);
3276 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3277 old_hfont = SelectObject(hdc, hfont);
3279 memset(&gm, 0, sizeof(gm));
3280 SetLastError(0xdeadbeef);
3281 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3282 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3284 memset(&gm, 0, sizeof(gm));
3285 SetLastError(0xdeadbeef);
3286 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3287 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3288 ok(GetLastError() == 0xdeadbeef ||
3289 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3290 "expected 0xdeadbeef, got %u\n", GetLastError());
3292 memset(&gm, 0, sizeof(gm));
3293 SetLastError(0xdeadbeef);
3294 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3295 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3296 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3298 memset(&gm, 0, sizeof(gm));
3299 SetLastError(0xdeadbeef);
3300 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3301 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3303 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3304 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3307 /* test for needed buffer size request on space char */
3308 memset(&gm, 0, sizeof(gm));
3309 SetLastError(0xdeadbeef);
3310 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3311 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3312 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3314 /* requesting buffer size for space char + error */
3315 memset(&gm, 0, sizeof(gm));
3316 SetLastError(0xdeadbeef);
3317 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3318 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3320 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3321 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3324 SelectObject(hdc, old_hfont);
3325 DeleteObject(hfont);
3327 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3329 lf.lfFaceName[0] = '\0';
3330 lf.lfCharSet = c[i].cs;
3331 lf.lfPitchAndFamily = 0;
3332 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3334 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3338 old_hfont = SelectObject(hdc, hfont);
3340 /* expected to ignore superfluous bytes (sigle-byte character) */
3341 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3342 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3343 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3345 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3346 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3347 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3349 /* expected to ignore superfluous bytes (double-byte character) */
3350 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3351 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3352 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3353 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3355 /* expected to match wide-char version results */
3356 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3357 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3359 hfont = SelectObject(hdc, old_hfont);
3360 DeleteObject(hfont);
3366 /* bug #9995: there is a limit to the character width that can be specified */
3367 static void test_GetTextMetrics2(const char *fontname, int font_height)
3373 int ave_width, height, width, ratio, scale;
3375 if (!is_truetype_font_installed( fontname)) {
3376 skip("%s is not installed\n", fontname);
3379 hdc = CreateCompatibleDC(0);
3380 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3381 /* select width = 0 */
3382 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3383 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3384 DEFAULT_QUALITY, VARIABLE_PITCH,
3386 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3387 of = SelectObject( hdc, hf);
3388 ret = GetTextMetricsA( hdc, &tm);
3389 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3390 height = tm.tmHeight;
3391 ave_width = tm.tmAveCharWidth;
3392 SelectObject( hdc, of);
3395 trace("height %d, ave width %d\n", height, ave_width);
3397 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3399 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3400 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3401 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3402 ok(hf != 0, "CreateFont failed\n");
3403 of = SelectObject(hdc, hf);
3404 ret = GetTextMetrics(hdc, &tm);
3405 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3406 SelectObject(hdc, of);
3409 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3415 ratio = width / height;
3416 scale = width / ave_width;
3418 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3419 width, height, ratio, width, ave_width, scale);
3421 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3424 static void test_CreateFontIndirect(void)
3426 LOGFONTA lf, getobj_lf;
3429 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3431 memset(&lf, 0, sizeof(lf));
3432 lf.lfCharSet = ANSI_CHARSET;
3433 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3436 lf.lfQuality = DEFAULT_QUALITY;
3437 lf.lfItalic = FALSE;
3438 lf.lfWeight = FW_DONTCARE;
3440 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3442 lstrcpyA(lf.lfFaceName, TestName[i]);
3443 hfont = CreateFontIndirectA(&lf);
3444 ok(hfont != 0, "CreateFontIndirectA failed\n");
3445 SetLastError(0xdeadbeef);
3446 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3447 ok(ret, "GetObject failed: %d\n", GetLastError());
3448 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3449 ok(lf.lfWeight == getobj_lf.lfWeight ||
3450 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3451 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3452 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3453 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3454 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3455 DeleteObject(hfont);
3459 static void test_CreateFontIndirectEx(void)
3461 ENUMLOGFONTEXDVA lfex;
3464 if (!pCreateFontIndirectExA)
3466 win_skip("CreateFontIndirectExA is not available\n");
3470 if (!is_truetype_font_installed("Arial"))
3472 skip("Arial is not installed\n");
3476 SetLastError(0xdeadbeef);
3477 hfont = pCreateFontIndirectExA(NULL);
3478 ok(hfont == NULL, "got %p\n", hfont);
3479 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3481 memset(&lfex, 0, sizeof(lfex));
3482 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3483 hfont = pCreateFontIndirectExA(&lfex);
3484 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3486 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3487 DeleteObject(hfont);
3490 static void free_font(void *font)
3492 UnmapViewOfFile(font);
3495 static void *load_font(const char *font_name, DWORD *font_size)
3497 char file_name[MAX_PATH];
3498 HANDLE file, mapping;
3501 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3502 strcat(file_name, "\\fonts\\");
3503 strcat(file_name, font_name);
3505 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3506 if (file == INVALID_HANDLE_VALUE) return NULL;
3508 *font_size = GetFileSize(file, NULL);
3510 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3517 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3520 CloseHandle(mapping);
3524 static void test_AddFontMemResource(void)
3527 DWORD font_size, num_fonts;
3531 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3533 win_skip("AddFontMemResourceEx is not available on this platform\n");
3537 font = load_font("sserife.fon", &font_size);
3540 skip("Unable to locate and load font sserife.fon\n");
3544 SetLastError(0xdeadbeef);
3545 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3546 ok(!ret, "AddFontMemResourceEx should fail\n");
3547 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3548 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3551 SetLastError(0xdeadbeef);
3552 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3553 ok(!ret, "AddFontMemResourceEx should fail\n");
3554 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3555 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3558 SetLastError(0xdeadbeef);
3559 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3560 ok(!ret, "AddFontMemResourceEx should fail\n");
3561 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3562 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3565 SetLastError(0xdeadbeef);
3566 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3567 ok(!ret, "AddFontMemResourceEx should fail\n");
3568 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3569 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3572 SetLastError(0xdeadbeef);
3573 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3574 ok(!ret, "AddFontMemResourceEx should fail\n");
3575 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3576 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3579 SetLastError(0xdeadbeef);
3580 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3581 ok(!ret, "AddFontMemResourceEx should fail\n");
3582 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3583 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3586 num_fonts = 0xdeadbeef;
3587 SetLastError(0xdeadbeef);
3588 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3589 ok(!ret, "AddFontMemResourceEx should fail\n");
3590 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3591 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3593 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3595 if (0) /* hangs under windows 2000 */
3597 num_fonts = 0xdeadbeef;
3598 SetLastError(0xdeadbeef);
3599 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3600 ok(!ret, "AddFontMemResourceEx should fail\n");
3601 ok(GetLastError() == 0xdeadbeef,
3602 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3604 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3607 num_fonts = 0xdeadbeef;
3608 SetLastError(0xdeadbeef);
3609 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3610 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3611 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3612 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3616 SetLastError(0xdeadbeef);
3617 bRet = pRemoveFontMemResourceEx(ret);
3618 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3620 /* test invalid pointer to number of loaded fonts */
3621 font = load_font("sserife.fon", &font_size);
3622 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3624 SetLastError(0xdeadbeef);
3625 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3626 ok(!ret, "AddFontMemResourceEx should fail\n");
3627 ok(GetLastError() == 0xdeadbeef,
3628 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3631 SetLastError(0xdeadbeef);
3632 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3633 ok(!ret, "AddFontMemResourceEx should fail\n");
3634 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3635 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3641 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3645 if (type != TRUETYPE_FONTTYPE) return 1;
3647 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3649 lf = (LOGFONT *)lparam;
3654 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3659 if (type != TRUETYPE_FONTTYPE) return 1;
3661 lf = (LOGFONT *)lparam;
3662 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3665 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3672 static void test_EnumFonts(void)
3678 if (!is_truetype_font_installed("Arial"))
3680 skip("Arial is not installed\n");
3684 /* Windows uses localized font face names, so Arial Bold won't be found */
3685 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3687 skip("User locale is not English, skipping the test\n");
3691 hdc = CreateCompatibleDC(0);
3693 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3694 ok(!ret, "font Arial is not enumerated\n");
3695 ret = strcmp(lf.lfFaceName, "Arial");
3696 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3697 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3699 lstrcpy(lf.lfFaceName, "Arial");
3700 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3701 ok(!ret, "font Arial is not enumerated\n");
3702 ret = strcmp(lf.lfFaceName, "Arial");
3703 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3704 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3706 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3707 ok(!ret, "font Arial Bold is not enumerated\n");
3708 ret = strcmp(lf.lfFaceName, "Arial");
3709 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3710 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3712 lstrcpy(lf.lfFaceName, "Arial Bold");
3713 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3714 ok(ret, "font Arial Bold should not be enumerated\n");
3716 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3717 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3718 ret = strcmp(lf.lfFaceName, "Arial");
3719 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3720 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3722 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3723 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3724 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3726 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3727 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3729 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3730 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3731 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3736 static void test_fullname(void)
3738 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic"};
3739 char buf[LF_FULLFACESIZE];
3745 /* Lucida Sans comes with XP SP2 or later */
3746 if (!is_truetype_font_installed("Lucida Sans"))
3748 skip("Lucida Sans is not installed\n");
3752 hdc = CreateCompatibleDC(0);
3753 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3755 memset(&lf, 0, sizeof(lf));
3756 lf.lfCharSet = ANSI_CHARSET;
3757 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3760 lf.lfQuality = DEFAULT_QUALITY;
3761 lf.lfItalic = FALSE;
3762 lf.lfWeight = FW_DONTCARE;
3764 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3766 lstrcpyA(lf.lfFaceName, TestName[i]);
3767 hfont = CreateFontIndirectA(&lf);
3768 ok(hfont != 0, "CreateFontIndirectA failed\n");
3770 of = SelectObject(hdc, hfont);
3772 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3773 "face full name could not be read\n");
3774 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3775 SelectObject(hdc, of);
3776 DeleteObject(hfont);
3787 test_outline_font();
3788 test_bitmap_font_metrics();
3789 test_GdiGetCharDimensions();
3790 test_GetCharABCWidths();
3791 test_text_extents();
3792 test_GetGlyphIndices();
3793 test_GetKerningPairs();
3794 test_GetOutlineTextMetrics();
3795 test_SetTextJustification();
3796 test_font_charset();
3797 test_GetFontUnicodeRanges();
3798 test_nonexistent_font();
3800 test_height_selection();
3801 test_AddFontMemResource();
3804 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3805 * I'd like to avoid them in this test.
3807 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3808 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3809 if (is_truetype_font_installed("Arial Black") &&
3810 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3812 test_EnumFontFamilies("", ANSI_CHARSET);
3813 test_EnumFontFamilies("", SYMBOL_CHARSET);
3814 test_EnumFontFamilies("", DEFAULT_CHARSET);
3817 skip("Arial Black or Symbol/Wingdings is not installed\n");
3818 test_EnumFontFamiliesEx_default_charset();
3819 test_GetTextMetrics();
3820 test_GdiRealizationInfo();
3822 test_GetGlyphOutline();
3823 test_GetTextMetrics2("Tahoma", -11);
3824 test_GetTextMetrics2("Tahoma", -55);
3825 test_GetTextMetrics2("Tahoma", -110);
3826 test_GetTextMetrics2("Arial", -11);
3827 test_GetTextMetrics2("Arial", -55);
3828 test_GetTextMetrics2("Arial", -110);
3829 test_CreateFontIndirect();
3830 test_CreateFontIndirectEx();