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");
991 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
992 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
994 hfont = SelectObject(hdc, hfont);
998 ReleaseDC(NULL, hdc);
1001 static void test_text_extents(void)
1003 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1005 INT i, len, fit1, fit2;
1013 memset(&lf, 0, sizeof(lf));
1014 strcpy(lf.lfFaceName, "Arial");
1017 hfont = CreateFontIndirectA(&lf);
1019 hfont = SelectObject(hdc, hfont);
1020 GetTextMetricsA(hdc, &tm);
1021 GetTextExtentPointA(hdc, "o", 1, &sz);
1022 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1024 SetLastError(0xdeadbeef);
1025 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1026 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1028 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1029 hfont = SelectObject(hdc, hfont);
1030 DeleteObject(hfont);
1036 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1037 extents[0] = 1; /* So that the increasing sequence test will fail
1038 if the extents array is untouched. */
1039 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1040 GetTextExtentPointW(hdc, wt, len, &sz2);
1041 ok(sz1.cy == sz2.cy,
1042 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1043 /* Because of the '\n' in the string GetTextExtentExPoint and
1044 GetTextExtentPoint return different widths under Win2k, but
1045 under WinXP they return the same width. So we don't test that
1048 for (i = 1; i < len; ++i)
1049 ok(extents[i-1] <= extents[i],
1050 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1052 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1053 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1054 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1055 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1056 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1057 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1058 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1059 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1060 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1061 ok(extents[0] == extents[2] && extents[1] == extents[3],
1062 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1063 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1064 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1065 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1066 HeapFree(GetProcessHeap(), 0, extents);
1068 hfont = SelectObject(hdc, hfont);
1069 DeleteObject(hfont);
1070 ReleaseDC(NULL, hdc);
1073 static void test_GetGlyphIndices(void)
1080 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1081 WORD glyphs[(sizeof(testtext)/2)-1];
1085 if (!pGetGlyphIndicesW) {
1086 win_skip("GetGlyphIndicesW not available on platform\n");
1092 memset(&lf, 0, sizeof(lf));
1093 strcpy(lf.lfFaceName, "System");
1095 lf.lfCharSet = ANSI_CHARSET;
1097 hfont = CreateFontIndirectA(&lf);
1098 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1099 if (textm.tmCharSet == ANSI_CHARSET)
1101 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1102 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1103 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1104 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1106 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1107 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1108 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1109 textm.tmDefaultChar, glyphs[4]);
1112 /* FIXME: Write tests for non-ANSI charsets. */
1113 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1115 if(!is_font_installed("Tahoma"))
1117 skip("Tahoma is not installed so skipping this test\n");
1120 memset(&lf, 0, sizeof(lf));
1121 strcpy(lf.lfFaceName, "Tahoma");
1124 hfont = CreateFontIndirectA(&lf);
1125 hOldFont = SelectObject(hdc, hfont);
1126 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1127 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1128 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1129 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1130 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1132 testtext[0] = textm.tmDefaultChar;
1133 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1134 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1135 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1136 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1137 DeleteObject(SelectObject(hdc, hOldFont));
1140 static void test_GetKerningPairs(void)
1142 static const struct kerning_data
1144 const char face_name[LF_FACESIZE];
1146 /* some interesting fields from OUTLINETEXTMETRIC */
1147 LONG tmHeight, tmAscent, tmDescent;
1152 UINT otmsCapEmHeight;
1157 UINT otmusMinimumPPEM;
1158 /* small subset of kerning pairs to test */
1159 DWORD total_kern_pairs;
1160 const KERNINGPAIR kern_pair[26];
1163 {"Arial", 12, 12, 9, 3,
1164 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1167 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1168 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1169 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1170 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1171 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1172 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1173 {933,970,+1},{933,972,-1}
1176 {"Arial", -34, 39, 32, 7,
1177 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1180 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1181 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1182 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1183 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1184 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1185 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1186 {933,970,+2},{933,972,-3}
1189 { "Arial", 120, 120, 97, 23,
1190 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1193 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1194 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1195 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1196 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1197 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1198 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1199 {933,970,+6},{933,972,-10}
1202 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1203 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1204 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1207 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1208 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1209 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1210 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1211 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1212 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1213 {933,970,+54},{933,972,-83}
1219 HFONT hfont, hfont_old;
1220 KERNINGPAIR *kern_pair;
1222 DWORD total_kern_pairs, ret, i, n, matches;
1226 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1227 * which may render this test unusable, so we're trying to avoid that.
1229 SetLastError(0xdeadbeef);
1230 GetKerningPairsW(hdc, 0, NULL);
1231 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1233 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1238 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1240 OUTLINETEXTMETRICW otm;
1243 if (!is_font_installed(kd[i].face_name))
1245 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1249 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1251 memset(&lf, 0, sizeof(lf));
1252 strcpy(lf.lfFaceName, kd[i].face_name);
1253 lf.lfHeight = kd[i].height;
1254 hfont = CreateFontIndirect(&lf);
1257 hfont_old = SelectObject(hdc, hfont);
1259 SetLastError(0xdeadbeef);
1260 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1261 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1262 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1264 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1265 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1266 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1267 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1268 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1269 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1271 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1272 kd[i].otmEMSquare, otm.otmEMSquare);
1273 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1274 kd[i].otmAscent, otm.otmAscent);
1275 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1276 kd[i].otmDescent, otm.otmDescent);
1277 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1278 kd[i].otmLineGap, otm.otmLineGap);
1279 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1280 kd[i].otmMacDescent, otm.otmMacDescent);
1281 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1282 kd[i].otmMacAscent, otm.otmMacAscent);
1284 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1285 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1286 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1287 kd[i].otmsXHeight, otm.otmsXHeight);
1288 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1289 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1290 kd[i].otmMacLineGap, otm.otmMacLineGap);
1291 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1292 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1295 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1296 trace("total_kern_pairs %u\n", total_kern_pairs);
1297 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1299 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1300 SetLastError(0xdeadbeef);
1301 ret = GetKerningPairsW(hdc, 0, kern_pair);
1302 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1303 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1304 ok(ret == 0, "got %lu, expected 0\n", ret);
1307 ret = GetKerningPairsW(hdc, 100, NULL);
1308 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1310 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1311 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1313 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1314 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1318 for (n = 0; n < ret; n++)
1322 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1323 trace("{'%c','%c',%d},\n",
1324 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1326 for (j = 0; j < kd[i].total_kern_pairs; j++)
1328 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1329 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1331 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1332 "pair %d:%d got %d, expected %d\n",
1333 kern_pair[n].wFirst, kern_pair[n].wSecond,
1334 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1340 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1341 matches, kd[i].total_kern_pairs);
1343 HeapFree(GetProcessHeap(), 0, kern_pair);
1345 SelectObject(hdc, hfont_old);
1346 DeleteObject(hfont);
1352 static void test_height_selection(void)
1354 static const struct font_data
1356 const char face_name[LF_FACESIZE];
1357 int requested_height;
1358 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1361 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1362 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1363 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1364 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1365 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1366 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1367 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1368 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1369 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1370 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1374 HFONT hfont, old_hfont;
1378 hdc = CreateCompatibleDC(0);
1381 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1383 if (!is_truetype_font_installed(fd[i].face_name))
1385 skip("%s is not installed\n", fd[i].face_name);
1389 memset(&lf, 0, sizeof(lf));
1390 lf.lfHeight = fd[i].requested_height;
1391 lf.lfWeight = fd[i].weight;
1392 strcpy(lf.lfFaceName, fd[i].face_name);
1394 hfont = CreateFontIndirect(&lf);
1397 old_hfont = SelectObject(hdc, hfont);
1398 ret = GetTextMetrics(hdc, &tm);
1399 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1400 if(fd[i].dpi == tm.tmDigitizedAspectX)
1402 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1403 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);
1404 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);
1405 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);
1406 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);
1407 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1408 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);
1410 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);
1413 SelectObject(hdc, old_hfont);
1414 DeleteObject(hfont);
1420 static void test_GetOutlineTextMetrics(void)
1422 OUTLINETEXTMETRIC *otm;
1424 HFONT hfont, hfont_old;
1426 DWORD ret, otm_size;
1429 if (!is_font_installed("Arial"))
1431 skip("Arial is not installed\n");
1437 memset(&lf, 0, sizeof(lf));
1438 strcpy(lf.lfFaceName, "Arial");
1440 lf.lfWeight = FW_NORMAL;
1441 lf.lfPitchAndFamily = DEFAULT_PITCH;
1442 lf.lfQuality = PROOF_QUALITY;
1443 hfont = CreateFontIndirect(&lf);
1446 hfont_old = SelectObject(hdc, hfont);
1447 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1448 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1450 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1452 memset(otm, 0xAA, otm_size);
1453 SetLastError(0xdeadbeef);
1454 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1455 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1456 ok(ret == 1 /* Win9x */ ||
1457 ret == otm->otmSize /* XP*/,
1458 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1459 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1461 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1462 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1463 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1464 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1467 memset(otm, 0xAA, otm_size);
1468 SetLastError(0xdeadbeef);
1469 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1470 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1471 ok(ret == 1 /* Win9x */ ||
1472 ret == otm->otmSize /* XP*/,
1473 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1474 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1476 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1477 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1478 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1479 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1482 /* ask about truncated data */
1483 memset(otm, 0xAA, otm_size);
1484 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1485 SetLastError(0xdeadbeef);
1486 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1487 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1488 ok(ret == 1 /* Win9x */ ||
1489 ret == otm->otmSize /* XP*/,
1490 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1491 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1493 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1494 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1495 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1497 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1499 HeapFree(GetProcessHeap(), 0, otm);
1501 SelectObject(hdc, hfont_old);
1502 DeleteObject(hfont);
1507 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1511 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1512 areaWidth = clientArea->right - clientArea->left,
1514 BOOL lastExtent = FALSE;
1515 PSTR pFirstChar, pLastChar;
1521 int GetTextExtentExPointWWidth;
1524 GetTextMetricsA(hdc, &tm);
1525 y = clientArea->top;
1528 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1534 /* if not at the end of the string, ... */
1535 if (*str == '\0') break;
1536 /* ... add the next word to the current extent */
1537 while (*str != '\0' && *str++ != tm.tmBreakChar);
1539 SetTextJustification(hdc, 0, 0);
1540 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1541 } while ((int) size.cx < areaWidth);
1543 /* ignore trailing break chars */
1545 while (*(pLastChar - 1) == tm.tmBreakChar)
1551 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1553 SetTextJustification(hdc, 0, 0);
1554 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1556 /* do not justify the last extent */
1557 if (*str != '\0' && breakCount > 0)
1559 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1560 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1561 justifiedWidth = size.cx;
1563 else lastExtent = TRUE;
1565 /* catch errors and report them */
1566 if (!lastExtent && (justifiedWidth != areaWidth))
1568 memset(error[nErrors].extent, 0, 100);
1569 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1570 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1576 } while (*str && y < clientArea->bottom);
1578 for (e = 0; e < nErrors; e++)
1580 /* The width returned by GetTextExtentPoint32() is exactly the same
1581 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1582 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1583 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1584 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1588 static void test_SetTextJustification(void)
1595 static char testText[] =
1596 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1597 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1598 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1599 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1600 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1601 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1602 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1604 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1605 GetClientRect( hwnd, &clientArea );
1606 hdc = GetDC( hwnd );
1608 memset(&lf, 0, sizeof lf);
1609 lf.lfCharSet = ANSI_CHARSET;
1610 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1611 lf.lfWeight = FW_DONTCARE;
1613 lf.lfQuality = DEFAULT_QUALITY;
1614 lstrcpyA(lf.lfFaceName, "Times New Roman");
1615 hfont = create_font("Times New Roman", &lf);
1616 SelectObject(hdc, hfont);
1618 testJustification(hdc, testText, &clientArea);
1620 DeleteObject(hfont);
1621 ReleaseDC(hwnd, hdc);
1622 DestroyWindow(hwnd);
1625 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1629 HFONT hfont, hfont_old;
1636 assert(count <= 128);
1638 memset(&lf, 0, sizeof(lf));
1640 lf.lfCharSet = charset;
1642 lstrcpyA(lf.lfFaceName, "Arial");
1643 SetLastError(0xdeadbeef);
1644 hfont = CreateFontIndirectA(&lf);
1645 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1648 hfont_old = SelectObject(hdc, hfont);
1650 cs = GetTextCharsetInfo(hdc, &fs, 0);
1651 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1653 SetLastError(0xdeadbeef);
1654 ret = GetTextFaceA(hdc, sizeof(name), name);
1655 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1657 if (charset == SYMBOL_CHARSET)
1659 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1660 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1664 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1665 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1668 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1670 trace("Can't find codepage for charset %d\n", cs);
1674 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1676 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1678 skip("Font code page %d, looking for code page %d\n",
1679 pGdiGetCodePage(hdc), code_page);
1687 WCHAR unicode_buf[128];
1689 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1691 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1693 SetLastError(0xdeadbeef);
1694 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1695 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1696 count, ret, GetLastError());
1702 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1704 SetLastError(0xdeadbeef);
1705 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1706 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1707 count, ret, GetLastError());
1710 SelectObject(hdc, hfont_old);
1711 DeleteObject(hfont);
1718 static void test_font_charset(void)
1720 static struct charset_data
1724 WORD font_idxA[128], font_idxW[128];
1727 { ANSI_CHARSET, 1252 },
1728 { RUSSIAN_CHARSET, 1251 },
1729 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1733 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1735 win_skip("Skipping the font charset test on a Win9x platform\n");
1739 if (!is_font_installed("Arial"))
1741 skip("Arial is not installed\n");
1745 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1747 if (cd[i].charset == SYMBOL_CHARSET)
1749 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1751 skip("Symbol or Wingdings is not installed\n");
1755 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1756 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1757 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1760 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1763 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1764 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1767 skip("Symbol or Wingdings is not installed\n");
1770 static void test_GetFontUnicodeRanges(void)
1774 HFONT hfont, hfont_old;
1778 if (!pGetFontUnicodeRanges)
1780 win_skip("GetFontUnicodeRanges not available before W2K\n");
1784 memset(&lf, 0, sizeof(lf));
1785 lstrcpyA(lf.lfFaceName, "Arial");
1786 hfont = create_font("Arial", &lf);
1789 hfont_old = SelectObject(hdc, hfont);
1791 size = pGetFontUnicodeRanges(NULL, NULL);
1792 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1794 size = pGetFontUnicodeRanges(hdc, NULL);
1795 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1797 gs = HeapAlloc(GetProcessHeap(), 0, size);
1799 size = pGetFontUnicodeRanges(hdc, gs);
1800 ok(size, "GetFontUnicodeRanges failed\n");
1802 for (i = 0; i < gs->cRanges; i++)
1803 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1805 trace("found %u ranges\n", gs->cRanges);
1807 HeapFree(GetProcessHeap(), 0, gs);
1809 SelectObject(hdc, hfont_old);
1810 DeleteObject(hfont);
1811 ReleaseDC(NULL, hdc);
1814 #define MAX_ENUM_FONTS 4096
1816 struct enum_font_data
1819 LOGFONT lf[MAX_ENUM_FONTS];
1822 struct enum_font_dataW
1825 LOGFONTW lf[MAX_ENUM_FONTS];
1828 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1830 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1832 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1834 if (type != TRUETYPE_FONTTYPE) return 1;
1836 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1837 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1839 if (efd->total < MAX_ENUM_FONTS)
1840 efd->lf[efd->total++] = *lf;
1842 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1847 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1849 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1851 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1853 if (type != TRUETYPE_FONTTYPE) return 1;
1855 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1856 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1858 if (efd->total < MAX_ENUM_FONTS)
1859 efd->lf[efd->total++] = *lf;
1861 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1866 static void get_charset_stats(struct enum_font_data *efd,
1867 int *ansi_charset, int *symbol_charset,
1868 int *russian_charset)
1873 *symbol_charset = 0;
1874 *russian_charset = 0;
1876 for (i = 0; i < efd->total; i++)
1878 switch (efd->lf[i].lfCharSet)
1883 case SYMBOL_CHARSET:
1884 (*symbol_charset)++;
1886 case RUSSIAN_CHARSET:
1887 (*russian_charset)++;
1893 static void get_charset_statsW(struct enum_font_dataW *efd,
1894 int *ansi_charset, int *symbol_charset,
1895 int *russian_charset)
1900 *symbol_charset = 0;
1901 *russian_charset = 0;
1903 for (i = 0; i < efd->total; i++)
1905 switch (efd->lf[i].lfCharSet)
1910 case SYMBOL_CHARSET:
1911 (*symbol_charset)++;
1913 case RUSSIAN_CHARSET:
1914 (*russian_charset)++;
1920 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1922 struct enum_font_data efd;
1923 struct enum_font_dataW efdw;
1926 int i, ret, ansi_charset, symbol_charset, russian_charset;
1928 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1930 if (*font_name && !is_truetype_font_installed(font_name))
1932 skip("%s is not installed\n", font_name);
1938 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1939 * while EnumFontFamiliesEx doesn't.
1941 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1944 * Use EnumFontFamiliesW since win98 crashes when the
1945 * second parameter is NULL using EnumFontFamilies
1948 SetLastError(0xdeadbeef);
1949 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1950 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1953 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1954 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1955 ansi_charset, symbol_charset, russian_charset);
1956 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1957 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1958 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1959 ok(russian_charset > 0 ||
1960 broken(russian_charset == 0), /* NT4 */
1961 "NULL family should enumerate RUSSIAN_CHARSET\n");
1965 SetLastError(0xdeadbeef);
1966 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1967 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1970 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1971 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1972 ansi_charset, symbol_charset, russian_charset);
1973 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1974 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1975 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1976 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1981 SetLastError(0xdeadbeef);
1982 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1983 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1984 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1985 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1986 ansi_charset, symbol_charset, russian_charset,
1987 *font_name ? font_name : "<empty>");
1989 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1991 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1992 for (i = 0; i < efd.total; i++)
1994 /* FIXME: remove completely once Wine is fixed */
1995 if (efd.lf[i].lfCharSet != font_charset)
1998 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2001 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2002 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2003 font_name, efd.lf[i].lfFaceName);
2006 memset(&lf, 0, sizeof(lf));
2007 lf.lfCharSet = ANSI_CHARSET;
2008 lstrcpy(lf.lfFaceName, font_name);
2010 SetLastError(0xdeadbeef);
2011 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2012 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2013 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2014 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2015 ansi_charset, symbol_charset, russian_charset,
2016 *font_name ? font_name : "<empty>");
2017 if (font_charset == SYMBOL_CHARSET)
2020 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2022 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2026 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2027 for (i = 0; i < efd.total; i++)
2029 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2031 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2032 font_name, efd.lf[i].lfFaceName);
2036 /* DEFAULT_CHARSET should enumerate all available charsets */
2037 memset(&lf, 0, sizeof(lf));
2038 lf.lfCharSet = DEFAULT_CHARSET;
2039 lstrcpy(lf.lfFaceName, font_name);
2041 SetLastError(0xdeadbeef);
2042 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2043 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2044 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2045 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2046 ansi_charset, symbol_charset, russian_charset,
2047 *font_name ? font_name : "<empty>");
2048 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2049 for (i = 0; i < efd.total; i++)
2052 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2053 font_name, efd.lf[i].lfFaceName);
2057 switch (font_charset)
2060 ok(ansi_charset > 0,
2061 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2063 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2064 ok(russian_charset > 0,
2065 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2067 case SYMBOL_CHARSET:
2069 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2071 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2072 ok(!russian_charset,
2073 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2075 case DEFAULT_CHARSET:
2076 ok(ansi_charset > 0,
2077 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2078 ok(symbol_charset > 0,
2079 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2080 ok(russian_charset > 0,
2081 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2087 ok(ansi_charset > 0,
2088 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2089 ok(symbol_charset > 0,
2090 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2091 ok(russian_charset > 0,
2092 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2095 memset(&lf, 0, sizeof(lf));
2096 lf.lfCharSet = SYMBOL_CHARSET;
2097 lstrcpy(lf.lfFaceName, font_name);
2099 SetLastError(0xdeadbeef);
2100 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2101 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2102 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2103 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2104 ansi_charset, symbol_charset, russian_charset,
2105 *font_name ? font_name : "<empty>");
2106 if (*font_name && font_charset == ANSI_CHARSET)
2107 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2110 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2111 for (i = 0; i < efd.total; i++)
2113 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2115 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2116 font_name, efd.lf[i].lfFaceName);
2120 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2121 ok(symbol_charset > 0,
2122 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2123 ok(!russian_charset,
2124 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2130 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2132 HFONT hfont, hfont_prev;
2134 GLYPHMETRICS gm1, gm2;
2137 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2139 if(!pGetGlyphIndicesA)
2142 /* negative widths are handled just as positive ones */
2143 lf2.lfWidth = -lf->lfWidth;
2145 SetLastError(0xdeadbeef);
2146 hfont = CreateFontIndirectA(lf);
2147 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2148 check_font("original", lf, hfont);
2150 hfont_prev = SelectObject(hdc, hfont);
2152 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2153 if (ret == GDI_ERROR || idx == 0xffff)
2155 SelectObject(hdc, hfont_prev);
2156 DeleteObject(hfont);
2157 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2161 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2162 memset(&gm1, 0xab, sizeof(gm1));
2163 SetLastError(0xdeadbeef);
2164 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2165 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2167 SelectObject(hdc, hfont_prev);
2168 DeleteObject(hfont);
2170 SetLastError(0xdeadbeef);
2171 hfont = CreateFontIndirectA(&lf2);
2172 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2173 check_font("negative width", &lf2, hfont);
2175 hfont_prev = SelectObject(hdc, hfont);
2177 memset(&gm2, 0xbb, sizeof(gm2));
2178 SetLastError(0xdeadbeef);
2179 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2180 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2182 SelectObject(hdc, hfont_prev);
2183 DeleteObject(hfont);
2185 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2186 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2187 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2188 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2189 gm1.gmCellIncX == gm2.gmCellIncX &&
2190 gm1.gmCellIncY == gm2.gmCellIncY,
2191 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2192 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2193 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2194 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2195 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2198 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2199 #include "pshpack2.h"
2203 SHORT xAvgCharWidth;
2204 USHORT usWeightClass;
2205 USHORT usWidthClass;
2207 SHORT ySubscriptXSize;
2208 SHORT ySubscriptYSize;
2209 SHORT ySubscriptXOffset;
2210 SHORT ySubscriptYOffset;
2211 SHORT ySuperscriptXSize;
2212 SHORT ySuperscriptYSize;
2213 SHORT ySuperscriptXOffset;
2214 SHORT ySuperscriptYOffset;
2215 SHORT yStrikeoutSize;
2216 SHORT yStrikeoutPosition;
2219 ULONG ulUnicodeRange1;
2220 ULONG ulUnicodeRange2;
2221 ULONG ulUnicodeRange3;
2222 ULONG ulUnicodeRange4;
2225 USHORT usFirstCharIndex;
2226 USHORT usLastCharIndex;
2227 /* According to the Apple spec, original version didn't have the below fields,
2228 * version numbers were taked from the OpenType spec.
2230 /* version 0 (TrueType 1.5) */
2231 USHORT sTypoAscender;
2232 USHORT sTypoDescender;
2233 USHORT sTypoLineGap;
2235 USHORT usWinDescent;
2236 /* version 1 (TrueType 1.66) */
2237 ULONG ulCodePageRange1;
2238 ULONG ulCodePageRange2;
2239 /* version 2 (OpenType 1.2) */
2242 USHORT usDefaultChar;
2244 USHORT usMaxContext;
2246 #include "poppack.h"
2248 #ifdef WORDS_BIGENDIAN
2249 #define GET_BE_WORD(x) (x)
2250 #define GET_BE_DWORD(x) (x)
2252 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2253 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2256 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2257 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2258 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2259 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2260 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2273 } cmap_encoding_record;
2281 BYTE glyph_ids[256];
2291 USHORT search_range;
2292 USHORT entry_selector;
2295 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2298 USHORT start_count[seg_countx2 / 2];
2299 USHORT id_delta[seg_countx2 / 2];
2300 USHORT id_range_offset[seg_countx2 / 2];
2310 USHORT id_range_offset;
2311 } cmap_format_4_seg;
2313 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2315 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2316 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2317 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2318 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2319 os2->panose.bWeight, os2->panose.bProportion);
2322 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2325 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2329 for(i = 0; i < 256; i++)
2331 if(cmap->glyph_ids[i] == 0) continue;
2333 if(*first == 256) *first = i;
2335 if(*first == 256) return FALSE;
2339 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2341 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2342 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2343 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2344 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2345 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2348 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2351 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2352 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2353 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2357 for(i = 0; i < seg_count; i++)
2360 cmap_format_4_seg seg;
2362 get_seg4(cmap, i, &seg);
2363 for(code = seg.start_count; code <= seg.end_count; code++)
2365 if(seg.id_range_offset == 0)
2366 index = (seg.id_delta + code) & 0xffff;
2369 index = seg.id_range_offset / 2
2370 + code - seg.start_count
2373 /* some fonts have broken last segment */
2374 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2375 index = GET_BE_WORD(glyph_ids[index]);
2378 trace("segment %04x/%04x index %04x points to nowhere\n",
2379 seg.start_count, seg.end_count, index);
2382 if(index) index += seg.id_delta;
2384 if(*first == 0x10000)
2385 *last = *first = code;
2391 if(*first == 0x10000) return FALSE;
2395 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2398 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2400 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2402 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2403 return (BYTE *)header + GET_BE_DWORD(record->offset);
2416 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2419 cmap_header *header;
2424 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2425 ok(size != GDI_ERROR, "no cmap table found\n");
2426 if(size == GDI_ERROR) return FALSE;
2428 header = HeapAlloc(GetProcessHeap(), 0, size);
2429 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2430 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2431 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2433 cmap = get_cmap(header, 3, 1);
2435 *cmap_type = cmap_ms_unicode;
2438 cmap = get_cmap(header, 3, 0);
2439 if(cmap) *cmap_type = cmap_ms_symbol;
2443 *cmap_type = cmap_none;
2447 format = GET_BE_WORD(*(WORD *)cmap);
2451 r = get_first_last_from_cmap0(cmap, first, last);
2454 r = get_first_last_from_cmap4(cmap, first, last, size);
2457 trace("unhandled cmap format %d\n", format);
2462 HeapFree(GetProcessHeap(), 0, header);
2466 static void test_text_metrics(const LOGFONTA *lf)
2469 HFONT hfont, hfont_old;
2473 const char *font_name = lf->lfFaceName;
2474 DWORD cmap_first = 0, cmap_last = 0;
2475 cmap_type cmap_type;
2476 BOOL sys_lang_non_english;
2478 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2481 SetLastError(0xdeadbeef);
2482 hfont = CreateFontIndirectA(lf);
2483 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2485 hfont_old = SelectObject(hdc, hfont);
2487 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2488 if (size == GDI_ERROR)
2490 trace("OS/2 chunk was not found\n");
2493 if (size > sizeof(tt_os2))
2495 trace("got too large OS/2 chunk of size %u\n", size);
2496 size = sizeof(tt_os2);
2499 memset(&tt_os2, 0, sizeof(tt_os2));
2500 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2501 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2503 SetLastError(0xdeadbeef);
2504 ret = GetTextMetricsA(hdc, &tmA);
2505 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2507 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2509 skip("Unable to retrieve first and last glyphs from cmap\n");
2513 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2514 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2515 UINT os2_first_char, os2_last_char, default_char, break_char;
2519 version = GET_BE_WORD(tt_os2.version);
2521 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2522 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2523 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2524 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2526 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2527 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2528 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2530 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2535 case 1257: /* Baltic */
2536 expect_last_W = 0xf8fd;
2539 expect_last_W = 0xf0ff;
2541 expect_break_W = 0x20;
2542 expect_default_W = expect_break_W - 1;
2543 expect_first_A = 0x1e;
2544 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2548 expect_first_W = cmap_first;
2549 expect_last_W = min(cmap_last, os2_last_char);
2550 if(os2_first_char <= 1)
2551 expect_break_W = os2_first_char + 2;
2552 else if(os2_first_char > 0xff)
2553 expect_break_W = 0x20;
2555 expect_break_W = os2_first_char;
2556 expect_default_W = expect_break_W - 1;
2557 expect_first_A = expect_default_W - 1;
2558 expect_last_A = min(expect_last_W, 0xff);
2560 expect_break_A = expect_break_W;
2561 expect_default_A = expect_default_W;
2563 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2564 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2565 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2566 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2567 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2569 ok(tmA.tmFirstChar == expect_first_A ||
2570 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2571 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2572 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2573 ok(tmA.tmLastChar == expect_last_A ||
2574 tmA.tmLastChar == 0xff /* win9x */,
2575 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2577 skip("tmLastChar is DBCS lead byte\n");
2578 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2579 font_name, tmA.tmBreakChar, expect_break_A);
2580 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2581 "A: tmDefaultChar for %s got %02x expected %02x\n",
2582 font_name, tmA.tmDefaultChar, expect_default_A);
2585 SetLastError(0xdeadbeef);
2586 ret = GetTextMetricsW(hdc, &tmW);
2587 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2588 "GetTextMetricsW error %u\n", GetLastError());
2591 /* Wine uses the os2 first char */
2592 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2593 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2594 font_name, tmW.tmFirstChar, expect_first_W);
2596 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2597 font_name, tmW.tmFirstChar, expect_first_W);
2599 /* Wine uses the os2 last char */
2600 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2601 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2602 font_name, tmW.tmLastChar, expect_last_W);
2604 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2605 font_name, tmW.tmLastChar, expect_last_W);
2606 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2607 font_name, tmW.tmBreakChar, expect_break_W);
2608 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2609 "W: tmDefaultChar for %s got %02x expected %02x\n",
2610 font_name, tmW.tmDefaultChar, expect_default_W);
2612 /* Test the aspect ratio while we have tmW */
2613 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2614 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2615 tmW.tmDigitizedAspectX, ret);
2616 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2617 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2618 tmW.tmDigitizedAspectX, ret);
2622 /* test FF_ values */
2623 switch(tt_os2.panose.bFamilyType)
2627 case PAN_FAMILY_TEXT_DISPLAY:
2628 case PAN_FAMILY_PICTORIAL:
2630 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2631 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2633 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2636 switch(tt_os2.panose.bSerifStyle)
2641 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2644 case PAN_SERIF_COVE:
2645 case PAN_SERIF_OBTUSE_COVE:
2646 case PAN_SERIF_SQUARE_COVE:
2647 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2648 case PAN_SERIF_SQUARE:
2649 case PAN_SERIF_THIN:
2650 case PAN_SERIF_BONE:
2651 case PAN_SERIF_EXAGGERATED:
2652 case PAN_SERIF_TRIANGLE:
2653 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2656 case PAN_SERIF_NORMAL_SANS:
2657 case PAN_SERIF_OBTUSE_SANS:
2658 case PAN_SERIF_PERP_SANS:
2659 case PAN_SERIF_FLARED:
2660 case PAN_SERIF_ROUNDED:
2661 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2666 case PAN_FAMILY_SCRIPT:
2667 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2670 case PAN_FAMILY_DECORATIVE:
2671 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2675 test_negative_width(hdc, lf);
2678 SelectObject(hdc, hfont_old);
2679 DeleteObject(hfont);
2684 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2686 INT *enumed = (INT *)lParam;
2688 if (type == TRUETYPE_FONTTYPE)
2691 test_text_metrics(lf);
2696 static void test_GetTextMetrics(void)
2702 /* Report only once */
2703 if(!pGetGlyphIndicesA)
2704 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2708 memset(&lf, 0, sizeof(lf));
2709 lf.lfCharSet = DEFAULT_CHARSET;
2711 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2712 trace("Tested metrics of %d truetype fonts\n", enumed);
2717 static void test_nonexistent_font(void)
2725 { "Times New Roman Baltic", 186 },
2726 { "Times New Roman CE", 238 },
2727 { "Times New Roman CYR", 204 },
2728 { "Times New Roman Greek", 161 },
2729 { "Times New Roman TUR", 162 }
2735 INT cs, expected_cs, i;
2736 char buf[LF_FACESIZE];
2738 if (!is_truetype_font_installed("Arial") ||
2739 !is_truetype_font_installed("Times New Roman"))
2741 skip("Arial or Times New Roman not installed\n");
2745 expected_cs = GetACP();
2746 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2748 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2751 expected_cs = csi.ciCharset;
2752 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2756 memset(&lf, 0, sizeof(lf));
2758 lf.lfWeight = FW_REGULAR;
2759 lf.lfCharSet = ANSI_CHARSET;
2760 lf.lfPitchAndFamily = FF_SWISS;
2761 strcpy(lf.lfFaceName, "Nonexistent font");
2762 hfont = CreateFontIndirectA(&lf);
2763 hfont = SelectObject(hdc, hfont);
2764 GetTextFaceA(hdc, sizeof(buf), buf);
2765 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2766 cs = GetTextCharset(hdc);
2767 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2768 DeleteObject(SelectObject(hdc, hfont));
2770 memset(&lf, 0, sizeof(lf));
2772 lf.lfWeight = FW_DONTCARE;
2773 strcpy(lf.lfFaceName, "Nonexistent font");
2774 hfont = CreateFontIndirectA(&lf);
2775 hfont = SelectObject(hdc, hfont);
2776 GetTextFaceA(hdc, sizeof(buf), buf);
2777 todo_wine /* Wine uses Arial for all substitutions */
2778 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2779 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2780 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2782 cs = GetTextCharset(hdc);
2783 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2784 DeleteObject(SelectObject(hdc, hfont));
2786 memset(&lf, 0, sizeof(lf));
2788 lf.lfWeight = FW_REGULAR;
2789 strcpy(lf.lfFaceName, "Nonexistent font");
2790 hfont = CreateFontIndirectA(&lf);
2791 hfont = SelectObject(hdc, hfont);
2792 GetTextFaceA(hdc, sizeof(buf), buf);
2793 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2794 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2795 cs = GetTextCharset(hdc);
2796 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2797 DeleteObject(SelectObject(hdc, hfont));
2799 memset(&lf, 0, sizeof(lf));
2801 lf.lfWeight = FW_DONTCARE;
2802 strcpy(lf.lfFaceName, "Times New Roman");
2803 hfont = CreateFontIndirectA(&lf);
2804 hfont = SelectObject(hdc, hfont);
2805 GetTextFaceA(hdc, sizeof(buf), buf);
2806 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2807 cs = GetTextCharset(hdc);
2808 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2809 DeleteObject(SelectObject(hdc, hfont));
2811 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2813 memset(&lf, 0, sizeof(lf));
2815 lf.lfWeight = FW_REGULAR;
2816 strcpy(lf.lfFaceName, font_subst[i].name);
2817 hfont = CreateFontIndirectA(&lf);
2818 hfont = SelectObject(hdc, hfont);
2819 cs = GetTextCharset(hdc);
2820 if (font_subst[i].charset == expected_cs)
2822 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2823 GetTextFaceA(hdc, sizeof(buf), buf);
2824 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2828 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2829 GetTextFaceA(hdc, sizeof(buf), buf);
2830 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2831 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2833 DeleteObject(SelectObject(hdc, hfont));
2835 memset(&lf, 0, sizeof(lf));
2837 lf.lfWeight = FW_DONTCARE;
2838 strcpy(lf.lfFaceName, font_subst[i].name);
2839 hfont = CreateFontIndirectA(&lf);
2840 hfont = SelectObject(hdc, hfont);
2841 GetTextFaceA(hdc, sizeof(buf), buf);
2842 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2843 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2844 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2845 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2846 "got %s for font %s\n", buf, font_subst[i].name);
2847 cs = GetTextCharset(hdc);
2848 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2849 DeleteObject(SelectObject(hdc, hfont));
2855 static void test_GdiRealizationInfo(void)
2860 HFONT hfont, hfont_old;
2863 if(!pGdiRealizationInfo)
2865 win_skip("GdiRealizationInfo not available\n");
2871 memset(info, 0xcc, sizeof(info));
2872 r = pGdiRealizationInfo(hdc, info);
2873 ok(r != 0, "ret 0\n");
2874 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2875 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2877 if (!is_truetype_font_installed("Arial"))
2879 skip("skipping GdiRealizationInfo with truetype font\n");
2883 memset(&lf, 0, sizeof(lf));
2884 strcpy(lf.lfFaceName, "Arial");
2886 lf.lfWeight = FW_NORMAL;
2887 hfont = CreateFontIndirectA(&lf);
2888 hfont_old = SelectObject(hdc, hfont);
2890 memset(info, 0xcc, sizeof(info));
2891 r = pGdiRealizationInfo(hdc, info);
2892 ok(r != 0, "ret 0\n");
2893 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2894 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2896 DeleteObject(SelectObject(hdc, hfont_old));
2902 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2903 the nul in the count of characters copied when the face name buffer is not
2904 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2905 always includes it. */
2906 static void test_GetTextFace(void)
2908 static const char faceA[] = "Tahoma";
2909 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2912 char bufA[LF_FACESIZE];
2913 WCHAR bufW[LF_FACESIZE];
2918 if(!is_font_installed("Tahoma"))
2920 skip("Tahoma is not installed so skipping this test\n");
2925 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2926 f = CreateFontIndirectA(&fA);
2927 ok(f != NULL, "CreateFontIndirectA failed\n");
2930 g = SelectObject(dc, f);
2931 n = GetTextFaceA(dc, sizeof bufA, bufA);
2932 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2933 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2935 /* Play with the count arg. */
2937 n = GetTextFaceA(dc, 0, bufA);
2938 ok(n == 0, "GetTextFaceA returned %d\n", n);
2939 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2942 n = GetTextFaceA(dc, 1, bufA);
2943 ok(n == 0, "GetTextFaceA returned %d\n", n);
2944 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2946 bufA[0] = 'x'; bufA[1] = 'y';
2947 n = GetTextFaceA(dc, 2, bufA);
2948 ok(n == 1, "GetTextFaceA returned %d\n", n);
2949 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2951 n = GetTextFaceA(dc, 0, NULL);
2952 ok(n == sizeof faceA ||
2953 broken(n == 0), /* win98, winMe */
2954 "GetTextFaceA returned %d\n", n);
2956 DeleteObject(SelectObject(dc, g));
2957 ReleaseDC(NULL, dc);
2960 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2961 SetLastError(0xdeadbeef);
2962 f = CreateFontIndirectW(&fW);
2963 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2965 win_skip("CreateFontIndirectW is not implemented\n");
2968 ok(f != NULL, "CreateFontIndirectW failed\n");
2971 g = SelectObject(dc, f);
2972 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2973 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2974 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2976 /* Play with the count arg. */
2978 n = GetTextFaceW(dc, 0, bufW);
2979 ok(n == 0, "GetTextFaceW returned %d\n", n);
2980 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2983 n = GetTextFaceW(dc, 1, bufW);
2984 ok(n == 1, "GetTextFaceW returned %d\n", n);
2985 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2987 bufW[0] = 'x'; bufW[1] = 'y';
2988 n = GetTextFaceW(dc, 2, bufW);
2989 ok(n == 2, "GetTextFaceW returned %d\n", n);
2990 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2992 n = GetTextFaceW(dc, 0, NULL);
2993 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2995 DeleteObject(SelectObject(dc, g));
2996 ReleaseDC(NULL, dc);
2999 static void test_orientation(void)
3001 static const char test_str[11] = "Test String";
3004 HFONT hfont, old_hfont;
3007 if (!is_truetype_font_installed("Arial"))
3009 skip("Arial is not installed\n");
3013 hdc = CreateCompatibleDC(0);
3014 memset(&lf, 0, sizeof(lf));
3015 lstrcpyA(lf.lfFaceName, "Arial");
3017 lf.lfOrientation = lf.lfEscapement = 900;
3018 hfont = create_font("orientation", &lf);
3019 old_hfont = SelectObject(hdc, hfont);
3020 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3021 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3022 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3023 SelectObject(hdc, old_hfont);
3024 DeleteObject(hfont);
3028 static void test_oemcharset(void)
3032 HFONT hfont, old_hfont;
3035 hdc = CreateCompatibleDC(0);
3036 ZeroMemory(&lf, sizeof(lf));
3038 lf.lfCharSet = OEM_CHARSET;
3039 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3040 lstrcpyA(lf.lfFaceName, "Terminal");
3041 hfont = CreateFontIndirectA(&lf);
3042 old_hfont = SelectObject(hdc, hfont);
3043 charset = GetTextCharset(hdc);
3045 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3046 hfont = SelectObject(hdc, old_hfont);
3047 GetObjectA(hfont, sizeof(clf), &clf);
3048 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3049 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3050 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3051 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3052 DeleteObject(hfont);
3056 static void test_GetGlyphOutline(void)
3058 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
3062 HFONT hfont, old_hfont;
3065 if (!is_truetype_font_installed("Tahoma"))
3067 skip("Tahoma is not installed\n");
3071 hdc = CreateCompatibleDC(0);
3072 memset(&lf, 0, sizeof(lf));
3074 lstrcpyA(lf.lfFaceName, "Tahoma");
3075 SetLastError(0xdeadbeef);
3076 hfont = CreateFontIndirectA(&lf);
3077 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3078 old_hfont = SelectObject(hdc, hfont);
3080 memset(&gm, 0, sizeof(gm));
3081 SetLastError(0xdeadbeef);
3082 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3083 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3085 memset(&gm, 0, sizeof(gm));
3086 SetLastError(0xdeadbeef);
3087 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3088 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3089 ok(GetLastError() == 0xdeadbeef ||
3090 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3091 "expected 0xdeadbeef, got %u\n", GetLastError());
3093 memset(&gm, 0, sizeof(gm));
3094 SetLastError(0xdeadbeef);
3095 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3096 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3097 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3099 memset(&gm, 0, sizeof(gm));
3100 SetLastError(0xdeadbeef);
3101 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3102 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3104 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3105 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3108 /* test for needed buffer size request on space char */
3109 memset(&gm, 0, sizeof(gm));
3110 SetLastError(0xdeadbeef);
3111 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3112 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3113 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3115 /* requesting buffer size for space char + error */
3116 memset(&gm, 0, sizeof(gm));
3117 SetLastError(0xdeadbeef);
3118 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3119 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3121 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3122 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3125 SelectObject(hdc, old_hfont);
3126 DeleteObject(hfont);
3130 /* bug #9995: there is a limit to the character width that can be specified */
3131 static void test_GetTextMetrics2(const char *fontname, int font_height)
3137 int ave_width, height, width, ratio, scale;
3139 if (!is_truetype_font_installed( fontname)) {
3140 skip("%s is not installed\n", fontname);
3143 hdc = CreateCompatibleDC(0);
3144 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3145 /* select width = 0 */
3146 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3147 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3148 DEFAULT_QUALITY, VARIABLE_PITCH,
3150 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3151 of = SelectObject( hdc, hf);
3152 ret = GetTextMetricsA( hdc, &tm);
3153 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3154 height = tm.tmHeight;
3155 ave_width = tm.tmAveCharWidth;
3156 SelectObject( hdc, of);
3159 trace("height %d, ave width %d\n", height, ave_width);
3161 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3163 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3164 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3165 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3166 ok(hf != 0, "CreateFont failed\n");
3167 of = SelectObject(hdc, hf);
3168 ret = GetTextMetrics(hdc, &tm);
3169 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3170 SelectObject(hdc, of);
3173 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3179 ratio = width / height;
3180 scale = width / ave_width;
3182 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3183 width, height, ratio, width, ave_width, scale);
3185 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3188 static void test_CreateFontIndirect(void)
3190 LOGFONTA lf, getobj_lf;
3193 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3195 memset(&lf, 0, sizeof(lf));
3196 lf.lfCharSet = ANSI_CHARSET;
3197 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3200 lf.lfQuality = DEFAULT_QUALITY;
3201 lf.lfItalic = FALSE;
3202 lf.lfWeight = FW_DONTCARE;
3204 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3206 lstrcpyA(lf.lfFaceName, TestName[i]);
3207 hfont = CreateFontIndirectA(&lf);
3208 ok(hfont != 0, "CreateFontIndirectA failed\n");
3209 SetLastError(0xdeadbeef);
3210 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3211 ok(ret, "GetObject failed: %d\n", GetLastError());
3212 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3213 ok(lf.lfWeight == getobj_lf.lfWeight ||
3214 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3215 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3216 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3217 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3218 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3219 DeleteObject(hfont);
3223 static void test_CreateFontIndirectEx(void)
3225 ENUMLOGFONTEXDVA lfex;
3228 if (!pCreateFontIndirectExA)
3230 win_skip("CreateFontIndirectExA is not available\n");
3234 if (!is_truetype_font_installed("Arial"))
3236 skip("Arial is not installed\n");
3240 SetLastError(0xdeadbeef);
3241 hfont = pCreateFontIndirectExA(NULL);
3242 ok(hfont == NULL, "got %p\n", hfont);
3243 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3245 memset(&lfex, 0, sizeof(lfex));
3246 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3247 hfont = pCreateFontIndirectExA(&lfex);
3248 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3250 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3251 DeleteObject(hfont);
3254 static void free_font(void *font)
3256 UnmapViewOfFile(font);
3259 static void *load_font(const char *font_name, DWORD *font_size)
3261 char file_name[MAX_PATH];
3262 HANDLE file, mapping;
3265 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3266 strcat(file_name, "\\fonts\\");
3267 strcat(file_name, font_name);
3269 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3270 if (file == INVALID_HANDLE_VALUE) return NULL;
3272 *font_size = GetFileSize(file, NULL);
3274 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3281 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3284 CloseHandle(mapping);
3288 static void test_AddFontMemResource(void)
3291 DWORD font_size, num_fonts;
3295 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3297 win_skip("AddFontMemResourceEx is not available on this platform\n");
3301 font = load_font("sserife.fon", &font_size);
3304 skip("Unable to locate and load font sserife.fon\n");
3308 SetLastError(0xdeadbeef);
3309 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3310 ok(!ret, "AddFontMemResourceEx should fail\n");
3311 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3312 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3315 SetLastError(0xdeadbeef);
3316 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3317 ok(!ret, "AddFontMemResourceEx should fail\n");
3318 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3319 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3322 SetLastError(0xdeadbeef);
3323 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3324 ok(!ret, "AddFontMemResourceEx should fail\n");
3325 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3326 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3329 SetLastError(0xdeadbeef);
3330 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3331 ok(!ret, "AddFontMemResourceEx should fail\n");
3332 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3333 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3336 SetLastError(0xdeadbeef);
3337 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3338 ok(!ret, "AddFontMemResourceEx should fail\n");
3339 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3340 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3343 SetLastError(0xdeadbeef);
3344 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3345 ok(!ret, "AddFontMemResourceEx should fail\n");
3346 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3347 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3350 num_fonts = 0xdeadbeef;
3351 SetLastError(0xdeadbeef);
3352 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3353 ok(!ret, "AddFontMemResourceEx should fail\n");
3354 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3355 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3357 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3359 if (0) /* hangs under windows 2000 */
3361 num_fonts = 0xdeadbeef;
3362 SetLastError(0xdeadbeef);
3363 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3364 ok(!ret, "AddFontMemResourceEx should fail\n");
3365 ok(GetLastError() == 0xdeadbeef,
3366 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3368 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3371 num_fonts = 0xdeadbeef;
3372 SetLastError(0xdeadbeef);
3373 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3374 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3375 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3376 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3380 SetLastError(0xdeadbeef);
3381 bRet = pRemoveFontMemResourceEx(ret);
3382 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3384 /* test invalid pointer to number of loaded fonts */
3385 font = load_font("sserife.fon", &font_size);
3386 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3388 SetLastError(0xdeadbeef);
3389 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3390 ok(!ret, "AddFontMemResourceEx should fail\n");
3391 ok(GetLastError() == 0xdeadbeef,
3392 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3395 SetLastError(0xdeadbeef);
3396 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3397 ok(!ret, "AddFontMemResourceEx should fail\n");
3398 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3399 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3411 test_outline_font();
3412 test_bitmap_font_metrics();
3413 test_GdiGetCharDimensions();
3414 test_GetCharABCWidths();
3415 test_text_extents();
3416 test_GetGlyphIndices();
3417 test_GetKerningPairs();
3418 test_GetOutlineTextMetrics();
3419 test_SetTextJustification();
3420 test_font_charset();
3421 test_GetFontUnicodeRanges();
3422 test_nonexistent_font();
3424 test_height_selection();
3425 test_AddFontMemResource();
3427 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3428 * I'd like to avoid them in this test.
3430 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3431 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3432 if (is_truetype_font_installed("Arial Black") &&
3433 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3435 test_EnumFontFamilies("", ANSI_CHARSET);
3436 test_EnumFontFamilies("", SYMBOL_CHARSET);
3437 test_EnumFontFamilies("", DEFAULT_CHARSET);
3440 skip("Arial Black or Symbol/Wingdings is not installed\n");
3441 test_GetTextMetrics();
3442 test_GdiRealizationInfo();
3444 test_GetGlyphOutline();
3445 test_GetTextMetrics2("Tahoma", -11);
3446 test_GetTextMetrics2("Tahoma", -55);
3447 test_GetTextMetrics2("Tahoma", -110);
3448 test_GetTextMetrics2("Arial", -11);
3449 test_GetTextMetrics2("Arial", -55);
3450 test_GetTextMetrics2("Arial", -110);
3451 test_CreateFontIndirect();
3452 test_CreateFontIndirectEx();