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 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
41 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
42 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
43 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
44 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
45 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
46 HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
47 HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
48 BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
50 static HMODULE hgdi32 = 0;
52 static void init(void)
54 hgdi32 = GetModuleHandleA("gdi32.dll");
56 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
57 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
58 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
59 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
60 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
61 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
62 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
63 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
64 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
65 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
68 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
70 if (type != TRUETYPE_FONTTYPE) return 1;
75 static BOOL is_truetype_font_installed(const char *name)
80 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
87 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
92 static BOOL is_font_installed(const char *name)
97 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
104 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
112 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
113 /* NT4 tries to be clever and only returns the minimum length */
114 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
116 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
117 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
118 ok(lf->lfHeight == getobj_lf.lfHeight ||
119 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
120 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
121 ok(lf->lfWidth == getobj_lf.lfWidth ||
122 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
123 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
124 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
125 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
126 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
127 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
128 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
129 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
130 ok(lf->lfWeight == getobj_lf.lfWeight ||
131 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
132 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
133 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
134 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
135 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
136 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
137 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
138 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
139 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
140 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
141 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
142 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
143 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
146 static HFONT create_font(const char* test, const LOGFONTA* lf)
148 HFONT hfont = CreateFontIndirectA(lf);
149 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
151 check_font(test, lf, hfont);
155 static void test_logfont(void)
160 memset(&lf, 0, sizeof lf);
162 lf.lfCharSet = ANSI_CHARSET;
163 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
164 lf.lfWeight = FW_DONTCARE;
167 lf.lfQuality = DEFAULT_QUALITY;
169 lstrcpyA(lf.lfFaceName, "Arial");
170 hfont = create_font("Arial", &lf);
173 memset(&lf, 'A', sizeof(lf));
174 hfont = CreateFontIndirectA(&lf);
175 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
177 lf.lfFaceName[LF_FACESIZE - 1] = 0;
178 check_font("AAA...", &lf, hfont);
182 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
184 if (type & RASTER_FONTTYPE)
186 LOGFONT *lf = (LOGFONT *)lParam;
188 return 0; /* stop enumeration */
191 return 1; /* continue enumeration */
194 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
196 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
197 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
198 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
199 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
200 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
201 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
202 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
203 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
204 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
205 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
206 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
207 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
208 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
209 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
210 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
211 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
212 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
213 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
214 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
215 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
218 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
219 LONG lfWidth, const char *test_str,
220 INT test_str_len, const TEXTMETRICA *tm_orig,
221 const SIZE *size_orig, INT width_of_A_orig,
222 INT scale_x, INT scale_y)
225 OUTLINETEXTMETRIC otm;
228 INT width_of_A, cx, cy;
234 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
236 GetObjectA(hfont, sizeof(lf), &lf);
238 if (GetOutlineTextMetricsA(hdc, 0, NULL))
240 otm.otmSize = sizeof(otm) / 2;
241 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
242 ok(ret == sizeof(otm)/2 /* XP */ ||
243 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
245 memset(&otm, 0x1, sizeof(otm));
246 otm.otmSize = sizeof(otm);
247 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
248 ok(ret == sizeof(otm) /* XP */ ||
249 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
251 memset(&tm, 0x2, sizeof(tm));
252 ret = GetTextMetricsA(hdc, &tm);
253 ok(ret, "GetTextMetricsA failed\n");
254 /* the structure size is aligned */
255 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
257 ok(0, "tm != otm\n");
258 compare_tm(&tm, &otm.otmTextMetrics);
261 tm = otm.otmTextMetrics;
262 if (0) /* these metrics are scaled too, but with rounding errors */
264 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
265 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
267 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
268 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
269 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
270 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
271 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
272 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
276 ret = GetTextMetricsA(hdc, &tm);
277 ok(ret, "GetTextMetricsA failed\n");
280 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
281 cy = tm.tmHeight / tm_orig->tmHeight;
282 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
283 lfHeight, scale_x, scale_y, cx, cy);
284 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
285 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
286 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
287 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
288 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
290 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
294 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
297 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
299 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
301 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
302 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
304 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
306 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
309 /* Test how GDI scales bitmap font metrics */
310 static void test_bitmap_font(void)
312 static const char test_str[11] = "Test String";
315 HFONT hfont, old_hfont;
318 INT ret, i, width_orig, height_orig, scale, lfWidth;
322 /* "System" has only 1 pixel size defined, otherwise the test breaks */
323 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
327 trace("no bitmap fonts were found, skipping the test\n");
331 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
333 height_orig = bitmap_lf.lfHeight;
334 lfWidth = bitmap_lf.lfWidth;
336 hfont = create_font("bitmap", &bitmap_lf);
337 old_hfont = SelectObject(hdc, hfont);
338 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
339 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
340 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
341 SelectObject(hdc, old_hfont);
344 bitmap_lf.lfHeight = 0;
345 bitmap_lf.lfWidth = 4;
346 hfont = create_font("bitmap", &bitmap_lf);
347 old_hfont = SelectObject(hdc, hfont);
348 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
349 SelectObject(hdc, old_hfont);
352 bitmap_lf.lfHeight = height_orig;
353 bitmap_lf.lfWidth = lfWidth;
355 /* test fractional scaling */
356 for (i = 1; i <= height_orig * 6; i++)
360 bitmap_lf.lfHeight = i;
361 hfont = create_font("fractional", &bitmap_lf);
362 scale = (i + height_orig - 1) / height_orig;
363 nearest_height = scale * height_orig;
364 /* Only jump to the next height if the difference <= 25% original height */
365 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
366 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
367 so we'll not test this particular height. */
368 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
369 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
370 old_hfont = SelectObject(hdc, hfont);
371 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
372 SelectObject(hdc, old_hfont);
376 /* test integer scaling 3x2 */
377 bitmap_lf.lfHeight = height_orig * 2;
378 bitmap_lf.lfWidth *= 3;
379 hfont = create_font("3x2", &bitmap_lf);
380 old_hfont = SelectObject(hdc, hfont);
381 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
382 SelectObject(hdc, old_hfont);
385 /* test integer scaling 3x3 */
386 bitmap_lf.lfHeight = height_orig * 3;
387 bitmap_lf.lfWidth = 0;
388 hfont = create_font("3x3", &bitmap_lf);
389 old_hfont = SelectObject(hdc, hfont);
390 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
391 SelectObject(hdc, old_hfont);
397 /* Test how GDI scales outline font metrics */
398 static void test_outline_font(void)
400 static const char test_str[11] = "Test String";
403 HFONT hfont, old_hfont, old_hfont_2;
404 OUTLINETEXTMETRICA otm;
406 INT width_orig, height_orig, lfWidth;
409 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
410 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
414 if (!is_truetype_font_installed("Arial"))
416 skip("Arial is not installed\n");
420 hdc = CreateCompatibleDC(0);
422 memset(&lf, 0, sizeof(lf));
423 strcpy(lf.lfFaceName, "Arial");
425 hfont = create_font("outline", &lf);
426 old_hfont = SelectObject(hdc, hfont);
427 otm.otmSize = sizeof(otm);
428 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
429 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
430 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
432 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
433 SelectObject(hdc, old_hfont);
436 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
437 lf.lfHeight = otm.otmEMSquare;
438 lf.lfHeight = -lf.lfHeight;
439 hfont = create_font("outline", &lf);
440 old_hfont = SelectObject(hdc, hfont);
441 otm.otmSize = sizeof(otm);
442 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
443 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
444 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
445 SelectObject(hdc, old_hfont);
448 height_orig = otm.otmTextMetrics.tmHeight;
449 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
451 /* test integer scaling 3x2 */
452 lf.lfHeight = height_orig * 2;
453 lf.lfWidth = lfWidth * 3;
454 hfont = create_font("3x2", &lf);
455 old_hfont = SelectObject(hdc, hfont);
456 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
457 SelectObject(hdc, old_hfont);
460 /* test integer scaling 3x3 */
461 lf.lfHeight = height_orig * 3;
462 lf.lfWidth = lfWidth * 3;
463 hfont = create_font("3x3", &lf);
464 old_hfont = SelectObject(hdc, hfont);
465 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
466 SelectObject(hdc, old_hfont);
469 /* test integer scaling 1x1 */
470 lf.lfHeight = height_orig * 1;
471 lf.lfWidth = lfWidth * 1;
472 hfont = create_font("1x1", &lf);
473 old_hfont = SelectObject(hdc, hfont);
474 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
475 SelectObject(hdc, old_hfont);
478 /* test integer scaling 1x1 */
479 lf.lfHeight = height_orig;
481 hfont = create_font("1x1", &lf);
482 old_hfont = SelectObject(hdc, hfont);
483 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 /* with an identity matrix */
486 memset(&gm, 0, sizeof(gm));
487 SetLastError(0xdeadbeef);
488 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
489 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
490 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
491 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
492 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
493 /* with a custom matrix */
494 memset(&gm, 0, sizeof(gm));
495 SetLastError(0xdeadbeef);
496 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
497 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
498 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
499 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
500 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
502 /* Test that changing the DC transformation affects only the font
503 * selected on this DC and doesn't affect the same font selected on
506 hdc_2 = CreateCompatibleDC(0);
507 old_hfont_2 = SelectObject(hdc_2, hfont);
508 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
510 SetMapMode(hdc, MM_ANISOTROPIC);
512 /* font metrics on another DC should be unchanged */
513 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
515 /* test restrictions of compatibility mode GM_COMPATIBLE */
516 /* part 1: rescaling only X should not change font scaling on screen.
517 So compressing the X axis by 2 is not done, and this
518 appears as X scaling of 2 that no one requested. */
519 SetWindowExtEx(hdc, 100, 100, NULL);
520 SetViewportExtEx(hdc, 50, 100, NULL);
521 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* part 2: rescaling only Y should change font scaling.
526 As also X is scaled by a factor of 2, but this is not
527 requested by the DC transformation, we get a scaling factor
528 of 2 in the X coordinate. */
529 SetViewportExtEx(hdc, 100, 200, NULL);
530 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
531 /* font metrics on another DC should be unchanged */
532 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
534 /* restore scaling */
535 SetMapMode(hdc, MM_TEXT);
537 /* font metrics on another DC should be unchanged */
538 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
540 SelectObject(hdc_2, old_hfont_2);
543 if (!SetGraphicsMode(hdc, GM_ADVANCED))
545 SelectObject(hdc, old_hfont);
548 skip("GM_ADVANCED is not supported on this platform\n");
559 SetLastError(0xdeadbeef);
560 ret = SetWorldTransform(hdc, &xform);
561 ok(ret, "SetWorldTransform error %u\n", GetLastError());
563 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
565 /* with an identity matrix */
566 memset(&gm, 0, sizeof(gm));
567 SetLastError(0xdeadbeef);
568 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
569 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
570 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
571 pt.x = width_orig; pt.y = 0;
573 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
574 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
575 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
576 /* with a custom matrix */
577 memset(&gm, 0, sizeof(gm));
578 SetLastError(0xdeadbeef);
579 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
580 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
581 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
582 pt.x = width_orig; pt.y = 0;
584 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
585 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
586 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
588 SetLastError(0xdeadbeef);
589 ret = SetMapMode(hdc, MM_LOMETRIC);
590 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
592 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
594 /* with an identity matrix */
595 memset(&gm, 0, sizeof(gm));
596 SetLastError(0xdeadbeef);
597 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
598 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
599 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
600 pt.x = width_orig; pt.y = 0;
602 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
603 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
604 /* with a custom matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
612 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
615 SetLastError(0xdeadbeef);
616 ret = SetMapMode(hdc, MM_TEXT);
617 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
619 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 /* with an identity matrix */
622 memset(&gm, 0, sizeof(gm));
623 SetLastError(0xdeadbeef);
624 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
625 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
626 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
627 pt.x = width_orig; pt.y = 0;
629 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
630 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
631 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
632 /* with a custom matrix */
633 memset(&gm, 0, sizeof(gm));
634 SetLastError(0xdeadbeef);
635 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
636 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
637 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
638 pt.x = width_orig; pt.y = 0;
640 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
641 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
642 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
644 SelectObject(hdc, old_hfont);
649 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
651 LOGFONT *lf = (LOGFONT *)lParam;
653 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
656 return 0; /* stop enumeration */
658 return 1; /* continue enumeration */
661 static void test_bitmap_font_metrics(void)
663 static const struct font_data
665 const char face_name[LF_FACESIZE];
666 int weight, height, ascent, descent, int_leading, ext_leading;
667 int ave_char_width, max_char_width, dpi;
671 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
672 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
673 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
674 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
675 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
676 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
677 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
679 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
680 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
681 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
684 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
685 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
687 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
688 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
689 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
690 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
693 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
694 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
695 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
696 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
697 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
698 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
699 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
700 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
701 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
702 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
703 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
705 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
706 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
707 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
710 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
711 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
712 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
713 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
714 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
716 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
717 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
719 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
722 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
723 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
724 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
726 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
727 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
728 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
730 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
731 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
733 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
734 * require a new system.sfd for that font
736 { "System", FW_BOLD, 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++)
806 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
807 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
809 lf.lfCharSet = csi.ciCharset;
810 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
813 hfont = create_font(lf.lfFaceName, &lf);
814 old_hfont = SelectObject(hdc, hfont);
815 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
816 if(fd[i].dpi == tm.tmDigitizedAspectX)
818 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
819 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);
820 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);
821 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);
822 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);
823 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);
824 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);
825 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);
827 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
828 that make the max width bigger */
829 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
830 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);
832 SelectObject(hdc, old_hfont);
840 static void test_GdiGetCharDimensions(void)
846 LONG avgwidth, height;
847 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
849 if (!pGdiGetCharDimensions)
851 win_skip("GdiGetCharDimensions not available on this platform\n");
855 hdc = CreateCompatibleDC(NULL);
857 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
858 avgwidth = ((size.cx / 26) + 1) / 2;
860 ret = pGdiGetCharDimensions(hdc, &tm, &height);
861 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
862 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
864 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
865 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
867 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
868 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
871 ret = pGdiGetCharDimensions(hdc, NULL, &height);
872 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
873 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
878 static void test_GetCharABCWidths(void)
880 static const WCHAR str[] = {'a',0};
889 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
891 win_skip("GetCharABCWidthsW/I not available on this platform\n");
895 memset(&lf, 0, sizeof(lf));
896 strcpy(lf.lfFaceName, "System");
899 hfont = CreateFontIndirectA(&lf);
901 hfont = SelectObject(hdc, hfont);
903 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
904 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
906 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
907 ok(!ret, "GetCharABCWidthsI should have failed\n");
909 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
910 ok(!ret, "GetCharABCWidthsI should have failed\n");
912 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
913 ok(ret, "GetCharABCWidthsI should have succeeded\n");
915 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
916 ok(!ret, "GetCharABCWidthsW should have failed\n");
918 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
919 ok(!ret, "GetCharABCWidthsW should have failed\n");
921 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
922 ok(!ret, "GetCharABCWidthsW should have failed\n");
924 hfont = SelectObject(hdc, hfont);
926 ReleaseDC(NULL, hdc);
929 static void test_text_extents(void)
931 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
933 INT i, len, fit1, fit2;
941 memset(&lf, 0, sizeof(lf));
942 strcpy(lf.lfFaceName, "Arial");
945 hfont = CreateFontIndirectA(&lf);
947 hfont = SelectObject(hdc, hfont);
948 GetTextMetricsA(hdc, &tm);
949 GetTextExtentPointA(hdc, "o", 1, &sz);
950 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
952 SetLastError(0xdeadbeef);
953 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
954 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
956 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
957 hfont = SelectObject(hdc, hfont);
964 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
965 extents[0] = 1; /* So that the increasing sequence test will fail
966 if the extents array is untouched. */
967 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
968 GetTextExtentPointW(hdc, wt, len, &sz2);
970 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
971 /* Because of the '\n' in the string GetTextExtentExPoint and
972 GetTextExtentPoint return different widths under Win2k, but
973 under WinXP they return the same width. So we don't test that
976 for (i = 1; i < len; ++i)
977 ok(extents[i-1] <= extents[i],
978 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
980 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
981 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
982 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
983 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
984 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
985 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
986 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
987 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
988 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
989 ok(extents[0] == extents[2] && extents[1] == extents[3],
990 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
991 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
992 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
993 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
994 HeapFree(GetProcessHeap(), 0, extents);
996 hfont = SelectObject(hdc, hfont);
998 ReleaseDC(NULL, hdc);
1001 static void test_GetGlyphIndices(void)
1008 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1009 WORD glyphs[(sizeof(testtext)/2)-1];
1013 if (!pGetGlyphIndicesW) {
1014 win_skip("GetGlyphIndicesW not available on platform\n");
1020 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1021 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1022 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1023 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1024 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1026 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1027 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1028 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1029 textm.tmDefaultChar, glyphs[4]);
1031 if(!is_font_installed("Tahoma"))
1033 skip("Tahoma is not installed so skipping this test\n");
1036 memset(&lf, 0, sizeof(lf));
1037 strcpy(lf.lfFaceName, "Tahoma");
1040 hfont = CreateFontIndirectA(&lf);
1041 hOldFont = SelectObject(hdc, hfont);
1042 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1043 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1044 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1045 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1046 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1048 testtext[0] = textm.tmDefaultChar;
1049 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1050 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1051 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1052 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1053 DeleteObject(SelectObject(hdc, hOldFont));
1056 static void test_GetKerningPairs(void)
1058 static const struct kerning_data
1060 const char face_name[LF_FACESIZE];
1062 /* some interesting fields from OUTLINETEXTMETRIC */
1063 LONG tmHeight, tmAscent, tmDescent;
1068 UINT otmsCapEmHeight;
1073 UINT otmusMinimumPPEM;
1074 /* small subset of kerning pairs to test */
1075 DWORD total_kern_pairs;
1076 const KERNINGPAIR kern_pair[26];
1079 {"Arial", 12, 12, 9, 3,
1080 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1083 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1084 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1085 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1086 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1087 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1088 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1089 {933,970,+1},{933,972,-1}
1092 {"Arial", -34, 39, 32, 7,
1093 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1096 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1097 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1098 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1099 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1100 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1101 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1102 {933,970,+2},{933,972,-3}
1105 { "Arial", 120, 120, 97, 23,
1106 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1109 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1110 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1111 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1112 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1113 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1114 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1115 {933,970,+6},{933,972,-10}
1118 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1119 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1120 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1123 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1124 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1125 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1126 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1127 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1128 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1129 {933,970,+54},{933,972,-83}
1135 HFONT hfont, hfont_old;
1136 KERNINGPAIR *kern_pair;
1138 DWORD total_kern_pairs, ret, i, n, matches;
1142 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1143 * which may render this test unusable, so we're trying to avoid that.
1145 SetLastError(0xdeadbeef);
1146 GetKerningPairsW(hdc, 0, NULL);
1147 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1149 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1154 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1156 OUTLINETEXTMETRICW otm;
1158 if (!is_font_installed(kd[i].face_name))
1160 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1164 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1166 memset(&lf, 0, sizeof(lf));
1167 strcpy(lf.lfFaceName, kd[i].face_name);
1168 lf.lfHeight = kd[i].height;
1169 hfont = CreateFontIndirect(&lf);
1172 hfont_old = SelectObject(hdc, hfont);
1174 SetLastError(0xdeadbeef);
1175 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1176 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1178 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1179 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1180 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1181 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1182 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1183 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1185 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1186 kd[i].otmEMSquare, otm.otmEMSquare);
1187 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1188 kd[i].otmAscent, otm.otmAscent);
1189 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1190 kd[i].otmDescent, otm.otmDescent);
1191 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1192 kd[i].otmLineGap, otm.otmLineGap);
1193 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1194 kd[i].otmMacDescent, otm.otmMacDescent);
1195 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1196 kd[i].otmMacAscent, otm.otmMacAscent);
1198 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1199 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1200 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1201 kd[i].otmsXHeight, otm.otmsXHeight);
1202 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1203 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1204 kd[i].otmMacLineGap, otm.otmMacLineGap);
1205 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1206 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1209 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1210 trace("total_kern_pairs %u\n", total_kern_pairs);
1211 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1213 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1214 SetLastError(0xdeadbeef);
1215 ret = GetKerningPairsW(hdc, 0, kern_pair);
1216 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1217 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1218 ok(ret == 0, "got %lu, expected 0\n", ret);
1221 ret = GetKerningPairsW(hdc, 100, NULL);
1222 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1224 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1225 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1227 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1228 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1232 for (n = 0; n < ret; n++)
1236 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1237 trace("{'%c','%c',%d},\n",
1238 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1240 for (j = 0; j < kd[i].total_kern_pairs; j++)
1242 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1243 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1245 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1246 "pair %d:%d got %d, expected %d\n",
1247 kern_pair[n].wFirst, kern_pair[n].wSecond,
1248 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1254 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1255 matches, kd[i].total_kern_pairs);
1257 HeapFree(GetProcessHeap(), 0, kern_pair);
1259 SelectObject(hdc, hfont_old);
1260 DeleteObject(hfont);
1266 static void test_height_selection(void)
1268 static const struct font_data
1270 const char face_name[LF_FACESIZE];
1271 int requested_height;
1272 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1275 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1276 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1277 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1278 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1279 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1280 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1281 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1282 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1283 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1284 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1288 HFONT hfont, old_hfont;
1292 hdc = CreateCompatibleDC(0);
1295 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1297 if (!is_truetype_font_installed(fd[i].face_name))
1299 skip("%s is not installed\n", fd[i].face_name);
1303 memset(&lf, 0, sizeof(lf));
1304 lf.lfHeight = fd[i].requested_height;
1305 lf.lfWeight = fd[i].weight;
1306 strcpy(lf.lfFaceName, fd[i].face_name);
1308 hfont = CreateFontIndirect(&lf);
1311 old_hfont = SelectObject(hdc, hfont);
1312 ret = GetTextMetrics(hdc, &tm);
1313 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1314 if(fd[i].dpi == tm.tmDigitizedAspectX)
1316 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1317 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);
1318 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);
1319 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);
1320 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);
1321 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1322 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);
1324 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);
1327 SelectObject(hdc, old_hfont);
1328 DeleteObject(hfont);
1334 static void test_GetOutlineTextMetrics(void)
1336 OUTLINETEXTMETRIC *otm;
1338 HFONT hfont, hfont_old;
1340 DWORD ret, otm_size;
1343 if (!is_font_installed("Arial"))
1345 skip("Arial is not installed\n");
1351 memset(&lf, 0, sizeof(lf));
1352 strcpy(lf.lfFaceName, "Arial");
1354 lf.lfWeight = FW_NORMAL;
1355 lf.lfPitchAndFamily = DEFAULT_PITCH;
1356 lf.lfQuality = PROOF_QUALITY;
1357 hfont = CreateFontIndirect(&lf);
1360 hfont_old = SelectObject(hdc, hfont);
1361 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1362 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1364 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1366 memset(otm, 0xAA, otm_size);
1367 SetLastError(0xdeadbeef);
1368 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1369 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1370 ok(ret == 1 /* Win9x */ ||
1371 ret == otm->otmSize /* XP*/,
1372 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1373 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1375 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1376 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1377 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1378 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1381 memset(otm, 0xAA, otm_size);
1382 SetLastError(0xdeadbeef);
1383 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1384 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1385 ok(ret == 1 /* Win9x */ ||
1386 ret == otm->otmSize /* XP*/,
1387 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1388 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1390 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1391 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1392 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1393 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1396 /* ask about truncated data */
1397 memset(otm, 0xAA, otm_size);
1398 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1399 SetLastError(0xdeadbeef);
1400 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1401 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1402 ok(ret == 1 /* Win9x */ ||
1403 ret == otm->otmSize /* XP*/,
1404 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1405 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1407 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1408 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1409 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1411 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1413 HeapFree(GetProcessHeap(), 0, otm);
1415 SelectObject(hdc, hfont_old);
1416 DeleteObject(hfont);
1421 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1425 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1426 areaWidth = clientArea->right - clientArea->left,
1428 BOOL lastExtent = FALSE;
1429 PSTR pFirstChar, pLastChar;
1435 int GetTextExtentExPointWWidth;
1438 GetTextMetricsA(hdc, &tm);
1439 y = clientArea->top;
1442 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1448 /* if not at the end of the string, ... */
1449 if (*str == '\0') break;
1450 /* ... add the next word to the current extent */
1451 while (*str != '\0' && *str++ != tm.tmBreakChar);
1453 SetTextJustification(hdc, 0, 0);
1454 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1455 } while ((int) size.cx < areaWidth);
1457 /* ignore trailing break chars */
1459 while (*(pLastChar - 1) == tm.tmBreakChar)
1465 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1467 SetTextJustification(hdc, 0, 0);
1468 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1470 /* do not justify the last extent */
1471 if (*str != '\0' && breakCount > 0)
1473 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1474 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1475 justifiedWidth = size.cx;
1477 else lastExtent = TRUE;
1479 /* catch errors and report them */
1480 if (!lastExtent && (justifiedWidth != areaWidth))
1482 memset(error[nErrors].extent, 0, 100);
1483 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1484 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1490 } while (*str && y < clientArea->bottom);
1492 for (e = 0; e < nErrors; e++)
1494 /* The width returned by GetTextExtentPoint32() is exactly the same
1495 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1496 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1497 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1498 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1502 static void test_SetTextJustification(void)
1509 static char testText[] =
1510 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1511 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1512 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1513 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1514 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1515 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1516 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1518 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1519 GetClientRect( hwnd, &clientArea );
1520 hdc = GetDC( hwnd );
1522 memset(&lf, 0, sizeof lf);
1523 lf.lfCharSet = ANSI_CHARSET;
1524 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1525 lf.lfWeight = FW_DONTCARE;
1527 lf.lfQuality = DEFAULT_QUALITY;
1528 lstrcpyA(lf.lfFaceName, "Times New Roman");
1529 hfont = create_font("Times New Roman", &lf);
1530 SelectObject(hdc, hfont);
1532 testJustification(hdc, testText, &clientArea);
1534 DeleteObject(hfont);
1535 ReleaseDC(hwnd, hdc);
1536 DestroyWindow(hwnd);
1539 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1543 HFONT hfont, hfont_old;
1550 assert(count <= 128);
1552 memset(&lf, 0, sizeof(lf));
1554 lf.lfCharSet = charset;
1556 lstrcpyA(lf.lfFaceName, "Arial");
1557 SetLastError(0xdeadbeef);
1558 hfont = CreateFontIndirectA(&lf);
1559 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1562 hfont_old = SelectObject(hdc, hfont);
1564 cs = GetTextCharsetInfo(hdc, &fs, 0);
1565 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1567 SetLastError(0xdeadbeef);
1568 ret = GetTextFaceA(hdc, sizeof(name), name);
1569 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1571 if (charset == SYMBOL_CHARSET)
1573 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1574 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1578 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1579 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1582 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1584 trace("Can't find codepage for charset %d\n", cs);
1588 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1593 WCHAR unicode_buf[128];
1595 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1597 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1599 SetLastError(0xdeadbeef);
1600 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1601 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1607 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1609 SetLastError(0xdeadbeef);
1610 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1611 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1614 SelectObject(hdc, hfont_old);
1615 DeleteObject(hfont);
1622 static void test_font_charset(void)
1624 static struct charset_data
1628 WORD font_idxA[128], font_idxW[128];
1631 { ANSI_CHARSET, 1252 },
1632 { RUSSIAN_CHARSET, 1251 },
1633 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1637 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1639 win_skip("Skipping the font charset test on a Win9x platform\n");
1643 if (!is_font_installed("Arial"))
1645 skip("Arial is not installed\n");
1649 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1651 if (cd[i].charset == SYMBOL_CHARSET)
1653 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1655 skip("Symbol or Wingdings is not installed\n");
1659 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1660 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1661 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1664 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1667 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1668 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1671 skip("Symbol or Wingdings is not installed\n");
1674 static void test_GetFontUnicodeRanges(void)
1678 HFONT hfont, hfont_old;
1682 if (!pGetFontUnicodeRanges)
1684 win_skip("GetFontUnicodeRanges not available before W2K\n");
1688 memset(&lf, 0, sizeof(lf));
1689 lstrcpyA(lf.lfFaceName, "Arial");
1690 hfont = create_font("Arial", &lf);
1693 hfont_old = SelectObject(hdc, hfont);
1695 size = pGetFontUnicodeRanges(NULL, NULL);
1696 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1698 size = pGetFontUnicodeRanges(hdc, NULL);
1699 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1701 gs = HeapAlloc(GetProcessHeap(), 0, size);
1703 size = pGetFontUnicodeRanges(hdc, gs);
1704 ok(size, "GetFontUnicodeRanges failed\n");
1706 for (i = 0; i < gs->cRanges; i++)
1707 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1709 trace("found %u ranges\n", gs->cRanges);
1711 HeapFree(GetProcessHeap(), 0, gs);
1713 SelectObject(hdc, hfont_old);
1714 DeleteObject(hfont);
1715 ReleaseDC(NULL, hdc);
1718 #define MAX_ENUM_FONTS 4096
1720 struct enum_font_data
1723 LOGFONT lf[MAX_ENUM_FONTS];
1726 struct enum_font_dataW
1729 LOGFONTW lf[MAX_ENUM_FONTS];
1732 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1734 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1736 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1738 if (type != TRUETYPE_FONTTYPE) return 1;
1740 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1741 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1743 if (efd->total < MAX_ENUM_FONTS)
1744 efd->lf[efd->total++] = *lf;
1746 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1751 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1753 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1755 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1757 if (type != TRUETYPE_FONTTYPE) return 1;
1759 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1760 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1762 if (efd->total < MAX_ENUM_FONTS)
1763 efd->lf[efd->total++] = *lf;
1765 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1770 static void get_charset_stats(struct enum_font_data *efd,
1771 int *ansi_charset, int *symbol_charset,
1772 int *russian_charset)
1777 *symbol_charset = 0;
1778 *russian_charset = 0;
1780 for (i = 0; i < efd->total; i++)
1782 switch (efd->lf[i].lfCharSet)
1787 case SYMBOL_CHARSET:
1788 (*symbol_charset)++;
1790 case RUSSIAN_CHARSET:
1791 (*russian_charset)++;
1797 static void get_charset_statsW(struct enum_font_dataW *efd,
1798 int *ansi_charset, int *symbol_charset,
1799 int *russian_charset)
1804 *symbol_charset = 0;
1805 *russian_charset = 0;
1807 for (i = 0; i < efd->total; i++)
1809 switch (efd->lf[i].lfCharSet)
1814 case SYMBOL_CHARSET:
1815 (*symbol_charset)++;
1817 case RUSSIAN_CHARSET:
1818 (*russian_charset)++;
1824 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1826 struct enum_font_data efd;
1827 struct enum_font_dataW efdw;
1830 int i, ret, ansi_charset, symbol_charset, russian_charset;
1832 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1834 if (*font_name && !is_truetype_font_installed(font_name))
1836 skip("%s is not installed\n", font_name);
1842 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1843 * while EnumFontFamiliesEx doesn't.
1845 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1848 * Use EnumFontFamiliesW since win98 crashes when the
1849 * second parameter is NULL using EnumFontFamilies
1852 SetLastError(0xdeadbeef);
1853 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1854 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1857 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1858 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1859 ansi_charset, symbol_charset, russian_charset);
1860 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1861 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1862 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1863 ok(russian_charset > 0 ||
1864 broken(russian_charset == 0), /* NT4 */
1865 "NULL family should enumerate RUSSIAN_CHARSET\n");
1869 SetLastError(0xdeadbeef);
1870 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1871 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1874 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1875 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1876 ansi_charset, symbol_charset, russian_charset);
1877 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1878 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1879 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1880 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1885 SetLastError(0xdeadbeef);
1886 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1887 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1888 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1889 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1890 ansi_charset, symbol_charset, russian_charset,
1891 *font_name ? font_name : "<empty>");
1893 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1895 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1896 for (i = 0; i < efd.total; i++)
1898 /* FIXME: remove completely once Wine is fixed */
1899 if (efd.lf[i].lfCharSet != font_charset)
1902 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1905 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1906 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1907 font_name, efd.lf[i].lfFaceName);
1910 memset(&lf, 0, sizeof(lf));
1911 lf.lfCharSet = ANSI_CHARSET;
1912 lstrcpy(lf.lfFaceName, font_name);
1914 SetLastError(0xdeadbeef);
1915 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1916 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1917 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1918 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1919 ansi_charset, symbol_charset, russian_charset,
1920 *font_name ? font_name : "<empty>");
1921 if (font_charset == SYMBOL_CHARSET)
1924 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1926 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1930 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1931 for (i = 0; i < efd.total; i++)
1933 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1935 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1936 font_name, efd.lf[i].lfFaceName);
1940 /* DEFAULT_CHARSET should enumerate all available charsets */
1941 memset(&lf, 0, sizeof(lf));
1942 lf.lfCharSet = DEFAULT_CHARSET;
1943 lstrcpy(lf.lfFaceName, font_name);
1945 SetLastError(0xdeadbeef);
1946 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1947 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1948 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1949 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1950 ansi_charset, symbol_charset, russian_charset,
1951 *font_name ? font_name : "<empty>");
1952 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1953 for (i = 0; i < efd.total; i++)
1956 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1957 font_name, efd.lf[i].lfFaceName);
1961 switch (font_charset)
1964 ok(ansi_charset > 0,
1965 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1967 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1968 ok(russian_charset > 0,
1969 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1971 case SYMBOL_CHARSET:
1973 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1975 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1976 ok(!russian_charset,
1977 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1979 case DEFAULT_CHARSET:
1980 ok(ansi_charset > 0,
1981 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1982 ok(symbol_charset > 0,
1983 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1984 ok(russian_charset > 0,
1985 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1991 ok(ansi_charset > 0,
1992 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1993 ok(symbol_charset > 0,
1994 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1995 ok(russian_charset > 0,
1996 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1999 memset(&lf, 0, sizeof(lf));
2000 lf.lfCharSet = SYMBOL_CHARSET;
2001 lstrcpy(lf.lfFaceName, font_name);
2003 SetLastError(0xdeadbeef);
2004 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2005 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2006 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2007 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2008 ansi_charset, symbol_charset, russian_charset,
2009 *font_name ? font_name : "<empty>");
2010 if (*font_name && font_charset == ANSI_CHARSET)
2011 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2014 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2015 for (i = 0; i < efd.total; i++)
2017 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2019 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2020 font_name, efd.lf[i].lfFaceName);
2024 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2025 ok(symbol_charset > 0,
2026 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2027 ok(!russian_charset,
2028 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2034 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2036 HFONT hfont, hfont_prev;
2038 GLYPHMETRICS gm1, gm2;
2041 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2043 if(!pGetGlyphIndicesA)
2046 /* negative widths are handled just as positive ones */
2047 lf2.lfWidth = -lf->lfWidth;
2049 SetLastError(0xdeadbeef);
2050 hfont = CreateFontIndirectA(lf);
2051 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2052 check_font("original", lf, hfont);
2054 hfont_prev = SelectObject(hdc, hfont);
2056 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2057 if (ret == GDI_ERROR || idx == 0xffff)
2059 SelectObject(hdc, hfont_prev);
2060 DeleteObject(hfont);
2061 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2065 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2066 memset(&gm1, 0xab, sizeof(gm1));
2067 SetLastError(0xdeadbeef);
2068 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2069 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2071 SelectObject(hdc, hfont_prev);
2072 DeleteObject(hfont);
2074 SetLastError(0xdeadbeef);
2075 hfont = CreateFontIndirectA(&lf2);
2076 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2077 check_font("negative width", &lf2, hfont);
2079 hfont_prev = SelectObject(hdc, hfont);
2081 memset(&gm2, 0xbb, sizeof(gm2));
2082 SetLastError(0xdeadbeef);
2083 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2084 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2086 SelectObject(hdc, hfont_prev);
2087 DeleteObject(hfont);
2089 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2090 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2091 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2092 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2093 gm1.gmCellIncX == gm2.gmCellIncX &&
2094 gm1.gmCellIncY == gm2.gmCellIncY,
2095 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2096 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2097 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2098 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2099 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2102 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2103 #include "pshpack2.h"
2107 SHORT xAvgCharWidth;
2108 USHORT usWeightClass;
2109 USHORT usWidthClass;
2111 SHORT ySubscriptXSize;
2112 SHORT ySubscriptYSize;
2113 SHORT ySubscriptXOffset;
2114 SHORT ySubscriptYOffset;
2115 SHORT ySuperscriptXSize;
2116 SHORT ySuperscriptYSize;
2117 SHORT ySuperscriptXOffset;
2118 SHORT ySuperscriptYOffset;
2119 SHORT yStrikeoutSize;
2120 SHORT yStrikeoutPosition;
2123 ULONG ulUnicodeRange1;
2124 ULONG ulUnicodeRange2;
2125 ULONG ulUnicodeRange3;
2126 ULONG ulUnicodeRange4;
2129 USHORT usFirstCharIndex;
2130 USHORT usLastCharIndex;
2131 /* According to the Apple spec, original version didn't have the below fields,
2132 * version numbers were taked from the OpenType spec.
2134 /* version 0 (TrueType 1.5) */
2135 USHORT sTypoAscender;
2136 USHORT sTypoDescender;
2137 USHORT sTypoLineGap;
2139 USHORT usWinDescent;
2140 /* version 1 (TrueType 1.66) */
2141 ULONG ulCodePageRange1;
2142 ULONG ulCodePageRange2;
2143 /* version 2 (OpenType 1.2) */
2146 USHORT usDefaultChar;
2148 USHORT usMaxContext;
2150 #include "poppack.h"
2152 #ifdef WORDS_BIGENDIAN
2153 #define GET_BE_WORD(x) (x)
2154 #define GET_BE_DWORD(x) (x)
2156 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2157 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2160 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2161 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2162 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2163 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2164 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2177 } cmap_encoding_record;
2185 BYTE glyph_ids[256];
2195 USHORT search_range;
2196 USHORT entry_selector;
2199 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2202 USHORT start_count[seg_countx2 / 2];
2203 USHORT id_delta[seg_countx2 / 2];
2204 USHORT id_range_offset[seg_countx2 / 2];
2214 USHORT id_range_offset;
2215 } cmap_format_4_seg;
2217 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2219 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2220 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2221 os2->panose.bWeight, os2->panose.bProportion);
2224 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2227 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2231 for(i = 0; i < 256; i++)
2233 if(cmap->glyph_ids[i] == 0) continue;
2235 if(*first == 256) *first = i;
2237 if(*first == 256) return FALSE;
2241 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2243 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2244 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2245 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2246 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2247 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2250 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2253 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2254 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2255 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2259 for(i = 0; i < seg_count; i++)
2262 cmap_format_4_seg seg;
2264 get_seg4(cmap, i, &seg);
2265 for(code = seg.start_count; code <= seg.end_count; code++)
2267 if(seg.id_range_offset == 0)
2268 index = (seg.id_delta + code) & 0xffff;
2271 index = seg.id_range_offset / 2
2272 + code - seg.start_count
2275 /* some fonts have broken last segment */
2276 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2277 index = GET_BE_WORD(glyph_ids[index]);
2280 trace("segment %04x/%04x index %04x points to nowhere\n",
2281 seg.start_count, seg.end_count, index);
2284 if(index) index += seg.id_delta;
2286 if(*first == 0x10000)
2287 *last = *first = code;
2293 if(*first == 0x10000) return FALSE;
2297 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2300 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2302 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2304 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2305 return (BYTE *)header + GET_BE_DWORD(record->offset);
2318 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2321 cmap_header *header;
2326 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2327 ok(size != GDI_ERROR, "no cmap table found\n");
2328 if(size == GDI_ERROR) return FALSE;
2330 header = HeapAlloc(GetProcessHeap(), 0, size);
2331 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2332 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2333 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2335 cmap = get_cmap(header, 3, 1);
2337 *cmap_type = cmap_ms_unicode;
2340 cmap = get_cmap(header, 3, 0);
2341 if(cmap) *cmap_type = cmap_ms_symbol;
2345 *cmap_type = cmap_none;
2349 format = GET_BE_WORD(*(WORD *)cmap);
2353 r = get_first_last_from_cmap0(cmap, first, last);
2356 r = get_first_last_from_cmap4(cmap, first, last, size);
2359 trace("unhandled cmap format %d\n", format);
2364 HeapFree(GetProcessHeap(), 0, header);
2368 static void test_text_metrics(const LOGFONTA *lf)
2371 HFONT hfont, hfont_old;
2375 const char *font_name = lf->lfFaceName;
2376 DWORD cmap_first = 0, cmap_last = 0;
2377 cmap_type cmap_type;
2381 SetLastError(0xdeadbeef);
2382 hfont = CreateFontIndirectA(lf);
2383 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2385 hfont_old = SelectObject(hdc, hfont);
2387 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2388 if (size == GDI_ERROR)
2390 trace("OS/2 chunk was not found\n");
2393 if (size > sizeof(tt_os2))
2395 trace("got too large OS/2 chunk of size %u\n", size);
2396 size = sizeof(tt_os2);
2399 memset(&tt_os2, 0, sizeof(tt_os2));
2400 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2401 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2403 SetLastError(0xdeadbeef);
2404 ret = GetTextMetricsA(hdc, &tmA);
2405 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2407 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2409 skip("Unable to retrieve first and last glyphs from cmap\n");
2413 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2414 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2415 UINT os2_first_char, os2_last_char, default_char, break_char;
2419 version = GET_BE_WORD(tt_os2.version);
2421 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2422 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2423 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2424 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2426 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2427 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2428 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2430 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2435 case 1257: /* Baltic */
2436 expect_last_W = 0xf8fd;
2439 expect_last_W = 0xf0ff;
2441 expect_break_W = 0x20;
2442 expect_default_W = expect_break_W - 1;
2443 expect_first_A = 0x1e;
2444 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2448 expect_first_W = cmap_first;
2449 expect_last_W = min(cmap_last, os2_last_char);
2450 if(os2_first_char <= 1)
2451 expect_break_W = os2_first_char + 2;
2452 else if(os2_first_char > 0xff)
2453 expect_break_W = 0x20;
2455 expect_break_W = os2_first_char;
2456 expect_default_W = expect_break_W - 1;
2457 expect_first_A = expect_default_W - 1;
2458 expect_last_A = min(expect_last_W, 0xff);
2460 expect_break_A = expect_break_W;
2461 expect_default_A = expect_default_W;
2463 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2464 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2465 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2466 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2467 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2469 ok(tmA.tmFirstChar == expect_first_A ||
2470 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2471 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2472 ok(tmA.tmLastChar == expect_last_A ||
2473 tmA.tmLastChar == 0xff /* win9x */,
2474 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2475 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2476 font_name, tmA.tmBreakChar, expect_break_A);
2477 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2478 font_name, tmA.tmDefaultChar, expect_default_A);
2481 SetLastError(0xdeadbeef);
2482 ret = GetTextMetricsW(hdc, &tmW);
2483 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2484 "GetTextMetricsW error %u\n", GetLastError());
2487 /* Wine uses the os2 first char */
2488 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2489 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2490 font_name, tmW.tmFirstChar, expect_first_W);
2492 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2493 font_name, tmW.tmFirstChar, expect_first_W);
2495 /* Wine uses the os2 last char */
2496 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2497 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2498 font_name, tmW.tmLastChar, expect_last_W);
2500 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2501 font_name, tmW.tmLastChar, expect_last_W);
2502 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2503 font_name, tmW.tmBreakChar, expect_break_W);
2504 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2505 font_name, tmW.tmDefaultChar, expect_default_W);
2507 /* Test the aspect ratio while we have tmW */
2508 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2509 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2510 tmW.tmDigitizedAspectX, ret);
2511 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2512 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2513 tmW.tmDigitizedAspectX, ret);
2517 /* test FF_ values */
2518 switch(tt_os2.panose.bFamilyType)
2522 case PAN_FAMILY_TEXT_DISPLAY:
2523 case PAN_FAMILY_PICTORIAL:
2525 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2526 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2528 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2531 switch(tt_os2.panose.bSerifStyle)
2536 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2539 case PAN_SERIF_COVE:
2540 case PAN_SERIF_OBTUSE_COVE:
2541 case PAN_SERIF_SQUARE_COVE:
2542 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2543 case PAN_SERIF_SQUARE:
2544 case PAN_SERIF_THIN:
2545 case PAN_SERIF_BONE:
2546 case PAN_SERIF_EXAGGERATED:
2547 case PAN_SERIF_TRIANGLE:
2548 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2551 case PAN_SERIF_NORMAL_SANS:
2552 case PAN_SERIF_OBTUSE_SANS:
2553 case PAN_SERIF_PERP_SANS:
2554 case PAN_SERIF_FLARED:
2555 case PAN_SERIF_ROUNDED:
2556 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2561 case PAN_FAMILY_SCRIPT:
2562 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2565 case PAN_FAMILY_DECORATIVE:
2566 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2570 test_negative_width(hdc, lf);
2573 SelectObject(hdc, hfont_old);
2574 DeleteObject(hfont);
2579 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2581 INT *enumed = (INT *)lParam;
2583 if (type == TRUETYPE_FONTTYPE)
2586 test_text_metrics(lf);
2591 static void test_GetTextMetrics(void)
2597 /* Report only once */
2598 if(!pGetGlyphIndicesA)
2599 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2603 memset(&lf, 0, sizeof(lf));
2604 lf.lfCharSet = DEFAULT_CHARSET;
2606 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2607 trace("Tested metrics of %d truetype fonts\n", enumed);
2612 static void test_nonexistent_font(void)
2620 { "Times New Roman Baltic", 186 },
2621 { "Times New Roman CE", 238 },
2622 { "Times New Roman CYR", 204 },
2623 { "Times New Roman Greek", 161 },
2624 { "Times New Roman TUR", 162 }
2630 INT cs, expected_cs, i;
2631 char buf[LF_FACESIZE];
2633 if (!is_truetype_font_installed("Arial") ||
2634 !is_truetype_font_installed("Times New Roman"))
2636 skip("Arial or Times New Roman not installed\n");
2640 expected_cs = GetACP();
2641 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2643 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2646 expected_cs = csi.ciCharset;
2647 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2651 memset(&lf, 0, sizeof(lf));
2653 lf.lfWeight = FW_REGULAR;
2654 lf.lfCharSet = ANSI_CHARSET;
2655 lf.lfPitchAndFamily = FF_SWISS;
2656 strcpy(lf.lfFaceName, "Nonexistent font");
2657 hfont = CreateFontIndirectA(&lf);
2658 hfont = SelectObject(hdc, hfont);
2659 GetTextFaceA(hdc, sizeof(buf), buf);
2660 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2661 cs = GetTextCharset(hdc);
2662 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2663 DeleteObject(SelectObject(hdc, hfont));
2665 memset(&lf, 0, sizeof(lf));
2667 lf.lfWeight = FW_DONTCARE;
2668 strcpy(lf.lfFaceName, "Nonexistent font");
2669 hfont = CreateFontIndirectA(&lf);
2670 hfont = SelectObject(hdc, hfont);
2671 GetTextFaceA(hdc, sizeof(buf), buf);
2672 todo_wine /* Wine uses Arial for all substitutions */
2673 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2674 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2675 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2677 cs = GetTextCharset(hdc);
2678 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2679 DeleteObject(SelectObject(hdc, hfont));
2681 memset(&lf, 0, sizeof(lf));
2683 lf.lfWeight = FW_REGULAR;
2684 strcpy(lf.lfFaceName, "Nonexistent font");
2685 hfont = CreateFontIndirectA(&lf);
2686 hfont = SelectObject(hdc, hfont);
2687 GetTextFaceA(hdc, sizeof(buf), buf);
2688 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2689 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2690 cs = GetTextCharset(hdc);
2691 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2692 DeleteObject(SelectObject(hdc, hfont));
2694 memset(&lf, 0, sizeof(lf));
2696 lf.lfWeight = FW_DONTCARE;
2697 strcpy(lf.lfFaceName, "Times New Roman");
2698 hfont = CreateFontIndirectA(&lf);
2699 hfont = SelectObject(hdc, hfont);
2700 GetTextFaceA(hdc, sizeof(buf), buf);
2701 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2702 cs = GetTextCharset(hdc);
2703 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2704 DeleteObject(SelectObject(hdc, hfont));
2706 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2708 memset(&lf, 0, sizeof(lf));
2710 lf.lfWeight = FW_REGULAR;
2711 strcpy(lf.lfFaceName, font_subst[i].name);
2712 hfont = CreateFontIndirectA(&lf);
2713 hfont = SelectObject(hdc, hfont);
2714 cs = GetTextCharset(hdc);
2715 if (font_subst[i].charset == expected_cs)
2717 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2718 GetTextFaceA(hdc, sizeof(buf), buf);
2719 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2723 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2724 GetTextFaceA(hdc, sizeof(buf), buf);
2725 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2726 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2728 DeleteObject(SelectObject(hdc, hfont));
2730 memset(&lf, 0, sizeof(lf));
2732 lf.lfWeight = FW_DONTCARE;
2733 strcpy(lf.lfFaceName, font_subst[i].name);
2734 hfont = CreateFontIndirectA(&lf);
2735 hfont = SelectObject(hdc, hfont);
2736 GetTextFaceA(hdc, sizeof(buf), buf);
2737 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2738 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2739 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2740 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2741 "got %s for font %s\n", buf, font_subst[i].name);
2742 cs = GetTextCharset(hdc);
2743 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2744 DeleteObject(SelectObject(hdc, hfont));
2750 static void test_GdiRealizationInfo(void)
2755 HFONT hfont, hfont_old;
2758 if(!pGdiRealizationInfo)
2760 win_skip("GdiRealizationInfo not available\n");
2766 memset(info, 0xcc, sizeof(info));
2767 r = pGdiRealizationInfo(hdc, info);
2768 ok(r != 0, "ret 0\n");
2769 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2770 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2772 if (!is_truetype_font_installed("Arial"))
2774 skip("skipping GdiRealizationInfo with truetype font\n");
2778 memset(&lf, 0, sizeof(lf));
2779 strcpy(lf.lfFaceName, "Arial");
2781 lf.lfWeight = FW_NORMAL;
2782 hfont = CreateFontIndirectA(&lf);
2783 hfont_old = SelectObject(hdc, hfont);
2785 memset(info, 0xcc, sizeof(info));
2786 r = pGdiRealizationInfo(hdc, info);
2787 ok(r != 0, "ret 0\n");
2788 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2789 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2791 DeleteObject(SelectObject(hdc, hfont_old));
2797 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2798 the nul in the count of characters copied when the face name buffer is not
2799 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2800 always includes it. */
2801 static void test_GetTextFace(void)
2803 static const char faceA[] = "Tahoma";
2804 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2807 char bufA[LF_FACESIZE];
2808 WCHAR bufW[LF_FACESIZE];
2813 if(!is_font_installed("Tahoma"))
2815 skip("Tahoma is not installed so skipping this test\n");
2820 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2821 f = CreateFontIndirectA(&fA);
2822 ok(f != NULL, "CreateFontIndirectA failed\n");
2825 g = SelectObject(dc, f);
2826 n = GetTextFaceA(dc, sizeof bufA, bufA);
2827 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2828 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2830 /* Play with the count arg. */
2832 n = GetTextFaceA(dc, 0, bufA);
2833 ok(n == 0, "GetTextFaceA returned %d\n", n);
2834 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2837 n = GetTextFaceA(dc, 1, bufA);
2838 ok(n == 0, "GetTextFaceA returned %d\n", n);
2839 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2841 bufA[0] = 'x'; bufA[1] = 'y';
2842 n = GetTextFaceA(dc, 2, bufA);
2843 ok(n == 1, "GetTextFaceA returned %d\n", n);
2844 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2846 n = GetTextFaceA(dc, 0, NULL);
2847 ok(n == sizeof faceA ||
2848 broken(n == 0), /* win98, winMe */
2849 "GetTextFaceA returned %d\n", n);
2851 DeleteObject(SelectObject(dc, g));
2852 ReleaseDC(NULL, dc);
2855 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2856 SetLastError(0xdeadbeef);
2857 f = CreateFontIndirectW(&fW);
2858 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2860 win_skip("CreateFontIndirectW is not implemented\n");
2863 ok(f != NULL, "CreateFontIndirectW failed\n");
2866 g = SelectObject(dc, f);
2867 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2868 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2869 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2871 /* Play with the count arg. */
2873 n = GetTextFaceW(dc, 0, bufW);
2874 ok(n == 0, "GetTextFaceW returned %d\n", n);
2875 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2878 n = GetTextFaceW(dc, 1, bufW);
2879 ok(n == 1, "GetTextFaceW returned %d\n", n);
2880 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2882 bufW[0] = 'x'; bufW[1] = 'y';
2883 n = GetTextFaceW(dc, 2, bufW);
2884 ok(n == 2, "GetTextFaceW returned %d\n", n);
2885 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2887 n = GetTextFaceW(dc, 0, NULL);
2888 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2890 DeleteObject(SelectObject(dc, g));
2891 ReleaseDC(NULL, dc);
2894 static void test_orientation(void)
2896 static const char test_str[11] = "Test String";
2899 HFONT hfont, old_hfont;
2902 if (!is_truetype_font_installed("Arial"))
2904 skip("Arial is not installed\n");
2908 hdc = CreateCompatibleDC(0);
2909 memset(&lf, 0, sizeof(lf));
2910 lstrcpyA(lf.lfFaceName, "Arial");
2912 lf.lfOrientation = lf.lfEscapement = 900;
2913 hfont = create_font("orientation", &lf);
2914 old_hfont = SelectObject(hdc, hfont);
2915 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2916 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2917 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2918 SelectObject(hdc, old_hfont);
2919 DeleteObject(hfont);
2923 static void test_oemcharset(void)
2927 HFONT hfont, old_hfont;
2930 hdc = CreateCompatibleDC(0);
2931 ZeroMemory(&lf, sizeof(lf));
2933 lf.lfCharSet = OEM_CHARSET;
2934 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
2935 lstrcpyA(lf.lfFaceName, "Terminal");
2936 hfont = CreateFontIndirectA(&lf);
2937 old_hfont = SelectObject(hdc, hfont);
2938 charset = GetTextCharset(hdc);
2940 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
2941 hfont = SelectObject(hdc, old_hfont);
2942 GetObjectA(hfont, sizeof(clf), &clf);
2943 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
2944 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
2945 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
2946 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
2947 DeleteObject(hfont);
2951 static void test_GetGlyphOutline(void)
2953 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2957 HFONT hfont, old_hfont;
2960 if (!is_truetype_font_installed("Tahoma"))
2962 skip("Tahoma is not installed\n");
2966 hdc = CreateCompatibleDC(0);
2967 memset(&lf, 0, sizeof(lf));
2969 lstrcpyA(lf.lfFaceName, "Tahoma");
2970 SetLastError(0xdeadbeef);
2971 hfont = CreateFontIndirectA(&lf);
2972 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2973 old_hfont = SelectObject(hdc, hfont);
2975 memset(&gm, 0, sizeof(gm));
2976 SetLastError(0xdeadbeef);
2977 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2978 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2980 memset(&gm, 0, sizeof(gm));
2981 SetLastError(0xdeadbeef);
2982 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2983 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2984 ok(GetLastError() == 0xdeadbeef ||
2985 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2986 "expected 0xdeadbeef, got %u\n", GetLastError());
2988 memset(&gm, 0, sizeof(gm));
2989 SetLastError(0xdeadbeef);
2990 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2991 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2992 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
2994 memset(&gm, 0, sizeof(gm));
2995 SetLastError(0xdeadbeef);
2996 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2997 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2999 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3000 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3003 /* test for needed buffer size request on space char */
3004 memset(&gm, 0, sizeof(gm));
3005 SetLastError(0xdeadbeef);
3006 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3007 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3008 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3010 /* requesting buffer size for space char + error */
3011 memset(&gm, 0, sizeof(gm));
3012 SetLastError(0xdeadbeef);
3013 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3014 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3016 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3017 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3020 SelectObject(hdc, old_hfont);
3021 DeleteObject(hfont);
3025 /* bug #9995: there is a limit to the character width that can be specified */
3026 static void test_GetTextMetrics2(const char *fontname, int font_height)
3032 int ave_width, height, width, ratio, scale;
3034 if (!is_truetype_font_installed( fontname)) {
3035 skip("%s is not installed\n", fontname);
3038 hdc = CreateCompatibleDC(0);
3039 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3040 /* select width = 0 */
3041 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3042 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3043 DEFAULT_QUALITY, VARIABLE_PITCH,
3045 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3046 of = SelectObject( hdc, hf);
3047 ret = GetTextMetricsA( hdc, &tm);
3048 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3049 height = tm.tmHeight;
3050 ave_width = tm.tmAveCharWidth;
3051 SelectObject( hdc, of);
3054 trace("height %d, ave width %d\n", height, ave_width);
3056 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3058 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3059 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3060 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3061 ok(hf != 0, "CreateFont failed\n");
3062 of = SelectObject(hdc, hf);
3063 ret = GetTextMetrics(hdc, &tm);
3064 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3065 SelectObject(hdc, of);
3068 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3074 ratio = width / height;
3075 scale = width / ave_width;
3077 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3078 width, height, ratio, width, ave_width, scale);
3080 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3083 static void test_CreateFontIndirect(void)
3085 LOGFONTA lf, getobj_lf;
3088 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3090 memset(&lf, 0, sizeof(lf));
3091 lf.lfCharSet = ANSI_CHARSET;
3092 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3095 lf.lfQuality = DEFAULT_QUALITY;
3096 lf.lfItalic = FALSE;
3097 lf.lfWeight = FW_DONTCARE;
3099 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3101 lstrcpyA(lf.lfFaceName, TestName[i]);
3102 hfont = CreateFontIndirectA(&lf);
3103 ok(hfont != 0, "CreateFontIndirectA failed\n");
3104 SetLastError(0xdeadbeef);
3105 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3106 ok(ret, "GetObject failed: %d\n", GetLastError());
3107 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3108 ok(lf.lfWeight == getobj_lf.lfWeight ||
3109 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3110 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3111 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3112 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3113 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3114 DeleteObject(hfont);
3118 static void test_CreateFontIndirectEx(void)
3120 ENUMLOGFONTEXDVA lfex;
3123 if (!pCreateFontIndirectExA)
3125 win_skip("CreateFontIndirectExA is not available\n");
3129 if (!is_truetype_font_installed("Arial"))
3131 skip("Arial is not installed\n");
3135 SetLastError(0xdeadbeef);
3136 hfont = pCreateFontIndirectExA(NULL);
3137 ok(hfont == NULL, "got %p\n", hfont);
3138 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3140 memset(&lfex, 0, sizeof(lfex));
3141 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3142 hfont = pCreateFontIndirectExA(&lfex);
3143 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3145 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3146 DeleteObject(hfont);
3149 static void free_font(void *font)
3151 UnmapViewOfFile(font);
3154 static void *load_font(const char *font_name, DWORD *font_size)
3156 char file_name[MAX_PATH];
3157 HANDLE file, mapping;
3160 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3161 strcat(file_name, "\\fonts\\");
3162 strcat(file_name, font_name);
3164 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3165 if (file == INVALID_HANDLE_VALUE) return NULL;
3167 *font_size = GetFileSize(file, NULL);
3169 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3176 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3179 CloseHandle(mapping);
3183 static void test_AddFontMemResource(void)
3186 DWORD font_size, num_fonts;
3189 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3191 win_skip("AddFontMemResourceEx is not available on this platform\n");
3195 font = load_font("sserife.fon", &font_size);
3198 skip("Unable to locate and load font sserife.fon\n");
3202 num_fonts = 0xdeadbeef;
3203 SetLastError(0xdeadbeef);
3204 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3205 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3206 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3207 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3211 SetLastError(0xdeadbeef);
3212 ok(pRemoveFontMemResourceEx(ret), "RemoveFontMemResourceEx error %d\n", GetLastError());
3214 /* test invalid pointer to number of loaded fonts */
3215 font = load_font("sserife.fon", &font_size);
3216 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3218 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3219 ok(!ret, "AddFontMemResourceEx should fail\n");
3221 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3222 ok(!ret, "AddFontMemResourceEx should fail\n");
3233 test_outline_font();
3234 test_bitmap_font_metrics();
3235 test_GdiGetCharDimensions();
3236 test_GetCharABCWidths();
3237 test_text_extents();
3238 test_GetGlyphIndices();
3239 test_GetKerningPairs();
3240 test_GetOutlineTextMetrics();
3241 test_SetTextJustification();
3242 test_font_charset();
3243 test_GetFontUnicodeRanges();
3244 test_nonexistent_font();
3246 test_height_selection();
3247 test_AddFontMemResource();
3249 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3250 * I'd like to avoid them in this test.
3252 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3253 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3254 if (is_truetype_font_installed("Arial Black") &&
3255 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3257 test_EnumFontFamilies("", ANSI_CHARSET);
3258 test_EnumFontFamilies("", SYMBOL_CHARSET);
3259 test_EnumFontFamilies("", DEFAULT_CHARSET);
3262 skip("Arial Black or Symbol/Wingdings is not installed\n");
3263 test_GetTextMetrics();
3264 test_GdiRealizationInfo();
3266 test_GetGlyphOutline();
3267 test_GetTextMetrics2("Tahoma", -11);
3268 test_GetTextMetrics2("Tahoma", -55);
3269 test_GetTextMetrics2("Tahoma", -110);
3270 test_GetTextMetrics2("Arial", -11);
3271 test_GetTextMetrics2("Arial", -55);
3272 test_GetTextMetrics2("Arial", -110);
3273 test_CreateFontIndirect();
3274 test_CreateFontIndirectEx();