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;
54 static void init(void)
56 hgdi32 = GetModuleHandleA("gdi32.dll");
58 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
59 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
60 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
61 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
62 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
63 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
64 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
65 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
66 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
67 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
68 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
69 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
72 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
74 if (type != TRUETYPE_FONTTYPE) return 1;
79 static BOOL is_truetype_font_installed(const char *name)
84 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
91 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
96 static BOOL is_font_installed(const char *name)
101 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
108 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
116 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
117 /* NT4 tries to be clever and only returns the minimum length */
118 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
120 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
121 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
122 ok(lf->lfHeight == getobj_lf.lfHeight ||
123 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
124 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
125 ok(lf->lfWidth == getobj_lf.lfWidth ||
126 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
127 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
128 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
129 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
130 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
131 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
132 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
133 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
134 ok(lf->lfWeight == getobj_lf.lfWeight ||
135 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
136 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
137 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
138 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
139 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
140 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
141 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
142 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
143 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
144 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
145 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
146 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
147 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
150 static HFONT create_font(const char* test, const LOGFONTA* lf)
152 HFONT hfont = CreateFontIndirectA(lf);
153 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
155 check_font(test, lf, hfont);
159 static void test_logfont(void)
164 memset(&lf, 0, sizeof lf);
166 lf.lfCharSet = ANSI_CHARSET;
167 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
168 lf.lfWeight = FW_DONTCARE;
171 lf.lfQuality = DEFAULT_QUALITY;
173 lstrcpyA(lf.lfFaceName, "Arial");
174 hfont = create_font("Arial", &lf);
177 memset(&lf, 'A', sizeof(lf));
178 hfont = CreateFontIndirectA(&lf);
179 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
181 lf.lfFaceName[LF_FACESIZE - 1] = 0;
182 check_font("AAA...", &lf, hfont);
186 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
188 if (type & RASTER_FONTTYPE)
190 LOGFONT *lf = (LOGFONT *)lParam;
192 return 0; /* stop enumeration */
195 return 1; /* continue enumeration */
198 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
200 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
201 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
202 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
203 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
204 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
205 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
206 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
207 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
208 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
209 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
210 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
211 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
212 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
213 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
214 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
215 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
216 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
217 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
218 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
219 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
222 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
223 LONG lfWidth, const char *test_str,
224 INT test_str_len, const TEXTMETRICA *tm_orig,
225 const SIZE *size_orig, INT width_of_A_orig,
226 INT scale_x, INT scale_y)
229 OUTLINETEXTMETRIC otm;
232 INT width_of_A, cx, cy;
238 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
240 GetObjectA(hfont, sizeof(lf), &lf);
242 if (GetOutlineTextMetricsA(hdc, 0, NULL))
244 otm.otmSize = sizeof(otm) / 2;
245 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
246 ok(ret == sizeof(otm)/2 /* XP */ ||
247 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
249 memset(&otm, 0x1, sizeof(otm));
250 otm.otmSize = sizeof(otm);
251 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
252 ok(ret == sizeof(otm) /* XP */ ||
253 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
255 memset(&tm, 0x2, sizeof(tm));
256 ret = GetTextMetricsA(hdc, &tm);
257 ok(ret, "GetTextMetricsA failed\n");
258 /* the structure size is aligned */
259 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
261 ok(0, "tm != otm\n");
262 compare_tm(&tm, &otm.otmTextMetrics);
265 tm = otm.otmTextMetrics;
266 if (0) /* these metrics are scaled too, but with rounding errors */
268 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
269 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
271 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
272 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
273 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
274 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
275 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
276 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
280 ret = GetTextMetricsA(hdc, &tm);
281 ok(ret, "GetTextMetricsA failed\n");
284 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
285 cy = tm.tmHeight / tm_orig->tmHeight;
286 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
287 lfHeight, scale_x, scale_y, cx, cy);
288 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
289 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
290 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
291 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
292 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
294 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
298 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
301 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
303 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
305 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
306 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
308 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
310 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);
313 /* Test how GDI scales bitmap font metrics */
314 static void test_bitmap_font(void)
316 static const char test_str[11] = "Test String";
319 HFONT hfont, old_hfont;
322 INT ret, i, width_orig, height_orig, scale, lfWidth;
326 /* "System" has only 1 pixel size defined, otherwise the test breaks */
327 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
331 trace("no bitmap fonts were found, skipping the test\n");
335 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
337 height_orig = bitmap_lf.lfHeight;
338 lfWidth = bitmap_lf.lfWidth;
340 hfont = create_font("bitmap", &bitmap_lf);
341 old_hfont = SelectObject(hdc, hfont);
342 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
343 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
344 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
345 SelectObject(hdc, old_hfont);
348 bitmap_lf.lfHeight = 0;
349 bitmap_lf.lfWidth = 4;
350 hfont = create_font("bitmap", &bitmap_lf);
351 old_hfont = SelectObject(hdc, hfont);
352 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
353 SelectObject(hdc, old_hfont);
356 bitmap_lf.lfHeight = height_orig;
357 bitmap_lf.lfWidth = lfWidth;
359 /* test fractional scaling */
360 for (i = 1; i <= height_orig * 6; i++)
364 bitmap_lf.lfHeight = i;
365 hfont = create_font("fractional", &bitmap_lf);
366 scale = (i + height_orig - 1) / height_orig;
367 nearest_height = scale * height_orig;
368 /* Only jump to the next height if the difference <= 25% original height */
369 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
370 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
371 so we'll not test this particular height. */
372 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
373 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
374 old_hfont = SelectObject(hdc, hfont);
375 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
376 SelectObject(hdc, old_hfont);
380 /* test integer scaling 3x2 */
381 bitmap_lf.lfHeight = height_orig * 2;
382 bitmap_lf.lfWidth *= 3;
383 hfont = create_font("3x2", &bitmap_lf);
384 old_hfont = SelectObject(hdc, hfont);
385 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
386 SelectObject(hdc, old_hfont);
389 /* test integer scaling 3x3 */
390 bitmap_lf.lfHeight = height_orig * 3;
391 bitmap_lf.lfWidth = 0;
392 hfont = create_font("3x3", &bitmap_lf);
393 old_hfont = SelectObject(hdc, hfont);
394 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
395 SelectObject(hdc, old_hfont);
401 /* Test how GDI scales outline font metrics */
402 static void test_outline_font(void)
404 static const char test_str[11] = "Test String";
407 HFONT hfont, old_hfont, old_hfont_2;
408 OUTLINETEXTMETRICA otm;
410 INT width_orig, height_orig, lfWidth;
413 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
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;
675 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
676 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
677 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
679 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
680 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
681 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
682 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
683 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
684 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
685 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
687 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
688 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
689 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
690 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
691 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
692 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
693 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
694 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
696 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
697 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
698 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
699 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
700 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
701 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
702 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
703 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
704 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
705 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
706 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
707 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
708 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
709 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
710 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
711 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
712 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
714 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
716 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
717 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
718 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
719 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
720 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
721 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
722 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
723 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
724 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
726 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
727 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
728 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
730 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
731 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
732 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
734 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
735 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
736 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
738 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
739 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
741 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
742 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
743 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
744 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
745 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
746 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
747 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
748 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
749 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
750 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
751 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
752 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
753 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
754 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
755 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
757 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
759 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
761 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
762 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
765 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
766 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
767 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
768 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
769 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
770 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
772 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
773 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
774 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
776 /* The 120dpi version still has its dpi marked as 96 */
777 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
779 /* FIXME: add "Terminal" */
783 HFONT hfont, old_hfont;
787 hdc = CreateCompatibleDC(0);
790 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
794 memset(&lf, 0, sizeof(lf));
796 lf.lfHeight = fd[i].height;
797 strcpy(lf.lfFaceName, fd[i].face_name);
799 for(bit = 0; bit < 32; bit++)
807 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
808 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
810 lf.lfCharSet = csi.ciCharset;
811 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
814 hfont = create_font(lf.lfFaceName, &lf);
815 old_hfont = SelectObject(hdc, hfont);
816 bRet = GetTextMetrics(hdc, &tm);
817 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
818 if(fd[i].dpi == tm.tmDigitizedAspectX)
820 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
821 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);
822 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);
823 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);
824 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);
825 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);
826 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);
827 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);
829 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
830 that make the max width bigger */
831 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
832 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);
834 SelectObject(hdc, old_hfont);
842 static void test_GdiGetCharDimensions(void)
848 LONG avgwidth, height;
849 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
851 if (!pGdiGetCharDimensions)
853 win_skip("GdiGetCharDimensions not available on this platform\n");
857 hdc = CreateCompatibleDC(NULL);
859 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
860 avgwidth = ((size.cx / 26) + 1) / 2;
862 ret = pGdiGetCharDimensions(hdc, &tm, &height);
863 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
864 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
866 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
867 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
869 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
870 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
873 ret = pGdiGetCharDimensions(hdc, NULL, &height);
874 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
875 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
880 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
881 const TEXTMETRIC *lpntme,
882 DWORD FontType, LPARAM lParam)
884 if (FontType & TRUETYPE_FONTTYPE)
888 hfont = CreateFontIndirect(lpelfe);
891 *(HFONT *)lParam = hfont;
899 static void test_GetCharABCWidths(void)
901 static const WCHAR str[] = {'a',0};
916 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
917 {HANGEUL_CHARSET, 0x8141, 0xac02},
918 {JOHAB_CHARSET, 0x8446, 0x3135},
919 {GB2312_CHARSET, 0x8141, 0x4e04},
920 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
924 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsI)
926 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
930 memset(&lf, 0, sizeof(lf));
931 strcpy(lf.lfFaceName, "System");
934 hfont = CreateFontIndirectA(&lf);
936 hfont = SelectObject(hdc, hfont);
938 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
939 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
941 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
942 ok(!ret, "GetCharABCWidthsI should have failed\n");
944 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
945 ok(!ret, "GetCharABCWidthsI should have failed\n");
947 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
948 ok(ret, "GetCharABCWidthsI should have succeeded\n");
950 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
951 ok(!ret, "GetCharABCWidthsW should have failed\n");
953 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
954 ok(!ret, "GetCharABCWidthsW should have failed\n");
956 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
957 ok(!ret, "GetCharABCWidthsW should have failed\n");
959 hfont = SelectObject(hdc, hfont);
962 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
968 lf.lfFaceName[0] = '\0';
969 lf.lfCharSet = c[i].cs;
970 lf.lfPitchAndFamily = 0;
971 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
973 skip("TrueType font for charset %u is not installed\n", c[i].cs);
977 memset(a, 0, sizeof a);
978 memset(w, 0, sizeof w);
979 hfont = SelectObject(hdc, hfont);
980 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
981 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
982 memcmp(a, w, sizeof a) == 0,
983 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
985 memset(a, 0xbb, sizeof a);
986 ret = pGetCharABCWidthsA(hdc, code, code, a);
987 ok(ret, "GetCharABCWidthsA should have succeeded\n");
988 memset(full, 0xcc, sizeof full);
989 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
990 ok(ret, "GetCharABCWidthsA should have succeeded\n");
992 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
993 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
995 hfont = SelectObject(hdc, hfont);
999 ReleaseDC(NULL, hdc);
1002 static void test_text_extents(void)
1004 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1006 INT i, len, fit1, fit2;
1014 memset(&lf, 0, sizeof(lf));
1015 strcpy(lf.lfFaceName, "Arial");
1018 hfont = CreateFontIndirectA(&lf);
1020 hfont = SelectObject(hdc, hfont);
1021 GetTextMetricsA(hdc, &tm);
1022 GetTextExtentPointA(hdc, "o", 1, &sz);
1023 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1025 SetLastError(0xdeadbeef);
1026 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1027 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1029 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1030 hfont = SelectObject(hdc, hfont);
1031 DeleteObject(hfont);
1037 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1038 extents[0] = 1; /* So that the increasing sequence test will fail
1039 if the extents array is untouched. */
1040 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1041 GetTextExtentPointW(hdc, wt, len, &sz2);
1042 ok(sz1.cy == sz2.cy,
1043 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1044 /* Because of the '\n' in the string GetTextExtentExPoint and
1045 GetTextExtentPoint return different widths under Win2k, but
1046 under WinXP they return the same width. So we don't test that
1049 for (i = 1; i < len; ++i)
1050 ok(extents[i-1] <= extents[i],
1051 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1053 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1054 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1055 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1056 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1057 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1058 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1059 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1060 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1061 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1062 ok(extents[0] == extents[2] && extents[1] == extents[3],
1063 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1064 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1065 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1066 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1067 HeapFree(GetProcessHeap(), 0, extents);
1069 hfont = SelectObject(hdc, hfont);
1070 DeleteObject(hfont);
1071 ReleaseDC(NULL, hdc);
1074 static void test_GetGlyphIndices(void)
1081 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1082 WORD glyphs[(sizeof(testtext)/2)-1];
1086 if (!pGetGlyphIndicesW) {
1087 win_skip("GetGlyphIndicesW not available on platform\n");
1093 memset(&lf, 0, sizeof(lf));
1094 strcpy(lf.lfFaceName, "System");
1096 lf.lfCharSet = ANSI_CHARSET;
1098 hfont = CreateFontIndirectA(&lf);
1099 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1100 if (textm.tmCharSet == ANSI_CHARSET)
1102 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1103 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1104 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1105 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1107 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1108 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1109 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1110 textm.tmDefaultChar, glyphs[4]);
1113 /* FIXME: Write tests for non-ANSI charsets. */
1114 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1116 if(!is_font_installed("Tahoma"))
1118 skip("Tahoma is not installed so skipping this test\n");
1121 memset(&lf, 0, sizeof(lf));
1122 strcpy(lf.lfFaceName, "Tahoma");
1125 hfont = CreateFontIndirectA(&lf);
1126 hOldFont = SelectObject(hdc, hfont);
1127 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1128 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1129 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1130 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1131 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1133 testtext[0] = textm.tmDefaultChar;
1134 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1135 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1136 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1137 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1138 DeleteObject(SelectObject(hdc, hOldFont));
1141 static void test_GetKerningPairs(void)
1143 static const struct kerning_data
1145 const char face_name[LF_FACESIZE];
1147 /* some interesting fields from OUTLINETEXTMETRIC */
1148 LONG tmHeight, tmAscent, tmDescent;
1153 UINT otmsCapEmHeight;
1158 UINT otmusMinimumPPEM;
1159 /* small subset of kerning pairs to test */
1160 DWORD total_kern_pairs;
1161 const KERNINGPAIR kern_pair[26];
1164 {"Arial", 12, 12, 9, 3,
1165 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1168 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1169 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1170 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1171 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1172 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1173 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1174 {933,970,+1},{933,972,-1}
1177 {"Arial", -34, 39, 32, 7,
1178 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1181 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1182 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1183 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1184 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1185 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1186 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1187 {933,970,+2},{933,972,-3}
1190 { "Arial", 120, 120, 97, 23,
1191 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1194 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1195 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1196 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1197 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1198 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1199 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1200 {933,970,+6},{933,972,-10}
1203 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1204 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1205 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1208 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1209 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1210 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1211 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1212 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1213 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1214 {933,970,+54},{933,972,-83}
1220 HFONT hfont, hfont_old;
1221 KERNINGPAIR *kern_pair;
1223 DWORD total_kern_pairs, ret, i, n, matches;
1227 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1228 * which may render this test unusable, so we're trying to avoid that.
1230 SetLastError(0xdeadbeef);
1231 GetKerningPairsW(hdc, 0, NULL);
1232 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1234 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1239 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1241 OUTLINETEXTMETRICW otm;
1244 if (!is_font_installed(kd[i].face_name))
1246 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1250 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1252 memset(&lf, 0, sizeof(lf));
1253 strcpy(lf.lfFaceName, kd[i].face_name);
1254 lf.lfHeight = kd[i].height;
1255 hfont = CreateFontIndirect(&lf);
1258 hfont_old = SelectObject(hdc, hfont);
1260 SetLastError(0xdeadbeef);
1261 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1262 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1263 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1265 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1266 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1267 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1268 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1269 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1270 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1272 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1273 kd[i].otmEMSquare, otm.otmEMSquare);
1274 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1275 kd[i].otmAscent, otm.otmAscent);
1276 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1277 kd[i].otmDescent, otm.otmDescent);
1278 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1279 kd[i].otmLineGap, otm.otmLineGap);
1280 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1281 kd[i].otmMacDescent, otm.otmMacDescent);
1282 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1283 kd[i].otmMacAscent, otm.otmMacAscent);
1285 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1286 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1287 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1288 kd[i].otmsXHeight, otm.otmsXHeight);
1289 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1290 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1291 kd[i].otmMacLineGap, otm.otmMacLineGap);
1292 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1293 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1296 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1297 trace("total_kern_pairs %u\n", total_kern_pairs);
1298 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1300 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1301 SetLastError(0xdeadbeef);
1302 ret = GetKerningPairsW(hdc, 0, kern_pair);
1303 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1304 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1305 ok(ret == 0, "got %lu, expected 0\n", ret);
1308 ret = GetKerningPairsW(hdc, 100, NULL);
1309 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1311 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1312 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1314 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1315 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1319 for (n = 0; n < ret; n++)
1323 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1324 trace("{'%c','%c',%d},\n",
1325 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1327 for (j = 0; j < kd[i].total_kern_pairs; j++)
1329 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1330 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1332 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1333 "pair %d:%d got %d, expected %d\n",
1334 kern_pair[n].wFirst, kern_pair[n].wSecond,
1335 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1341 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1342 matches, kd[i].total_kern_pairs);
1344 HeapFree(GetProcessHeap(), 0, kern_pair);
1346 SelectObject(hdc, hfont_old);
1347 DeleteObject(hfont);
1353 static void test_height_selection(void)
1355 static const struct font_data
1357 const char face_name[LF_FACESIZE];
1358 int requested_height;
1359 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1362 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1363 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1364 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1365 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1366 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1367 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1368 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1369 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1370 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1371 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1375 HFONT hfont, old_hfont;
1379 hdc = CreateCompatibleDC(0);
1382 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1384 if (!is_truetype_font_installed(fd[i].face_name))
1386 skip("%s is not installed\n", fd[i].face_name);
1390 memset(&lf, 0, sizeof(lf));
1391 lf.lfHeight = fd[i].requested_height;
1392 lf.lfWeight = fd[i].weight;
1393 strcpy(lf.lfFaceName, fd[i].face_name);
1395 hfont = CreateFontIndirect(&lf);
1398 old_hfont = SelectObject(hdc, hfont);
1399 ret = GetTextMetrics(hdc, &tm);
1400 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1401 if(fd[i].dpi == tm.tmDigitizedAspectX)
1403 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1404 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);
1405 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);
1406 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);
1407 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);
1408 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1409 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);
1411 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);
1414 SelectObject(hdc, old_hfont);
1415 DeleteObject(hfont);
1421 static void test_GetOutlineTextMetrics(void)
1423 OUTLINETEXTMETRIC *otm;
1425 HFONT hfont, hfont_old;
1427 DWORD ret, otm_size;
1430 if (!is_font_installed("Arial"))
1432 skip("Arial is not installed\n");
1438 memset(&lf, 0, sizeof(lf));
1439 strcpy(lf.lfFaceName, "Arial");
1441 lf.lfWeight = FW_NORMAL;
1442 lf.lfPitchAndFamily = DEFAULT_PITCH;
1443 lf.lfQuality = PROOF_QUALITY;
1444 hfont = CreateFontIndirect(&lf);
1447 hfont_old = SelectObject(hdc, hfont);
1448 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1449 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1451 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1453 memset(otm, 0xAA, otm_size);
1454 SetLastError(0xdeadbeef);
1455 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1456 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1457 ok(ret == 1 /* Win9x */ ||
1458 ret == otm->otmSize /* XP*/,
1459 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1460 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1462 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1463 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1464 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1465 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1468 memset(otm, 0xAA, otm_size);
1469 SetLastError(0xdeadbeef);
1470 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1471 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1472 ok(ret == 1 /* Win9x */ ||
1473 ret == otm->otmSize /* XP*/,
1474 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1475 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1477 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1478 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1479 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1480 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1483 /* ask about truncated data */
1484 memset(otm, 0xAA, otm_size);
1485 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1486 SetLastError(0xdeadbeef);
1487 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1488 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1489 ok(ret == 1 /* Win9x */ ||
1490 ret == otm->otmSize /* XP*/,
1491 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1492 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1494 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1495 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1496 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1498 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1500 HeapFree(GetProcessHeap(), 0, otm);
1502 SelectObject(hdc, hfont_old);
1503 DeleteObject(hfont);
1508 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1512 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1513 areaWidth = clientArea->right - clientArea->left,
1515 BOOL lastExtent = FALSE;
1516 PSTR pFirstChar, pLastChar;
1522 int GetTextExtentExPointWWidth;
1525 GetTextMetricsA(hdc, &tm);
1526 y = clientArea->top;
1529 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1535 /* if not at the end of the string, ... */
1536 if (*str == '\0') break;
1537 /* ... add the next word to the current extent */
1538 while (*str != '\0' && *str++ != tm.tmBreakChar);
1540 SetTextJustification(hdc, 0, 0);
1541 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1542 } while ((int) size.cx < areaWidth);
1544 /* ignore trailing break chars */
1546 while (*(pLastChar - 1) == tm.tmBreakChar)
1552 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1554 SetTextJustification(hdc, 0, 0);
1555 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1557 /* do not justify the last extent */
1558 if (*str != '\0' && breakCount > 0)
1560 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1561 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1562 justifiedWidth = size.cx;
1564 else lastExtent = TRUE;
1566 /* catch errors and report them */
1567 if (!lastExtent && (justifiedWidth != areaWidth))
1569 memset(error[nErrors].extent, 0, 100);
1570 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1571 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1577 } while (*str && y < clientArea->bottom);
1579 for (e = 0; e < nErrors; e++)
1581 /* The width returned by GetTextExtentPoint32() is exactly the same
1582 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1583 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1584 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1585 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1589 static void test_SetTextJustification(void)
1596 static char testText[] =
1597 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1598 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1599 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1600 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1601 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1602 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1603 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1605 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1606 GetClientRect( hwnd, &clientArea );
1607 hdc = GetDC( hwnd );
1609 memset(&lf, 0, sizeof lf);
1610 lf.lfCharSet = ANSI_CHARSET;
1611 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1612 lf.lfWeight = FW_DONTCARE;
1614 lf.lfQuality = DEFAULT_QUALITY;
1615 lstrcpyA(lf.lfFaceName, "Times New Roman");
1616 hfont = create_font("Times New Roman", &lf);
1617 SelectObject(hdc, hfont);
1619 testJustification(hdc, testText, &clientArea);
1621 DeleteObject(hfont);
1622 ReleaseDC(hwnd, hdc);
1623 DestroyWindow(hwnd);
1626 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1630 HFONT hfont, hfont_old;
1637 assert(count <= 128);
1639 memset(&lf, 0, sizeof(lf));
1641 lf.lfCharSet = charset;
1643 lstrcpyA(lf.lfFaceName, "Arial");
1644 SetLastError(0xdeadbeef);
1645 hfont = CreateFontIndirectA(&lf);
1646 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1649 hfont_old = SelectObject(hdc, hfont);
1651 cs = GetTextCharsetInfo(hdc, &fs, 0);
1652 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1654 SetLastError(0xdeadbeef);
1655 ret = GetTextFaceA(hdc, sizeof(name), name);
1656 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1658 if (charset == SYMBOL_CHARSET)
1660 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1661 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1665 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1666 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1669 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1671 trace("Can't find codepage for charset %d\n", cs);
1675 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1677 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1679 skip("Font code page %d, looking for code page %d\n",
1680 pGdiGetCodePage(hdc), code_page);
1688 WCHAR unicode_buf[128];
1690 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1692 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1694 SetLastError(0xdeadbeef);
1695 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1696 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1697 count, ret, GetLastError());
1703 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1705 SetLastError(0xdeadbeef);
1706 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1707 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1708 count, ret, GetLastError());
1711 SelectObject(hdc, hfont_old);
1712 DeleteObject(hfont);
1719 static void test_font_charset(void)
1721 static struct charset_data
1725 WORD font_idxA[128], font_idxW[128];
1728 { ANSI_CHARSET, 1252 },
1729 { RUSSIAN_CHARSET, 1251 },
1730 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1734 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1736 win_skip("Skipping the font charset test on a Win9x platform\n");
1740 if (!is_font_installed("Arial"))
1742 skip("Arial is not installed\n");
1746 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1748 if (cd[i].charset == SYMBOL_CHARSET)
1750 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1752 skip("Symbol or Wingdings is not installed\n");
1756 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1757 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1758 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1761 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1764 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1765 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1768 skip("Symbol or Wingdings is not installed\n");
1771 static void test_GetFontUnicodeRanges(void)
1775 HFONT hfont, hfont_old;
1779 if (!pGetFontUnicodeRanges)
1781 win_skip("GetFontUnicodeRanges not available before W2K\n");
1785 memset(&lf, 0, sizeof(lf));
1786 lstrcpyA(lf.lfFaceName, "Arial");
1787 hfont = create_font("Arial", &lf);
1790 hfont_old = SelectObject(hdc, hfont);
1792 size = pGetFontUnicodeRanges(NULL, NULL);
1793 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1795 size = pGetFontUnicodeRanges(hdc, NULL);
1796 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1798 gs = HeapAlloc(GetProcessHeap(), 0, size);
1800 size = pGetFontUnicodeRanges(hdc, gs);
1801 ok(size, "GetFontUnicodeRanges failed\n");
1803 for (i = 0; i < gs->cRanges; i++)
1804 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1806 trace("found %u ranges\n", gs->cRanges);
1808 HeapFree(GetProcessHeap(), 0, gs);
1810 SelectObject(hdc, hfont_old);
1811 DeleteObject(hfont);
1812 ReleaseDC(NULL, hdc);
1815 #define MAX_ENUM_FONTS 4096
1817 struct enum_font_data
1820 LOGFONT lf[MAX_ENUM_FONTS];
1823 struct enum_font_dataW
1826 LOGFONTW lf[MAX_ENUM_FONTS];
1829 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1831 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1833 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1835 if (type != TRUETYPE_FONTTYPE) return 1;
1837 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1838 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1840 if (efd->total < MAX_ENUM_FONTS)
1841 efd->lf[efd->total++] = *lf;
1843 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1848 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1850 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1852 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1854 if (type != TRUETYPE_FONTTYPE) return 1;
1856 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1857 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1859 if (efd->total < MAX_ENUM_FONTS)
1860 efd->lf[efd->total++] = *lf;
1862 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1867 static void get_charset_stats(struct enum_font_data *efd,
1868 int *ansi_charset, int *symbol_charset,
1869 int *russian_charset)
1874 *symbol_charset = 0;
1875 *russian_charset = 0;
1877 for (i = 0; i < efd->total; i++)
1879 switch (efd->lf[i].lfCharSet)
1884 case SYMBOL_CHARSET:
1885 (*symbol_charset)++;
1887 case RUSSIAN_CHARSET:
1888 (*russian_charset)++;
1894 static void get_charset_statsW(struct enum_font_dataW *efd,
1895 int *ansi_charset, int *symbol_charset,
1896 int *russian_charset)
1901 *symbol_charset = 0;
1902 *russian_charset = 0;
1904 for (i = 0; i < efd->total; i++)
1906 switch (efd->lf[i].lfCharSet)
1911 case SYMBOL_CHARSET:
1912 (*symbol_charset)++;
1914 case RUSSIAN_CHARSET:
1915 (*russian_charset)++;
1921 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1923 struct enum_font_data efd;
1924 struct enum_font_dataW efdw;
1927 int i, ret, ansi_charset, symbol_charset, russian_charset;
1929 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1931 if (*font_name && !is_truetype_font_installed(font_name))
1933 skip("%s is not installed\n", font_name);
1939 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1940 * while EnumFontFamiliesEx doesn't.
1942 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1945 * Use EnumFontFamiliesW since win98 crashes when the
1946 * second parameter is NULL using EnumFontFamilies
1949 SetLastError(0xdeadbeef);
1950 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1951 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1954 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1955 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1956 ansi_charset, symbol_charset, russian_charset);
1957 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1958 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1959 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1960 ok(russian_charset > 0 ||
1961 broken(russian_charset == 0), /* NT4 */
1962 "NULL family should enumerate RUSSIAN_CHARSET\n");
1966 SetLastError(0xdeadbeef);
1967 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1968 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1971 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1972 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1973 ansi_charset, symbol_charset, russian_charset);
1974 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1975 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1976 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1977 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1982 SetLastError(0xdeadbeef);
1983 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1984 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1985 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1986 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1987 ansi_charset, symbol_charset, russian_charset,
1988 *font_name ? font_name : "<empty>");
1990 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1992 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1993 for (i = 0; i < efd.total; i++)
1995 /* FIXME: remove completely once Wine is fixed */
1996 if (efd.lf[i].lfCharSet != font_charset)
1999 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2002 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2003 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2004 font_name, efd.lf[i].lfFaceName);
2007 memset(&lf, 0, sizeof(lf));
2008 lf.lfCharSet = ANSI_CHARSET;
2009 lstrcpy(lf.lfFaceName, font_name);
2011 SetLastError(0xdeadbeef);
2012 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2013 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2014 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2015 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2016 ansi_charset, symbol_charset, russian_charset,
2017 *font_name ? font_name : "<empty>");
2018 if (font_charset == SYMBOL_CHARSET)
2021 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2023 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2027 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2028 for (i = 0; i < efd.total; i++)
2030 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2032 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2033 font_name, efd.lf[i].lfFaceName);
2037 /* DEFAULT_CHARSET should enumerate all available charsets */
2038 memset(&lf, 0, sizeof(lf));
2039 lf.lfCharSet = DEFAULT_CHARSET;
2040 lstrcpy(lf.lfFaceName, font_name);
2042 SetLastError(0xdeadbeef);
2043 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2044 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2045 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2046 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2047 ansi_charset, symbol_charset, russian_charset,
2048 *font_name ? font_name : "<empty>");
2049 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2050 for (i = 0; i < efd.total; i++)
2053 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2054 font_name, efd.lf[i].lfFaceName);
2058 switch (font_charset)
2061 ok(ansi_charset > 0,
2062 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2064 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2065 ok(russian_charset > 0,
2066 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2068 case SYMBOL_CHARSET:
2070 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2072 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2073 ok(!russian_charset,
2074 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2076 case DEFAULT_CHARSET:
2077 ok(ansi_charset > 0,
2078 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2079 ok(symbol_charset > 0,
2080 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2081 ok(russian_charset > 0,
2082 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2088 ok(ansi_charset > 0,
2089 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2090 ok(symbol_charset > 0,
2091 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2092 ok(russian_charset > 0,
2093 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2096 memset(&lf, 0, sizeof(lf));
2097 lf.lfCharSet = SYMBOL_CHARSET;
2098 lstrcpy(lf.lfFaceName, font_name);
2100 SetLastError(0xdeadbeef);
2101 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2102 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2103 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2104 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2105 ansi_charset, symbol_charset, russian_charset,
2106 *font_name ? font_name : "<empty>");
2107 if (*font_name && font_charset == ANSI_CHARSET)
2108 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2111 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2112 for (i = 0; i < efd.total; i++)
2114 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2116 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2117 font_name, efd.lf[i].lfFaceName);
2121 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2122 ok(symbol_charset > 0,
2123 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2124 ok(!russian_charset,
2125 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2131 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2133 HFONT hfont, hfont_prev;
2135 GLYPHMETRICS gm1, gm2;
2138 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2140 if(!pGetGlyphIndicesA)
2143 /* negative widths are handled just as positive ones */
2144 lf2.lfWidth = -lf->lfWidth;
2146 SetLastError(0xdeadbeef);
2147 hfont = CreateFontIndirectA(lf);
2148 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2149 check_font("original", lf, hfont);
2151 hfont_prev = SelectObject(hdc, hfont);
2153 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2154 if (ret == GDI_ERROR || idx == 0xffff)
2156 SelectObject(hdc, hfont_prev);
2157 DeleteObject(hfont);
2158 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2162 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2163 memset(&gm1, 0xab, sizeof(gm1));
2164 SetLastError(0xdeadbeef);
2165 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2166 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2168 SelectObject(hdc, hfont_prev);
2169 DeleteObject(hfont);
2171 SetLastError(0xdeadbeef);
2172 hfont = CreateFontIndirectA(&lf2);
2173 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2174 check_font("negative width", &lf2, hfont);
2176 hfont_prev = SelectObject(hdc, hfont);
2178 memset(&gm2, 0xbb, sizeof(gm2));
2179 SetLastError(0xdeadbeef);
2180 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2181 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2183 SelectObject(hdc, hfont_prev);
2184 DeleteObject(hfont);
2186 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2187 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2188 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2189 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2190 gm1.gmCellIncX == gm2.gmCellIncX &&
2191 gm1.gmCellIncY == gm2.gmCellIncY,
2192 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2193 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2194 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2195 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2196 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2199 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2200 #include "pshpack2.h"
2204 SHORT xAvgCharWidth;
2205 USHORT usWeightClass;
2206 USHORT usWidthClass;
2208 SHORT ySubscriptXSize;
2209 SHORT ySubscriptYSize;
2210 SHORT ySubscriptXOffset;
2211 SHORT ySubscriptYOffset;
2212 SHORT ySuperscriptXSize;
2213 SHORT ySuperscriptYSize;
2214 SHORT ySuperscriptXOffset;
2215 SHORT ySuperscriptYOffset;
2216 SHORT yStrikeoutSize;
2217 SHORT yStrikeoutPosition;
2220 ULONG ulUnicodeRange1;
2221 ULONG ulUnicodeRange2;
2222 ULONG ulUnicodeRange3;
2223 ULONG ulUnicodeRange4;
2226 USHORT usFirstCharIndex;
2227 USHORT usLastCharIndex;
2228 /* According to the Apple spec, original version didn't have the below fields,
2229 * version numbers were taked from the OpenType spec.
2231 /* version 0 (TrueType 1.5) */
2232 USHORT sTypoAscender;
2233 USHORT sTypoDescender;
2234 USHORT sTypoLineGap;
2236 USHORT usWinDescent;
2237 /* version 1 (TrueType 1.66) */
2238 ULONG ulCodePageRange1;
2239 ULONG ulCodePageRange2;
2240 /* version 2 (OpenType 1.2) */
2243 USHORT usDefaultChar;
2245 USHORT usMaxContext;
2247 #include "poppack.h"
2249 #ifdef WORDS_BIGENDIAN
2250 #define GET_BE_WORD(x) (x)
2251 #define GET_BE_DWORD(x) (x)
2253 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2254 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2257 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2258 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2259 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2260 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2261 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2274 } cmap_encoding_record;
2282 BYTE glyph_ids[256];
2292 USHORT search_range;
2293 USHORT entry_selector;
2296 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2299 USHORT start_count[seg_countx2 / 2];
2300 USHORT id_delta[seg_countx2 / 2];
2301 USHORT id_range_offset[seg_countx2 / 2];
2311 USHORT id_range_offset;
2312 } cmap_format_4_seg;
2314 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2316 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2317 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2318 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2319 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2320 os2->panose.bWeight, os2->panose.bProportion);
2323 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2326 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2330 for(i = 0; i < 256; i++)
2332 if(cmap->glyph_ids[i] == 0) continue;
2334 if(*first == 256) *first = i;
2336 if(*first == 256) return FALSE;
2340 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2342 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2343 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2344 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2345 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2346 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2349 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2352 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2353 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2354 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2358 for(i = 0; i < seg_count; i++)
2361 cmap_format_4_seg seg;
2363 get_seg4(cmap, i, &seg);
2364 for(code = seg.start_count; code <= seg.end_count; code++)
2366 if(seg.id_range_offset == 0)
2367 index = (seg.id_delta + code) & 0xffff;
2370 index = seg.id_range_offset / 2
2371 + code - seg.start_count
2374 /* some fonts have broken last segment */
2375 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2376 index = GET_BE_WORD(glyph_ids[index]);
2379 trace("segment %04x/%04x index %04x points to nowhere\n",
2380 seg.start_count, seg.end_count, index);
2383 if(index) index += seg.id_delta;
2385 if(*first == 0x10000)
2386 *last = *first = code;
2392 if(*first == 0x10000) return FALSE;
2396 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2399 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2401 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2403 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2404 return (BYTE *)header + GET_BE_DWORD(record->offset);
2417 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2420 cmap_header *header;
2425 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2426 ok(size != GDI_ERROR, "no cmap table found\n");
2427 if(size == GDI_ERROR) return FALSE;
2429 header = HeapAlloc(GetProcessHeap(), 0, size);
2430 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2431 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2432 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2434 cmap = get_cmap(header, 3, 1);
2436 *cmap_type = cmap_ms_unicode;
2439 cmap = get_cmap(header, 3, 0);
2440 if(cmap) *cmap_type = cmap_ms_symbol;
2444 *cmap_type = cmap_none;
2448 format = GET_BE_WORD(*(WORD *)cmap);
2452 r = get_first_last_from_cmap0(cmap, first, last);
2455 r = get_first_last_from_cmap4(cmap, first, last, size);
2458 trace("unhandled cmap format %d\n", format);
2463 HeapFree(GetProcessHeap(), 0, header);
2467 static void test_text_metrics(const LOGFONTA *lf)
2470 HFONT hfont, hfont_old;
2474 const char *font_name = lf->lfFaceName;
2475 DWORD cmap_first = 0, cmap_last = 0;
2476 cmap_type cmap_type;
2477 BOOL sys_lang_non_english;
2479 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2482 SetLastError(0xdeadbeef);
2483 hfont = CreateFontIndirectA(lf);
2484 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2486 hfont_old = SelectObject(hdc, hfont);
2488 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2489 if (size == GDI_ERROR)
2491 trace("OS/2 chunk was not found\n");
2494 if (size > sizeof(tt_os2))
2496 trace("got too large OS/2 chunk of size %u\n", size);
2497 size = sizeof(tt_os2);
2500 memset(&tt_os2, 0, sizeof(tt_os2));
2501 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2502 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2504 SetLastError(0xdeadbeef);
2505 ret = GetTextMetricsA(hdc, &tmA);
2506 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2508 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2510 skip("Unable to retrieve first and last glyphs from cmap\n");
2514 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2515 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2516 UINT os2_first_char, os2_last_char, default_char, break_char;
2520 version = GET_BE_WORD(tt_os2.version);
2522 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2523 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2524 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2525 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2527 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2528 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2529 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2531 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2536 case 1257: /* Baltic */
2537 expect_last_W = 0xf8fd;
2540 expect_last_W = 0xf0ff;
2542 expect_break_W = 0x20;
2543 expect_default_W = expect_break_W - 1;
2544 expect_first_A = 0x1e;
2545 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2549 expect_first_W = cmap_first;
2550 expect_last_W = min(cmap_last, os2_last_char);
2551 if(os2_first_char <= 1)
2552 expect_break_W = os2_first_char + 2;
2553 else if(os2_first_char > 0xff)
2554 expect_break_W = 0x20;
2556 expect_break_W = os2_first_char;
2557 expect_default_W = expect_break_W - 1;
2558 expect_first_A = expect_default_W - 1;
2559 expect_last_A = min(expect_last_W, 0xff);
2561 expect_break_A = expect_break_W;
2562 expect_default_A = expect_default_W;
2564 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2565 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2566 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2567 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2568 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2570 ok(tmA.tmFirstChar == expect_first_A ||
2571 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2572 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2573 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2574 ok(tmA.tmLastChar == expect_last_A ||
2575 tmA.tmLastChar == 0xff /* win9x */,
2576 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2578 skip("tmLastChar is DBCS lead byte\n");
2579 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2580 font_name, tmA.tmBreakChar, expect_break_A);
2581 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2582 "A: tmDefaultChar for %s got %02x expected %02x\n",
2583 font_name, tmA.tmDefaultChar, expect_default_A);
2586 SetLastError(0xdeadbeef);
2587 ret = GetTextMetricsW(hdc, &tmW);
2588 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2589 "GetTextMetricsW error %u\n", GetLastError());
2592 /* Wine uses the os2 first char */
2593 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2594 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2595 font_name, tmW.tmFirstChar, expect_first_W);
2597 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2598 font_name, tmW.tmFirstChar, expect_first_W);
2600 /* Wine uses the os2 last char */
2601 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2602 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2603 font_name, tmW.tmLastChar, expect_last_W);
2605 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2606 font_name, tmW.tmLastChar, expect_last_W);
2607 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2608 font_name, tmW.tmBreakChar, expect_break_W);
2609 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2610 "W: tmDefaultChar for %s got %02x expected %02x\n",
2611 font_name, tmW.tmDefaultChar, expect_default_W);
2613 /* Test the aspect ratio while we have tmW */
2614 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2615 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2616 tmW.tmDigitizedAspectX, ret);
2617 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2618 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2619 tmW.tmDigitizedAspectX, ret);
2623 /* test FF_ values */
2624 switch(tt_os2.panose.bFamilyType)
2628 case PAN_FAMILY_TEXT_DISPLAY:
2629 case PAN_FAMILY_PICTORIAL:
2631 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2632 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2634 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2637 switch(tt_os2.panose.bSerifStyle)
2642 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2645 case PAN_SERIF_COVE:
2646 case PAN_SERIF_OBTUSE_COVE:
2647 case PAN_SERIF_SQUARE_COVE:
2648 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2649 case PAN_SERIF_SQUARE:
2650 case PAN_SERIF_THIN:
2651 case PAN_SERIF_BONE:
2652 case PAN_SERIF_EXAGGERATED:
2653 case PAN_SERIF_TRIANGLE:
2654 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2657 case PAN_SERIF_NORMAL_SANS:
2658 case PAN_SERIF_OBTUSE_SANS:
2659 case PAN_SERIF_PERP_SANS:
2660 case PAN_SERIF_FLARED:
2661 case PAN_SERIF_ROUNDED:
2662 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2667 case PAN_FAMILY_SCRIPT:
2668 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2671 case PAN_FAMILY_DECORATIVE:
2672 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2676 test_negative_width(hdc, lf);
2679 SelectObject(hdc, hfont_old);
2680 DeleteObject(hfont);
2685 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2687 INT *enumed = (INT *)lParam;
2689 if (type == TRUETYPE_FONTTYPE)
2692 test_text_metrics(lf);
2697 static void test_GetTextMetrics(void)
2703 /* Report only once */
2704 if(!pGetGlyphIndicesA)
2705 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2709 memset(&lf, 0, sizeof(lf));
2710 lf.lfCharSet = DEFAULT_CHARSET;
2712 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2713 trace("Tested metrics of %d truetype fonts\n", enumed);
2718 static void test_nonexistent_font(void)
2726 { "Times New Roman Baltic", 186 },
2727 { "Times New Roman CE", 238 },
2728 { "Times New Roman CYR", 204 },
2729 { "Times New Roman Greek", 161 },
2730 { "Times New Roman TUR", 162 }
2736 INT cs, expected_cs, i;
2737 char buf[LF_FACESIZE];
2739 if (!is_truetype_font_installed("Arial") ||
2740 !is_truetype_font_installed("Times New Roman"))
2742 skip("Arial or Times New Roman not installed\n");
2746 expected_cs = GetACP();
2747 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2749 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2752 expected_cs = csi.ciCharset;
2753 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2757 memset(&lf, 0, sizeof(lf));
2759 lf.lfWeight = FW_REGULAR;
2760 lf.lfCharSet = ANSI_CHARSET;
2761 lf.lfPitchAndFamily = FF_SWISS;
2762 strcpy(lf.lfFaceName, "Nonexistent font");
2763 hfont = CreateFontIndirectA(&lf);
2764 hfont = SelectObject(hdc, hfont);
2765 GetTextFaceA(hdc, sizeof(buf), buf);
2766 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2767 cs = GetTextCharset(hdc);
2768 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2769 DeleteObject(SelectObject(hdc, hfont));
2771 memset(&lf, 0, sizeof(lf));
2773 lf.lfWeight = FW_DONTCARE;
2774 strcpy(lf.lfFaceName, "Nonexistent font");
2775 hfont = CreateFontIndirectA(&lf);
2776 hfont = SelectObject(hdc, hfont);
2777 GetTextFaceA(hdc, sizeof(buf), buf);
2778 todo_wine /* Wine uses Arial for all substitutions */
2779 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2780 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2781 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2783 cs = GetTextCharset(hdc);
2784 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2785 DeleteObject(SelectObject(hdc, hfont));
2787 memset(&lf, 0, sizeof(lf));
2789 lf.lfWeight = FW_REGULAR;
2790 strcpy(lf.lfFaceName, "Nonexistent font");
2791 hfont = CreateFontIndirectA(&lf);
2792 hfont = SelectObject(hdc, hfont);
2793 GetTextFaceA(hdc, sizeof(buf), buf);
2794 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2795 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2796 cs = GetTextCharset(hdc);
2797 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2798 DeleteObject(SelectObject(hdc, hfont));
2800 memset(&lf, 0, sizeof(lf));
2802 lf.lfWeight = FW_DONTCARE;
2803 strcpy(lf.lfFaceName, "Times New Roman");
2804 hfont = CreateFontIndirectA(&lf);
2805 hfont = SelectObject(hdc, hfont);
2806 GetTextFaceA(hdc, sizeof(buf), buf);
2807 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2808 cs = GetTextCharset(hdc);
2809 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2810 DeleteObject(SelectObject(hdc, hfont));
2812 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2814 memset(&lf, 0, sizeof(lf));
2816 lf.lfWeight = FW_REGULAR;
2817 strcpy(lf.lfFaceName, font_subst[i].name);
2818 hfont = CreateFontIndirectA(&lf);
2819 hfont = SelectObject(hdc, hfont);
2820 cs = GetTextCharset(hdc);
2821 if (font_subst[i].charset == expected_cs)
2823 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2824 GetTextFaceA(hdc, sizeof(buf), buf);
2825 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2829 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2830 GetTextFaceA(hdc, sizeof(buf), buf);
2831 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2832 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2834 DeleteObject(SelectObject(hdc, hfont));
2836 memset(&lf, 0, sizeof(lf));
2838 lf.lfWeight = FW_DONTCARE;
2839 strcpy(lf.lfFaceName, font_subst[i].name);
2840 hfont = CreateFontIndirectA(&lf);
2841 hfont = SelectObject(hdc, hfont);
2842 GetTextFaceA(hdc, sizeof(buf), buf);
2843 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2844 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2845 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2846 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2847 "got %s for font %s\n", buf, font_subst[i].name);
2848 cs = GetTextCharset(hdc);
2849 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2850 DeleteObject(SelectObject(hdc, hfont));
2856 static void test_GdiRealizationInfo(void)
2861 HFONT hfont, hfont_old;
2864 if(!pGdiRealizationInfo)
2866 win_skip("GdiRealizationInfo not available\n");
2872 memset(info, 0xcc, sizeof(info));
2873 r = pGdiRealizationInfo(hdc, info);
2874 ok(r != 0, "ret 0\n");
2875 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2876 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2878 if (!is_truetype_font_installed("Arial"))
2880 skip("skipping GdiRealizationInfo with truetype font\n");
2884 memset(&lf, 0, sizeof(lf));
2885 strcpy(lf.lfFaceName, "Arial");
2887 lf.lfWeight = FW_NORMAL;
2888 hfont = CreateFontIndirectA(&lf);
2889 hfont_old = SelectObject(hdc, hfont);
2891 memset(info, 0xcc, sizeof(info));
2892 r = pGdiRealizationInfo(hdc, info);
2893 ok(r != 0, "ret 0\n");
2894 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2895 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2897 DeleteObject(SelectObject(hdc, hfont_old));
2903 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2904 the nul in the count of characters copied when the face name buffer is not
2905 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2906 always includes it. */
2907 static void test_GetTextFace(void)
2909 static const char faceA[] = "Tahoma";
2910 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2913 char bufA[LF_FACESIZE];
2914 WCHAR bufW[LF_FACESIZE];
2919 if(!is_font_installed("Tahoma"))
2921 skip("Tahoma is not installed so skipping this test\n");
2926 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2927 f = CreateFontIndirectA(&fA);
2928 ok(f != NULL, "CreateFontIndirectA failed\n");
2931 g = SelectObject(dc, f);
2932 n = GetTextFaceA(dc, sizeof bufA, bufA);
2933 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2934 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2936 /* Play with the count arg. */
2938 n = GetTextFaceA(dc, 0, bufA);
2939 ok(n == 0, "GetTextFaceA returned %d\n", n);
2940 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2943 n = GetTextFaceA(dc, 1, bufA);
2944 ok(n == 0, "GetTextFaceA returned %d\n", n);
2945 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2947 bufA[0] = 'x'; bufA[1] = 'y';
2948 n = GetTextFaceA(dc, 2, bufA);
2949 ok(n == 1, "GetTextFaceA returned %d\n", n);
2950 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2952 n = GetTextFaceA(dc, 0, NULL);
2953 ok(n == sizeof faceA ||
2954 broken(n == 0), /* win98, winMe */
2955 "GetTextFaceA returned %d\n", n);
2957 DeleteObject(SelectObject(dc, g));
2958 ReleaseDC(NULL, dc);
2961 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2962 SetLastError(0xdeadbeef);
2963 f = CreateFontIndirectW(&fW);
2964 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2966 win_skip("CreateFontIndirectW is not implemented\n");
2969 ok(f != NULL, "CreateFontIndirectW failed\n");
2972 g = SelectObject(dc, f);
2973 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2974 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2975 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2977 /* Play with the count arg. */
2979 n = GetTextFaceW(dc, 0, bufW);
2980 ok(n == 0, "GetTextFaceW returned %d\n", n);
2981 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2984 n = GetTextFaceW(dc, 1, bufW);
2985 ok(n == 1, "GetTextFaceW returned %d\n", n);
2986 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2988 bufW[0] = 'x'; bufW[1] = 'y';
2989 n = GetTextFaceW(dc, 2, bufW);
2990 ok(n == 2, "GetTextFaceW returned %d\n", n);
2991 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2993 n = GetTextFaceW(dc, 0, NULL);
2994 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2996 DeleteObject(SelectObject(dc, g));
2997 ReleaseDC(NULL, dc);
3000 static void test_orientation(void)
3002 static const char test_str[11] = "Test String";
3005 HFONT hfont, old_hfont;
3008 if (!is_truetype_font_installed("Arial"))
3010 skip("Arial is not installed\n");
3014 hdc = CreateCompatibleDC(0);
3015 memset(&lf, 0, sizeof(lf));
3016 lstrcpyA(lf.lfFaceName, "Arial");
3018 lf.lfOrientation = lf.lfEscapement = 900;
3019 hfont = create_font("orientation", &lf);
3020 old_hfont = SelectObject(hdc, hfont);
3021 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3022 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3023 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3024 SelectObject(hdc, old_hfont);
3025 DeleteObject(hfont);
3029 static void test_oemcharset(void)
3033 HFONT hfont, old_hfont;
3036 hdc = CreateCompatibleDC(0);
3037 ZeroMemory(&lf, sizeof(lf));
3039 lf.lfCharSet = OEM_CHARSET;
3040 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3041 lstrcpyA(lf.lfFaceName, "Terminal");
3042 hfont = CreateFontIndirectA(&lf);
3043 old_hfont = SelectObject(hdc, hfont);
3044 charset = GetTextCharset(hdc);
3046 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3047 hfont = SelectObject(hdc, old_hfont);
3048 GetObjectA(hfont, sizeof(clf), &clf);
3049 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3050 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3051 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3052 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3053 DeleteObject(hfont);
3057 static void test_GetGlyphOutline(void)
3059 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
3063 HFONT hfont, old_hfont;
3066 if (!is_truetype_font_installed("Tahoma"))
3068 skip("Tahoma is not installed\n");
3072 hdc = CreateCompatibleDC(0);
3073 memset(&lf, 0, sizeof(lf));
3075 lstrcpyA(lf.lfFaceName, "Tahoma");
3076 SetLastError(0xdeadbeef);
3077 hfont = CreateFontIndirectA(&lf);
3078 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3079 old_hfont = SelectObject(hdc, hfont);
3081 memset(&gm, 0, sizeof(gm));
3082 SetLastError(0xdeadbeef);
3083 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3084 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3086 memset(&gm, 0, sizeof(gm));
3087 SetLastError(0xdeadbeef);
3088 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3089 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3090 ok(GetLastError() == 0xdeadbeef ||
3091 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3092 "expected 0xdeadbeef, got %u\n", GetLastError());
3094 memset(&gm, 0, sizeof(gm));
3095 SetLastError(0xdeadbeef);
3096 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3097 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3098 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3100 memset(&gm, 0, sizeof(gm));
3101 SetLastError(0xdeadbeef);
3102 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3103 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3105 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3106 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3109 /* test for needed buffer size request on space char */
3110 memset(&gm, 0, sizeof(gm));
3111 SetLastError(0xdeadbeef);
3112 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3113 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3114 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3116 /* requesting buffer size for space char + error */
3117 memset(&gm, 0, sizeof(gm));
3118 SetLastError(0xdeadbeef);
3119 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3120 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3122 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3123 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3126 SelectObject(hdc, old_hfont);
3127 DeleteObject(hfont);
3131 /* bug #9995: there is a limit to the character width that can be specified */
3132 static void test_GetTextMetrics2(const char *fontname, int font_height)
3138 int ave_width, height, width, ratio, scale;
3140 if (!is_truetype_font_installed( fontname)) {
3141 skip("%s is not installed\n", fontname);
3144 hdc = CreateCompatibleDC(0);
3145 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3146 /* select width = 0 */
3147 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3148 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3149 DEFAULT_QUALITY, VARIABLE_PITCH,
3151 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3152 of = SelectObject( hdc, hf);
3153 ret = GetTextMetricsA( hdc, &tm);
3154 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3155 height = tm.tmHeight;
3156 ave_width = tm.tmAveCharWidth;
3157 SelectObject( hdc, of);
3160 trace("height %d, ave width %d\n", height, ave_width);
3162 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3164 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3165 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3166 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3167 ok(hf != 0, "CreateFont failed\n");
3168 of = SelectObject(hdc, hf);
3169 ret = GetTextMetrics(hdc, &tm);
3170 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3171 SelectObject(hdc, of);
3174 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3180 ratio = width / height;
3181 scale = width / ave_width;
3183 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3184 width, height, ratio, width, ave_width, scale);
3186 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3189 static void test_CreateFontIndirect(void)
3191 LOGFONTA lf, getobj_lf;
3194 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3196 memset(&lf, 0, sizeof(lf));
3197 lf.lfCharSet = ANSI_CHARSET;
3198 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3201 lf.lfQuality = DEFAULT_QUALITY;
3202 lf.lfItalic = FALSE;
3203 lf.lfWeight = FW_DONTCARE;
3205 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3207 lstrcpyA(lf.lfFaceName, TestName[i]);
3208 hfont = CreateFontIndirectA(&lf);
3209 ok(hfont != 0, "CreateFontIndirectA failed\n");
3210 SetLastError(0xdeadbeef);
3211 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3212 ok(ret, "GetObject failed: %d\n", GetLastError());
3213 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3214 ok(lf.lfWeight == getobj_lf.lfWeight ||
3215 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3216 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3217 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3218 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3219 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3220 DeleteObject(hfont);
3224 static void test_CreateFontIndirectEx(void)
3226 ENUMLOGFONTEXDVA lfex;
3229 if (!pCreateFontIndirectExA)
3231 win_skip("CreateFontIndirectExA is not available\n");
3235 if (!is_truetype_font_installed("Arial"))
3237 skip("Arial is not installed\n");
3241 SetLastError(0xdeadbeef);
3242 hfont = pCreateFontIndirectExA(NULL);
3243 ok(hfont == NULL, "got %p\n", hfont);
3244 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3246 memset(&lfex, 0, sizeof(lfex));
3247 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3248 hfont = pCreateFontIndirectExA(&lfex);
3249 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3251 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3252 DeleteObject(hfont);
3255 static void free_font(void *font)
3257 UnmapViewOfFile(font);
3260 static void *load_font(const char *font_name, DWORD *font_size)
3262 char file_name[MAX_PATH];
3263 HANDLE file, mapping;
3266 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3267 strcat(file_name, "\\fonts\\");
3268 strcat(file_name, font_name);
3270 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3271 if (file == INVALID_HANDLE_VALUE) return NULL;
3273 *font_size = GetFileSize(file, NULL);
3275 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3282 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3285 CloseHandle(mapping);
3289 static void test_AddFontMemResource(void)
3292 DWORD font_size, num_fonts;
3296 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3298 win_skip("AddFontMemResourceEx is not available on this platform\n");
3302 font = load_font("sserife.fon", &font_size);
3305 skip("Unable to locate and load font sserife.fon\n");
3309 SetLastError(0xdeadbeef);
3310 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3311 ok(!ret, "AddFontMemResourceEx should fail\n");
3312 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3313 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3316 SetLastError(0xdeadbeef);
3317 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3318 ok(!ret, "AddFontMemResourceEx should fail\n");
3319 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3320 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3323 SetLastError(0xdeadbeef);
3324 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3325 ok(!ret, "AddFontMemResourceEx should fail\n");
3326 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3327 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3330 SetLastError(0xdeadbeef);
3331 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3332 ok(!ret, "AddFontMemResourceEx should fail\n");
3333 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3334 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3337 SetLastError(0xdeadbeef);
3338 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3339 ok(!ret, "AddFontMemResourceEx should fail\n");
3340 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3341 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3344 SetLastError(0xdeadbeef);
3345 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3346 ok(!ret, "AddFontMemResourceEx should fail\n");
3347 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3348 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3351 num_fonts = 0xdeadbeef;
3352 SetLastError(0xdeadbeef);
3353 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3354 ok(!ret, "AddFontMemResourceEx should fail\n");
3355 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3356 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3358 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3360 if (0) /* hangs under windows 2000 */
3362 num_fonts = 0xdeadbeef;
3363 SetLastError(0xdeadbeef);
3364 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3365 ok(!ret, "AddFontMemResourceEx should fail\n");
3366 ok(GetLastError() == 0xdeadbeef,
3367 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3369 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3372 num_fonts = 0xdeadbeef;
3373 SetLastError(0xdeadbeef);
3374 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3375 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3376 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3377 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3381 SetLastError(0xdeadbeef);
3382 bRet = pRemoveFontMemResourceEx(ret);
3383 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3385 /* test invalid pointer to number of loaded fonts */
3386 font = load_font("sserife.fon", &font_size);
3387 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3389 SetLastError(0xdeadbeef);
3390 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3391 ok(!ret, "AddFontMemResourceEx should fail\n");
3392 ok(GetLastError() == 0xdeadbeef,
3393 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3396 SetLastError(0xdeadbeef);
3397 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3398 ok(!ret, "AddFontMemResourceEx should fail\n");
3399 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3400 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3412 test_outline_font();
3413 test_bitmap_font_metrics();
3414 test_GdiGetCharDimensions();
3415 test_GetCharABCWidths();
3416 test_text_extents();
3417 test_GetGlyphIndices();
3418 test_GetKerningPairs();
3419 test_GetOutlineTextMetrics();
3420 test_SetTextJustification();
3421 test_font_charset();
3422 test_GetFontUnicodeRanges();
3423 test_nonexistent_font();
3425 test_height_selection();
3426 test_AddFontMemResource();
3428 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3429 * I'd like to avoid them in this test.
3431 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3432 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3433 if (is_truetype_font_installed("Arial Black") &&
3434 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3436 test_EnumFontFamilies("", ANSI_CHARSET);
3437 test_EnumFontFamilies("", SYMBOL_CHARSET);
3438 test_EnumFontFamilies("", DEFAULT_CHARSET);
3441 skip("Arial Black or Symbol/Wingdings is not installed\n");
3442 test_GetTextMetrics();
3443 test_GdiRealizationInfo();
3445 test_GetGlyphOutline();
3446 test_GetTextMetrics2("Tahoma", -11);
3447 test_GetTextMetrics2("Tahoma", -55);
3448 test_GetTextMetrics2("Tahoma", -110);
3449 test_GetTextMetrics2("Arial", -11);
3450 test_GetTextMetrics2("Arial", -55);
3451 test_GetTextMetrics2("Arial", -110);
3452 test_CreateFontIndirect();
3453 test_CreateFontIndirectEx();