2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
45 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
46 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
48 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
49 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
50 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static HMODULE hgdi32 = 0;
54 static void init(void)
56 hgdi32 = GetModuleHandleA("gdi32.dll");
58 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
59 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
60 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
61 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
62 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
63 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
64 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
65 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
66 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
67 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
68 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
69 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
72 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
74 if (type != TRUETYPE_FONTTYPE) return 1;
79 static BOOL is_truetype_font_installed(const char *name)
84 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
91 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
96 static BOOL is_font_installed(const char *name)
101 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
108 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
116 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
117 /* NT4 tries to be clever and only returns the minimum length */
118 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
120 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
121 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
122 ok(lf->lfHeight == getobj_lf.lfHeight ||
123 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
124 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
125 ok(lf->lfWidth == getobj_lf.lfWidth ||
126 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
127 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
128 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
129 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
130 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
131 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
132 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
133 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
134 ok(lf->lfWeight == getobj_lf.lfWeight ||
135 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
136 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
137 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
138 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
139 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
140 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
141 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
142 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
143 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
144 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
145 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
146 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
147 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
150 static HFONT create_font(const char* test, const LOGFONTA* lf)
152 HFONT hfont = CreateFontIndirectA(lf);
153 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
155 check_font(test, lf, hfont);
159 static void test_logfont(void)
164 memset(&lf, 0, sizeof lf);
166 lf.lfCharSet = ANSI_CHARSET;
167 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
168 lf.lfWeight = FW_DONTCARE;
171 lf.lfQuality = DEFAULT_QUALITY;
173 lstrcpyA(lf.lfFaceName, "Arial");
174 hfont = create_font("Arial", &lf);
177 memset(&lf, 'A', sizeof(lf));
178 hfont = CreateFontIndirectA(&lf);
179 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
181 lf.lfFaceName[LF_FACESIZE - 1] = 0;
182 check_font("AAA...", &lf, hfont);
186 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
188 if (type & RASTER_FONTTYPE)
190 LOGFONT *lf = (LOGFONT *)lParam;
192 return 0; /* stop enumeration */
195 return 1; /* continue enumeration */
198 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
200 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
201 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
202 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
203 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
204 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
205 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
206 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
207 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
208 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
209 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
210 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
211 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
212 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
213 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
214 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
215 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
216 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
217 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
218 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
219 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
222 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
223 LONG lfWidth, const char *test_str,
224 INT test_str_len, const TEXTMETRICA *tm_orig,
225 const SIZE *size_orig, INT width_of_A_orig,
226 INT scale_x, INT scale_y)
229 OUTLINETEXTMETRIC otm;
232 INT width_of_A, cx, cy;
238 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
240 GetObjectA(hfont, sizeof(lf), &lf);
242 if (GetOutlineTextMetricsA(hdc, 0, NULL))
244 otm.otmSize = sizeof(otm) / 2;
245 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
246 ok(ret == sizeof(otm)/2 /* XP */ ||
247 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
249 memset(&otm, 0x1, sizeof(otm));
250 otm.otmSize = sizeof(otm);
251 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
252 ok(ret == sizeof(otm) /* XP */ ||
253 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
255 memset(&tm, 0x2, sizeof(tm));
256 ret = GetTextMetricsA(hdc, &tm);
257 ok(ret, "GetTextMetricsA failed\n");
258 /* the structure size is aligned */
259 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
261 ok(0, "tm != otm\n");
262 compare_tm(&tm, &otm.otmTextMetrics);
265 tm = otm.otmTextMetrics;
266 if (0) /* these metrics are scaled too, but with rounding errors */
268 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
269 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
271 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
272 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
273 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
274 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
275 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
276 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
280 ret = GetTextMetricsA(hdc, &tm);
281 ok(ret, "GetTextMetricsA failed\n");
284 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
285 cy = tm.tmHeight / tm_orig->tmHeight;
286 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
287 lfHeight, scale_x, scale_y, cx, cy);
288 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
289 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
290 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
291 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
292 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
294 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
298 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
301 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
303 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
305 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
306 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
308 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
310 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
313 /* Test how GDI scales bitmap font metrics */
314 static void test_bitmap_font(void)
316 static const char test_str[11] = "Test String";
319 HFONT hfont, old_hfont;
322 INT ret, i, width_orig, height_orig, scale, lfWidth;
326 /* "System" has only 1 pixel size defined, otherwise the test breaks */
327 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
331 trace("no bitmap fonts were found, skipping the test\n");
335 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
337 height_orig = bitmap_lf.lfHeight;
338 lfWidth = bitmap_lf.lfWidth;
340 hfont = create_font("bitmap", &bitmap_lf);
341 old_hfont = SelectObject(hdc, hfont);
342 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
343 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
344 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
345 SelectObject(hdc, old_hfont);
348 bitmap_lf.lfHeight = 0;
349 bitmap_lf.lfWidth = 4;
350 hfont = create_font("bitmap", &bitmap_lf);
351 old_hfont = SelectObject(hdc, hfont);
352 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
353 SelectObject(hdc, old_hfont);
356 bitmap_lf.lfHeight = height_orig;
357 bitmap_lf.lfWidth = lfWidth;
359 /* test fractional scaling */
360 for (i = 1; i <= height_orig * 6; i++)
364 bitmap_lf.lfHeight = i;
365 hfont = create_font("fractional", &bitmap_lf);
366 scale = (i + height_orig - 1) / height_orig;
367 nearest_height = scale * height_orig;
368 /* Only jump to the next height if the difference <= 25% original height */
369 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
370 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
371 so we'll not test this particular height. */
372 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
373 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
374 old_hfont = SelectObject(hdc, hfont);
375 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
376 SelectObject(hdc, old_hfont);
380 /* test integer scaling 3x2 */
381 bitmap_lf.lfHeight = height_orig * 2;
382 bitmap_lf.lfWidth *= 3;
383 hfont = create_font("3x2", &bitmap_lf);
384 old_hfont = SelectObject(hdc, hfont);
385 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
386 SelectObject(hdc, old_hfont);
389 /* test integer scaling 3x3 */
390 bitmap_lf.lfHeight = height_orig * 3;
391 bitmap_lf.lfWidth = 0;
392 hfont = create_font("3x3", &bitmap_lf);
393 old_hfont = SelectObject(hdc, hfont);
394 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
395 SelectObject(hdc, old_hfont);
401 /* Test how GDI scales outline font metrics */
402 static void test_outline_font(void)
404 static const char test_str[11] = "Test String";
407 HFONT hfont, old_hfont, old_hfont_2;
408 OUTLINETEXTMETRICA otm;
410 INT width_orig, height_orig, lfWidth;
413 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
414 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
418 if (!is_truetype_font_installed("Arial"))
420 skip("Arial is not installed\n");
424 hdc = CreateCompatibleDC(0);
426 memset(&lf, 0, sizeof(lf));
427 strcpy(lf.lfFaceName, "Arial");
429 hfont = create_font("outline", &lf);
430 old_hfont = SelectObject(hdc, hfont);
431 otm.otmSize = sizeof(otm);
432 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
433 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
434 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
436 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
437 SelectObject(hdc, old_hfont);
440 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
441 lf.lfHeight = otm.otmEMSquare;
442 lf.lfHeight = -lf.lfHeight;
443 hfont = create_font("outline", &lf);
444 old_hfont = SelectObject(hdc, hfont);
445 otm.otmSize = sizeof(otm);
446 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
447 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
448 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
449 SelectObject(hdc, old_hfont);
452 height_orig = otm.otmTextMetrics.tmHeight;
453 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
455 /* test integer scaling 3x2 */
456 lf.lfHeight = height_orig * 2;
457 lf.lfWidth = lfWidth * 3;
458 hfont = create_font("3x2", &lf);
459 old_hfont = SelectObject(hdc, hfont);
460 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
461 SelectObject(hdc, old_hfont);
464 /* test integer scaling 3x3 */
465 lf.lfHeight = height_orig * 3;
466 lf.lfWidth = lfWidth * 3;
467 hfont = create_font("3x3", &lf);
468 old_hfont = SelectObject(hdc, hfont);
469 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
470 SelectObject(hdc, old_hfont);
473 /* test integer scaling 1x1 */
474 lf.lfHeight = height_orig * 1;
475 lf.lfWidth = lfWidth * 1;
476 hfont = create_font("1x1", &lf);
477 old_hfont = SelectObject(hdc, hfont);
478 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
479 SelectObject(hdc, old_hfont);
482 /* test integer scaling 1x1 */
483 lf.lfHeight = height_orig;
485 hfont = create_font("1x1", &lf);
486 old_hfont = SelectObject(hdc, hfont);
487 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
489 /* with an identity matrix */
490 memset(&gm, 0, sizeof(gm));
491 SetLastError(0xdeadbeef);
492 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
493 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
495 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
496 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
497 /* with a custom matrix */
498 memset(&gm, 0, sizeof(gm));
499 SetLastError(0xdeadbeef);
500 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
501 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
502 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
503 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
504 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
506 /* Test that changing the DC transformation affects only the font
507 * selected on this DC and doesn't affect the same font selected on
510 hdc_2 = CreateCompatibleDC(0);
511 old_hfont_2 = SelectObject(hdc_2, hfont);
512 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
514 SetMapMode(hdc, MM_ANISOTROPIC);
516 /* font metrics on another DC should be unchanged */
517 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
519 /* test restrictions of compatibility mode GM_COMPATIBLE */
520 /* part 1: rescaling only X should not change font scaling on screen.
521 So compressing the X axis by 2 is not done, and this
522 appears as X scaling of 2 that no one requested. */
523 SetWindowExtEx(hdc, 100, 100, NULL);
524 SetViewportExtEx(hdc, 50, 100, NULL);
525 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
526 /* font metrics on another DC should be unchanged */
527 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
529 /* part 2: rescaling only Y should change font scaling.
530 As also X is scaled by a factor of 2, but this is not
531 requested by the DC transformation, we get a scaling factor
532 of 2 in the X coordinate. */
533 SetViewportExtEx(hdc, 100, 200, NULL);
534 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
535 /* font metrics on another DC should be unchanged */
536 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
538 /* restore scaling */
539 SetMapMode(hdc, MM_TEXT);
541 /* font metrics on another DC should be unchanged */
542 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
544 SelectObject(hdc_2, old_hfont_2);
547 if (!SetGraphicsMode(hdc, GM_ADVANCED))
549 SelectObject(hdc, old_hfont);
552 skip("GM_ADVANCED is not supported on this platform\n");
563 SetLastError(0xdeadbeef);
564 ret = SetWorldTransform(hdc, &xform);
565 ok(ret, "SetWorldTransform error %u\n", GetLastError());
567 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
569 /* with an identity matrix */
570 memset(&gm, 0, sizeof(gm));
571 SetLastError(0xdeadbeef);
572 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
573 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
574 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
575 pt.x = width_orig; pt.y = 0;
577 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
578 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
579 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
580 /* with a custom matrix */
581 memset(&gm, 0, sizeof(gm));
582 SetLastError(0xdeadbeef);
583 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
584 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
585 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
586 pt.x = width_orig; pt.y = 0;
588 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
589 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
592 SetLastError(0xdeadbeef);
593 ret = SetMapMode(hdc, MM_LOMETRIC);
594 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
596 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
598 /* with an identity matrix */
599 memset(&gm, 0, sizeof(gm));
600 SetLastError(0xdeadbeef);
601 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
602 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
604 pt.x = width_orig; pt.y = 0;
606 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
607 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
608 /* with a custom matrix */
609 memset(&gm, 0, sizeof(gm));
610 SetLastError(0xdeadbeef);
611 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
612 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
613 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
614 pt.x = width_orig; pt.y = 0;
616 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
617 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
619 SetLastError(0xdeadbeef);
620 ret = SetMapMode(hdc, MM_TEXT);
621 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
623 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
625 /* with an identity matrix */
626 memset(&gm, 0, sizeof(gm));
627 SetLastError(0xdeadbeef);
628 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
629 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
630 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
631 pt.x = width_orig; pt.y = 0;
633 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
634 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
635 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
636 /* with a custom matrix */
637 memset(&gm, 0, sizeof(gm));
638 SetLastError(0xdeadbeef);
639 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
640 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
641 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
642 pt.x = width_orig; pt.y = 0;
644 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
645 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
646 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
648 SelectObject(hdc, old_hfont);
653 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
655 LOGFONT *lf = (LOGFONT *)lParam;
657 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
660 return 0; /* stop enumeration */
662 return 1; /* continue enumeration */
665 static void test_bitmap_font_metrics(void)
667 static const struct font_data
669 const char face_name[LF_FACESIZE];
670 int weight, height, ascent, descent, int_leading, ext_leading;
671 int ave_char_width, max_char_width, dpi;
676 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
677 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
679 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
680 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
681 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
682 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
684 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
685 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
688 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
689 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
690 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
691 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
693 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
694 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
695 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
697 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
698 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
699 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
700 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
701 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
702 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
703 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
705 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
706 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
707 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
709 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
710 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
711 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
712 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
713 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
717 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
719 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
721 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
722 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
723 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
724 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
725 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
727 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
728 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
729 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
731 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
732 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
733 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
735 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
736 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
737 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
739 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
740 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
742 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
743 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
744 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
745 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1, LANG_ARABIC },
746 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
747 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
748 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1, LANG_ARABIC },
749 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
750 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_ARABIC },
751 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
752 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1, LANG_ARABIC },
753 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
754 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_ARABIC },
755 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
757 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, FS_ARABIC },
759 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
761 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, FS_ARABIC },
762 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
765 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
766 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
767 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
768 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
769 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
770 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
771 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
772 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
773 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
774 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
775 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
777 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
778 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
779 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
781 /* The 120dpi version still has its dpi marked as 96 */
782 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
784 /* FIXME: add "Terminal" */
788 HFONT hfont, old_hfont;
793 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
795 hdc = CreateCompatibleDC(0);
798 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
802 memset(&lf, 0, sizeof(lf));
804 lf.lfHeight = fd[i].height;
805 strcpy(lf.lfFaceName, fd[i].face_name);
807 for(bit = 0; bit < 32; bit++)
815 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
816 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
818 lf.lfCharSet = csi.ciCharset;
819 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
822 hfont = create_font(lf.lfFaceName, &lf);
823 old_hfont = SelectObject(hdc, hfont);
824 bRet = GetTextMetrics(hdc, &tm);
825 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
826 if(fd[i].dpi == tm.tmDigitizedAspectX)
828 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
829 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
831 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
832 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
833 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
834 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
835 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
836 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
837 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
839 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
840 that make the max width bigger */
841 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
842 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
845 skip("Skipping font metrics test for system langid 0x%x\n",
848 SelectObject(hdc, old_hfont);
856 static void test_GdiGetCharDimensions(void)
862 LONG avgwidth, height;
863 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
865 if (!pGdiGetCharDimensions)
867 win_skip("GdiGetCharDimensions not available on this platform\n");
871 hdc = CreateCompatibleDC(NULL);
873 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
874 avgwidth = ((size.cx / 26) + 1) / 2;
876 ret = pGdiGetCharDimensions(hdc, &tm, &height);
877 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
878 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
880 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
881 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
883 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
884 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
887 ret = pGdiGetCharDimensions(hdc, NULL, &height);
888 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
889 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
894 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
895 const TEXTMETRIC *lpntme,
896 DWORD FontType, LPARAM lParam)
898 if (FontType & TRUETYPE_FONTTYPE)
902 hfont = CreateFontIndirect(lpelfe);
905 *(HFONT *)lParam = hfont;
913 static void test_GetCharABCWidths(void)
915 static const WCHAR str[] = {'a',0};
936 {0xffffff, 0xffffff},
937 {0x1000000, 0x1000000},
938 {0xffffff, 0x1000000},
939 {0xffffffff, 0xffffffff}
946 BOOL r[sizeof range / sizeof range[0]];
949 {ANSI_CHARSET, 0x30, 0x30, {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
950 {SHIFTJIS_CHARSET, 0x82a0, 0x3042, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
951 {HANGEUL_CHARSET, 0x8141, 0xac02, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
952 {JOHAB_CHARSET, 0x8446, 0x3135, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
953 {GB2312_CHARSET, 0x8141, 0x4e04, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
954 {CHINESEBIG5_CHARSET, 0xa142, 0x3001, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}}
958 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsI)
960 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
964 memset(&lf, 0, sizeof(lf));
965 strcpy(lf.lfFaceName, "System");
968 hfont = CreateFontIndirectA(&lf);
970 hfont = SelectObject(hdc, hfont);
972 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
973 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
975 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
976 ok(!ret, "GetCharABCWidthsI should have failed\n");
978 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
979 ok(!ret, "GetCharABCWidthsI should have failed\n");
981 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
982 ok(ret, "GetCharABCWidthsI should have succeeded\n");
984 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
985 ok(!ret, "GetCharABCWidthsW should have failed\n");
987 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
988 ok(!ret, "GetCharABCWidthsW should have failed\n");
990 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
991 ok(!ret, "GetCharABCWidthsW should have failed\n");
993 hfont = SelectObject(hdc, hfont);
996 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1000 UINT code = 0x41, j;
1002 lf.lfFaceName[0] = '\0';
1003 lf.lfCharSet = c[i].cs;
1004 lf.lfPitchAndFamily = 0;
1005 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1007 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1011 memset(a, 0, sizeof a);
1012 memset(w, 0, sizeof w);
1013 hfont = SelectObject(hdc, hfont);
1014 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1015 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1016 memcmp(a, w, sizeof a) == 0,
1017 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1019 memset(a, 0xbb, sizeof a);
1020 ret = pGetCharABCWidthsA(hdc, code, code, a);
1021 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1022 memset(full, 0xcc, sizeof full);
1023 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1024 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1025 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1026 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1028 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1030 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1031 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1032 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1035 hfont = SelectObject(hdc, hfont);
1036 DeleteObject(hfont);
1039 ReleaseDC(NULL, hdc);
1042 static void test_text_extents(void)
1044 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1046 INT i, len, fit1, fit2;
1054 memset(&lf, 0, sizeof(lf));
1055 strcpy(lf.lfFaceName, "Arial");
1058 hfont = CreateFontIndirectA(&lf);
1060 hfont = SelectObject(hdc, hfont);
1061 GetTextMetricsA(hdc, &tm);
1062 GetTextExtentPointA(hdc, "o", 1, &sz);
1063 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1065 SetLastError(0xdeadbeef);
1066 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1067 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1069 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1070 hfont = SelectObject(hdc, hfont);
1071 DeleteObject(hfont);
1077 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1078 extents[0] = 1; /* So that the increasing sequence test will fail
1079 if the extents array is untouched. */
1080 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1081 GetTextExtentPointW(hdc, wt, len, &sz2);
1082 ok(sz1.cy == sz2.cy,
1083 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1084 /* Because of the '\n' in the string GetTextExtentExPoint and
1085 GetTextExtentPoint return different widths under Win2k, but
1086 under WinXP they return the same width. So we don't test that
1089 for (i = 1; i < len; ++i)
1090 ok(extents[i-1] <= extents[i],
1091 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1093 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1094 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1095 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1096 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1097 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1098 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1099 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1100 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1101 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1102 ok(extents[0] == extents[2] && extents[1] == extents[3],
1103 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1104 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1105 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1106 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1107 HeapFree(GetProcessHeap(), 0, extents);
1109 hfont = SelectObject(hdc, hfont);
1110 DeleteObject(hfont);
1111 ReleaseDC(NULL, hdc);
1114 static void test_GetGlyphIndices(void)
1121 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1122 WORD glyphs[(sizeof(testtext)/2)-1];
1126 if (!pGetGlyphIndicesW) {
1127 win_skip("GetGlyphIndicesW not available on platform\n");
1133 memset(&lf, 0, sizeof(lf));
1134 strcpy(lf.lfFaceName, "System");
1136 lf.lfCharSet = ANSI_CHARSET;
1138 hfont = CreateFontIndirectA(&lf);
1139 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1140 if (textm.tmCharSet == ANSI_CHARSET)
1142 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1143 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1144 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1145 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1147 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1148 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1149 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1150 textm.tmDefaultChar, glyphs[4]);
1153 /* FIXME: Write tests for non-ANSI charsets. */
1154 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1156 if(!is_font_installed("Tahoma"))
1158 skip("Tahoma is not installed so skipping this test\n");
1161 memset(&lf, 0, sizeof(lf));
1162 strcpy(lf.lfFaceName, "Tahoma");
1165 hfont = CreateFontIndirectA(&lf);
1166 hOldFont = SelectObject(hdc, hfont);
1167 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1168 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1169 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1170 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1171 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1173 testtext[0] = textm.tmDefaultChar;
1174 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1175 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1176 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1177 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1178 DeleteObject(SelectObject(hdc, hOldFont));
1181 static void test_GetKerningPairs(void)
1183 static const struct kerning_data
1185 const char face_name[LF_FACESIZE];
1187 /* some interesting fields from OUTLINETEXTMETRIC */
1188 LONG tmHeight, tmAscent, tmDescent;
1193 UINT otmsCapEmHeight;
1198 UINT otmusMinimumPPEM;
1199 /* small subset of kerning pairs to test */
1200 DWORD total_kern_pairs;
1201 const KERNINGPAIR kern_pair[26];
1204 {"Arial", 12, 12, 9, 3,
1205 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1208 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1209 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1210 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1211 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1212 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1213 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1214 {933,970,+1},{933,972,-1}
1217 {"Arial", -34, 39, 32, 7,
1218 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1221 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1222 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1223 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1224 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1225 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1226 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1227 {933,970,+2},{933,972,-3}
1230 { "Arial", 120, 120, 97, 23,
1231 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1234 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1235 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1236 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1237 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1238 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1239 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1240 {933,970,+6},{933,972,-10}
1243 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1244 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1245 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1248 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1249 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1250 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1251 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1252 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1253 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1254 {933,970,+54},{933,972,-83}
1260 HFONT hfont, hfont_old;
1261 KERNINGPAIR *kern_pair;
1263 DWORD total_kern_pairs, ret, i, n, matches;
1267 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1268 * which may render this test unusable, so we're trying to avoid that.
1270 SetLastError(0xdeadbeef);
1271 GetKerningPairsW(hdc, 0, NULL);
1272 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1274 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1279 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1281 OUTLINETEXTMETRICW otm;
1284 if (!is_font_installed(kd[i].face_name))
1286 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1290 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1292 memset(&lf, 0, sizeof(lf));
1293 strcpy(lf.lfFaceName, kd[i].face_name);
1294 lf.lfHeight = kd[i].height;
1295 hfont = CreateFontIndirect(&lf);
1298 hfont_old = SelectObject(hdc, hfont);
1300 SetLastError(0xdeadbeef);
1301 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1302 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1303 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1305 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1306 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1307 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1308 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1309 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1310 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1312 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1313 kd[i].otmEMSquare, otm.otmEMSquare);
1314 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1315 kd[i].otmAscent, otm.otmAscent);
1316 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1317 kd[i].otmDescent, otm.otmDescent);
1318 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1319 kd[i].otmLineGap, otm.otmLineGap);
1320 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1321 kd[i].otmMacDescent, otm.otmMacDescent);
1322 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1323 kd[i].otmMacAscent, otm.otmMacAscent);
1325 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1326 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1327 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1328 kd[i].otmsXHeight, otm.otmsXHeight);
1329 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1330 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1331 kd[i].otmMacLineGap, otm.otmMacLineGap);
1332 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1333 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1336 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1337 trace("total_kern_pairs %u\n", total_kern_pairs);
1338 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1340 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1341 SetLastError(0xdeadbeef);
1342 ret = GetKerningPairsW(hdc, 0, kern_pair);
1343 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1344 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1345 ok(ret == 0, "got %lu, expected 0\n", ret);
1348 ret = GetKerningPairsW(hdc, 100, NULL);
1349 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1351 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1352 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1354 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1355 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1359 for (n = 0; n < ret; n++)
1363 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1364 trace("{'%c','%c',%d},\n",
1365 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1367 for (j = 0; j < kd[i].total_kern_pairs; j++)
1369 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1370 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1372 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1373 "pair %d:%d got %d, expected %d\n",
1374 kern_pair[n].wFirst, kern_pair[n].wSecond,
1375 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1381 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1382 matches, kd[i].total_kern_pairs);
1384 HeapFree(GetProcessHeap(), 0, kern_pair);
1386 SelectObject(hdc, hfont_old);
1387 DeleteObject(hfont);
1393 static void test_height_selection(void)
1395 static const struct font_data
1397 const char face_name[LF_FACESIZE];
1398 int requested_height;
1399 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1402 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1403 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1404 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1405 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1406 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1407 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1408 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1409 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1410 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1411 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1415 HFONT hfont, old_hfont;
1419 hdc = CreateCompatibleDC(0);
1422 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1424 if (!is_truetype_font_installed(fd[i].face_name))
1426 skip("%s is not installed\n", fd[i].face_name);
1430 memset(&lf, 0, sizeof(lf));
1431 lf.lfHeight = fd[i].requested_height;
1432 lf.lfWeight = fd[i].weight;
1433 strcpy(lf.lfFaceName, fd[i].face_name);
1435 hfont = CreateFontIndirect(&lf);
1438 old_hfont = SelectObject(hdc, hfont);
1439 ret = GetTextMetrics(hdc, &tm);
1440 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1441 if(fd[i].dpi == tm.tmDigitizedAspectX)
1443 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1444 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);
1445 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);
1446 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);
1447 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);
1448 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1449 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);
1451 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);
1454 SelectObject(hdc, old_hfont);
1455 DeleteObject(hfont);
1461 static void test_GetOutlineTextMetrics(void)
1463 OUTLINETEXTMETRIC *otm;
1465 HFONT hfont, hfont_old;
1467 DWORD ret, otm_size;
1470 if (!is_font_installed("Arial"))
1472 skip("Arial is not installed\n");
1478 memset(&lf, 0, sizeof(lf));
1479 strcpy(lf.lfFaceName, "Arial");
1481 lf.lfWeight = FW_NORMAL;
1482 lf.lfPitchAndFamily = DEFAULT_PITCH;
1483 lf.lfQuality = PROOF_QUALITY;
1484 hfont = CreateFontIndirect(&lf);
1487 hfont_old = SelectObject(hdc, hfont);
1488 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1489 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1491 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1493 memset(otm, 0xAA, otm_size);
1494 SetLastError(0xdeadbeef);
1495 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1496 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1497 ok(ret == 1 /* Win9x */ ||
1498 ret == otm->otmSize /* XP*/,
1499 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1500 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1502 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1503 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1504 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1505 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1508 memset(otm, 0xAA, otm_size);
1509 SetLastError(0xdeadbeef);
1510 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1511 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1512 ok(ret == 1 /* Win9x */ ||
1513 ret == otm->otmSize /* XP*/,
1514 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1515 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1517 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1518 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1519 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1520 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1523 /* ask about truncated data */
1524 memset(otm, 0xAA, otm_size);
1525 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1526 SetLastError(0xdeadbeef);
1527 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1528 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1529 ok(ret == 1 /* Win9x */ ||
1530 ret == otm->otmSize /* XP*/,
1531 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1532 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1534 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1535 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1536 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1538 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1540 HeapFree(GetProcessHeap(), 0, otm);
1542 SelectObject(hdc, hfont_old);
1543 DeleteObject(hfont);
1548 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1552 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1553 areaWidth = clientArea->right - clientArea->left,
1555 BOOL lastExtent = FALSE;
1556 PSTR pFirstChar, pLastChar;
1562 int GetTextExtentExPointWWidth;
1565 GetTextMetricsA(hdc, &tm);
1566 y = clientArea->top;
1569 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1575 /* if not at the end of the string, ... */
1576 if (*str == '\0') break;
1577 /* ... add the next word to the current extent */
1578 while (*str != '\0' && *str++ != tm.tmBreakChar);
1580 SetTextJustification(hdc, 0, 0);
1581 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1582 } while ((int) size.cx < areaWidth);
1584 /* ignore trailing break chars */
1586 while (*(pLastChar - 1) == tm.tmBreakChar)
1592 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1594 SetTextJustification(hdc, 0, 0);
1595 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1597 /* do not justify the last extent */
1598 if (*str != '\0' && breakCount > 0)
1600 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1601 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1602 justifiedWidth = size.cx;
1604 else lastExtent = TRUE;
1606 /* catch errors and report them */
1607 if (!lastExtent && (justifiedWidth != areaWidth))
1609 memset(error[nErrors].extent, 0, 100);
1610 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1611 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1617 } while (*str && y < clientArea->bottom);
1619 for (e = 0; e < nErrors; e++)
1621 /* The width returned by GetTextExtentPoint32() is exactly the same
1622 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1623 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1624 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1625 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1629 static void test_SetTextJustification(void)
1636 static char testText[] =
1637 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1638 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1639 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1640 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1641 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1642 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1643 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1645 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1646 GetClientRect( hwnd, &clientArea );
1647 hdc = GetDC( hwnd );
1649 memset(&lf, 0, sizeof lf);
1650 lf.lfCharSet = ANSI_CHARSET;
1651 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1652 lf.lfWeight = FW_DONTCARE;
1654 lf.lfQuality = DEFAULT_QUALITY;
1655 lstrcpyA(lf.lfFaceName, "Times New Roman");
1656 hfont = create_font("Times New Roman", &lf);
1657 SelectObject(hdc, hfont);
1659 testJustification(hdc, testText, &clientArea);
1661 DeleteObject(hfont);
1662 ReleaseDC(hwnd, hdc);
1663 DestroyWindow(hwnd);
1666 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1670 HFONT hfont, hfont_old;
1677 assert(count <= 128);
1679 memset(&lf, 0, sizeof(lf));
1681 lf.lfCharSet = charset;
1683 lstrcpyA(lf.lfFaceName, "Arial");
1684 SetLastError(0xdeadbeef);
1685 hfont = CreateFontIndirectA(&lf);
1686 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1689 hfont_old = SelectObject(hdc, hfont);
1691 cs = GetTextCharsetInfo(hdc, &fs, 0);
1692 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1694 SetLastError(0xdeadbeef);
1695 ret = GetTextFaceA(hdc, sizeof(name), name);
1696 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1698 if (charset == SYMBOL_CHARSET)
1700 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1701 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1705 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1706 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1709 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1711 trace("Can't find codepage for charset %d\n", cs);
1715 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1717 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1719 skip("Font code page %d, looking for code page %d\n",
1720 pGdiGetCodePage(hdc), code_page);
1728 WCHAR unicode_buf[128];
1730 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1732 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1734 SetLastError(0xdeadbeef);
1735 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1736 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1737 count, ret, GetLastError());
1743 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1745 SetLastError(0xdeadbeef);
1746 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1747 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1748 count, ret, GetLastError());
1751 SelectObject(hdc, hfont_old);
1752 DeleteObject(hfont);
1759 static void test_font_charset(void)
1761 static struct charset_data
1765 WORD font_idxA[128], font_idxW[128];
1768 { ANSI_CHARSET, 1252 },
1769 { RUSSIAN_CHARSET, 1251 },
1770 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1774 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1776 win_skip("Skipping the font charset test on a Win9x platform\n");
1780 if (!is_font_installed("Arial"))
1782 skip("Arial is not installed\n");
1786 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1788 if (cd[i].charset == SYMBOL_CHARSET)
1790 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1792 skip("Symbol or Wingdings is not installed\n");
1796 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1797 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1798 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1801 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1804 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1805 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1808 skip("Symbol or Wingdings is not installed\n");
1811 static void test_GetFontUnicodeRanges(void)
1815 HFONT hfont, hfont_old;
1819 if (!pGetFontUnicodeRanges)
1821 win_skip("GetFontUnicodeRanges not available before W2K\n");
1825 memset(&lf, 0, sizeof(lf));
1826 lstrcpyA(lf.lfFaceName, "Arial");
1827 hfont = create_font("Arial", &lf);
1830 hfont_old = SelectObject(hdc, hfont);
1832 size = pGetFontUnicodeRanges(NULL, NULL);
1833 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1835 size = pGetFontUnicodeRanges(hdc, NULL);
1836 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1838 gs = HeapAlloc(GetProcessHeap(), 0, size);
1840 size = pGetFontUnicodeRanges(hdc, gs);
1841 ok(size, "GetFontUnicodeRanges failed\n");
1843 for (i = 0; i < gs->cRanges; i++)
1844 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1846 trace("found %u ranges\n", gs->cRanges);
1848 HeapFree(GetProcessHeap(), 0, gs);
1850 SelectObject(hdc, hfont_old);
1851 DeleteObject(hfont);
1852 ReleaseDC(NULL, hdc);
1855 #define MAX_ENUM_FONTS 4096
1857 struct enum_font_data
1860 LOGFONT lf[MAX_ENUM_FONTS];
1863 struct enum_font_dataW
1866 LOGFONTW lf[MAX_ENUM_FONTS];
1869 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1871 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1873 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1875 if (type != TRUETYPE_FONTTYPE) return 1;
1877 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1878 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1880 if (efd->total < MAX_ENUM_FONTS)
1881 efd->lf[efd->total++] = *lf;
1883 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1888 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1890 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1892 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1894 if (type != TRUETYPE_FONTTYPE) return 1;
1896 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1897 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1899 if (efd->total < MAX_ENUM_FONTS)
1900 efd->lf[efd->total++] = *lf;
1902 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1907 static void get_charset_stats(struct enum_font_data *efd,
1908 int *ansi_charset, int *symbol_charset,
1909 int *russian_charset)
1914 *symbol_charset = 0;
1915 *russian_charset = 0;
1917 for (i = 0; i < efd->total; i++)
1919 switch (efd->lf[i].lfCharSet)
1924 case SYMBOL_CHARSET:
1925 (*symbol_charset)++;
1927 case RUSSIAN_CHARSET:
1928 (*russian_charset)++;
1934 static void get_charset_statsW(struct enum_font_dataW *efd,
1935 int *ansi_charset, int *symbol_charset,
1936 int *russian_charset)
1941 *symbol_charset = 0;
1942 *russian_charset = 0;
1944 for (i = 0; i < efd->total; i++)
1946 switch (efd->lf[i].lfCharSet)
1951 case SYMBOL_CHARSET:
1952 (*symbol_charset)++;
1954 case RUSSIAN_CHARSET:
1955 (*russian_charset)++;
1961 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1963 struct enum_font_data efd;
1964 struct enum_font_dataW efdw;
1967 int i, ret, ansi_charset, symbol_charset, russian_charset;
1969 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1971 if (*font_name && !is_truetype_font_installed(font_name))
1973 skip("%s is not installed\n", font_name);
1979 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1980 * while EnumFontFamiliesEx doesn't.
1982 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1985 * Use EnumFontFamiliesW since win98 crashes when the
1986 * second parameter is NULL using EnumFontFamilies
1989 SetLastError(0xdeadbeef);
1990 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1991 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1994 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1995 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1996 ansi_charset, symbol_charset, russian_charset);
1997 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1998 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1999 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2000 ok(russian_charset > 0 ||
2001 broken(russian_charset == 0), /* NT4 */
2002 "NULL family should enumerate RUSSIAN_CHARSET\n");
2006 SetLastError(0xdeadbeef);
2007 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2008 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2011 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2012 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2013 ansi_charset, symbol_charset, russian_charset);
2014 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2015 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2016 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2017 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2022 SetLastError(0xdeadbeef);
2023 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2024 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2025 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2026 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2027 ansi_charset, symbol_charset, russian_charset,
2028 *font_name ? font_name : "<empty>");
2030 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2032 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2033 for (i = 0; i < efd.total; i++)
2035 /* FIXME: remove completely once Wine is fixed */
2036 if (efd.lf[i].lfCharSet != font_charset)
2039 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2042 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2043 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2044 font_name, efd.lf[i].lfFaceName);
2047 memset(&lf, 0, sizeof(lf));
2048 lf.lfCharSet = ANSI_CHARSET;
2049 lstrcpy(lf.lfFaceName, font_name);
2051 SetLastError(0xdeadbeef);
2052 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2053 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2054 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2055 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2056 ansi_charset, symbol_charset, russian_charset,
2057 *font_name ? font_name : "<empty>");
2058 if (font_charset == SYMBOL_CHARSET)
2061 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2063 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2067 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2068 for (i = 0; i < efd.total; i++)
2070 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2072 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2073 font_name, efd.lf[i].lfFaceName);
2077 /* DEFAULT_CHARSET should enumerate all available charsets */
2078 memset(&lf, 0, sizeof(lf));
2079 lf.lfCharSet = DEFAULT_CHARSET;
2080 lstrcpy(lf.lfFaceName, font_name);
2082 SetLastError(0xdeadbeef);
2083 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2084 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2085 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2086 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2087 ansi_charset, symbol_charset, russian_charset,
2088 *font_name ? font_name : "<empty>");
2089 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2090 for (i = 0; i < efd.total; i++)
2093 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2094 font_name, efd.lf[i].lfFaceName);
2098 switch (font_charset)
2101 ok(ansi_charset > 0,
2102 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2104 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2105 ok(russian_charset > 0,
2106 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2108 case SYMBOL_CHARSET:
2110 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2112 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2113 ok(!russian_charset,
2114 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2116 case DEFAULT_CHARSET:
2117 ok(ansi_charset > 0,
2118 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2119 ok(symbol_charset > 0,
2120 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2121 ok(russian_charset > 0,
2122 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2128 ok(ansi_charset > 0,
2129 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2130 ok(symbol_charset > 0,
2131 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2132 ok(russian_charset > 0,
2133 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2136 memset(&lf, 0, sizeof(lf));
2137 lf.lfCharSet = SYMBOL_CHARSET;
2138 lstrcpy(lf.lfFaceName, font_name);
2140 SetLastError(0xdeadbeef);
2141 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2142 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2143 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2144 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2145 ansi_charset, symbol_charset, russian_charset,
2146 *font_name ? font_name : "<empty>");
2147 if (*font_name && font_charset == ANSI_CHARSET)
2148 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2151 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2152 for (i = 0; i < efd.total; i++)
2154 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2156 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2157 font_name, efd.lf[i].lfFaceName);
2161 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2162 ok(symbol_charset > 0,
2163 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2164 ok(!russian_charset,
2165 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2171 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2173 HFONT hfont, hfont_prev;
2175 GLYPHMETRICS gm1, gm2;
2178 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2180 if(!pGetGlyphIndicesA)
2183 /* negative widths are handled just as positive ones */
2184 lf2.lfWidth = -lf->lfWidth;
2186 SetLastError(0xdeadbeef);
2187 hfont = CreateFontIndirectA(lf);
2188 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2189 check_font("original", lf, hfont);
2191 hfont_prev = SelectObject(hdc, hfont);
2193 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2194 if (ret == GDI_ERROR || idx == 0xffff)
2196 SelectObject(hdc, hfont_prev);
2197 DeleteObject(hfont);
2198 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2202 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2203 memset(&gm1, 0xab, sizeof(gm1));
2204 SetLastError(0xdeadbeef);
2205 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2206 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2208 SelectObject(hdc, hfont_prev);
2209 DeleteObject(hfont);
2211 SetLastError(0xdeadbeef);
2212 hfont = CreateFontIndirectA(&lf2);
2213 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2214 check_font("negative width", &lf2, hfont);
2216 hfont_prev = SelectObject(hdc, hfont);
2218 memset(&gm2, 0xbb, sizeof(gm2));
2219 SetLastError(0xdeadbeef);
2220 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2221 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2223 SelectObject(hdc, hfont_prev);
2224 DeleteObject(hfont);
2226 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2227 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2228 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2229 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2230 gm1.gmCellIncX == gm2.gmCellIncX &&
2231 gm1.gmCellIncY == gm2.gmCellIncY,
2232 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2233 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2234 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2235 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2236 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2239 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2240 #include "pshpack2.h"
2244 SHORT xAvgCharWidth;
2245 USHORT usWeightClass;
2246 USHORT usWidthClass;
2248 SHORT ySubscriptXSize;
2249 SHORT ySubscriptYSize;
2250 SHORT ySubscriptXOffset;
2251 SHORT ySubscriptYOffset;
2252 SHORT ySuperscriptXSize;
2253 SHORT ySuperscriptYSize;
2254 SHORT ySuperscriptXOffset;
2255 SHORT ySuperscriptYOffset;
2256 SHORT yStrikeoutSize;
2257 SHORT yStrikeoutPosition;
2260 ULONG ulUnicodeRange1;
2261 ULONG ulUnicodeRange2;
2262 ULONG ulUnicodeRange3;
2263 ULONG ulUnicodeRange4;
2266 USHORT usFirstCharIndex;
2267 USHORT usLastCharIndex;
2268 /* According to the Apple spec, original version didn't have the below fields,
2269 * version numbers were taked from the OpenType spec.
2271 /* version 0 (TrueType 1.5) */
2272 USHORT sTypoAscender;
2273 USHORT sTypoDescender;
2274 USHORT sTypoLineGap;
2276 USHORT usWinDescent;
2277 /* version 1 (TrueType 1.66) */
2278 ULONG ulCodePageRange1;
2279 ULONG ulCodePageRange2;
2280 /* version 2 (OpenType 1.2) */
2283 USHORT usDefaultChar;
2285 USHORT usMaxContext;
2287 #include "poppack.h"
2289 #ifdef WORDS_BIGENDIAN
2290 #define GET_BE_WORD(x) (x)
2291 #define GET_BE_DWORD(x) (x)
2293 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2294 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2297 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2298 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2299 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2300 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2301 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2314 } cmap_encoding_record;
2322 BYTE glyph_ids[256];
2332 USHORT search_range;
2333 USHORT entry_selector;
2336 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2339 USHORT start_count[seg_countx2 / 2];
2340 USHORT id_delta[seg_countx2 / 2];
2341 USHORT id_range_offset[seg_countx2 / 2];
2351 USHORT id_range_offset;
2352 } cmap_format_4_seg;
2354 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2356 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2357 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2358 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2359 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2360 os2->panose.bWeight, os2->panose.bProportion);
2363 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2366 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2370 for(i = 0; i < 256; i++)
2372 if(cmap->glyph_ids[i] == 0) continue;
2374 if(*first == 256) *first = i;
2376 if(*first == 256) return FALSE;
2380 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2382 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2383 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2384 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2385 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2386 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2389 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2392 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2393 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2394 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2398 for(i = 0; i < seg_count; i++)
2401 cmap_format_4_seg seg;
2403 get_seg4(cmap, i, &seg);
2404 for(code = seg.start_count; code <= seg.end_count; code++)
2406 if(seg.id_range_offset == 0)
2407 index = (seg.id_delta + code) & 0xffff;
2410 index = seg.id_range_offset / 2
2411 + code - seg.start_count
2414 /* some fonts have broken last segment */
2415 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2416 index = GET_BE_WORD(glyph_ids[index]);
2419 trace("segment %04x/%04x index %04x points to nowhere\n",
2420 seg.start_count, seg.end_count, index);
2423 if(index) index += seg.id_delta;
2425 if(*first == 0x10000)
2426 *last = *first = code;
2432 if(*first == 0x10000) return FALSE;
2436 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2439 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2441 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2443 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2444 return (BYTE *)header + GET_BE_DWORD(record->offset);
2457 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2460 cmap_header *header;
2465 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2466 ok(size != GDI_ERROR, "no cmap table found\n");
2467 if(size == GDI_ERROR) return FALSE;
2469 header = HeapAlloc(GetProcessHeap(), 0, size);
2470 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2471 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2472 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2474 cmap = get_cmap(header, 3, 1);
2476 *cmap_type = cmap_ms_unicode;
2479 cmap = get_cmap(header, 3, 0);
2480 if(cmap) *cmap_type = cmap_ms_symbol;
2484 *cmap_type = cmap_none;
2488 format = GET_BE_WORD(*(WORD *)cmap);
2492 r = get_first_last_from_cmap0(cmap, first, last);
2495 r = get_first_last_from_cmap4(cmap, first, last, size);
2498 trace("unhandled cmap format %d\n", format);
2503 HeapFree(GetProcessHeap(), 0, header);
2507 static void test_text_metrics(const LOGFONTA *lf)
2510 HFONT hfont, hfont_old;
2514 const char *font_name = lf->lfFaceName;
2515 DWORD cmap_first = 0, cmap_last = 0;
2516 cmap_type cmap_type;
2517 BOOL sys_lang_non_english;
2519 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2522 SetLastError(0xdeadbeef);
2523 hfont = CreateFontIndirectA(lf);
2524 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2526 hfont_old = SelectObject(hdc, hfont);
2528 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2529 if (size == GDI_ERROR)
2531 trace("OS/2 chunk was not found\n");
2534 if (size > sizeof(tt_os2))
2536 trace("got too large OS/2 chunk of size %u\n", size);
2537 size = sizeof(tt_os2);
2540 memset(&tt_os2, 0, sizeof(tt_os2));
2541 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2542 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2544 SetLastError(0xdeadbeef);
2545 ret = GetTextMetricsA(hdc, &tmA);
2546 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2548 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2550 skip("Unable to retrieve first and last glyphs from cmap\n");
2554 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2555 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2556 UINT os2_first_char, os2_last_char, default_char, break_char;
2560 version = GET_BE_WORD(tt_os2.version);
2562 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2563 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2564 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2565 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2567 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2568 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2569 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2571 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2576 case 1257: /* Baltic */
2577 expect_last_W = 0xf8fd;
2580 expect_last_W = 0xf0ff;
2582 expect_break_W = 0x20;
2583 expect_default_W = expect_break_W - 1;
2584 expect_first_A = 0x1e;
2585 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2589 expect_first_W = cmap_first;
2590 expect_last_W = min(cmap_last, os2_last_char);
2591 if(os2_first_char <= 1)
2592 expect_break_W = os2_first_char + 2;
2593 else if(os2_first_char > 0xff)
2594 expect_break_W = 0x20;
2596 expect_break_W = os2_first_char;
2597 expect_default_W = expect_break_W - 1;
2598 expect_first_A = expect_default_W - 1;
2599 expect_last_A = min(expect_last_W, 0xff);
2601 expect_break_A = expect_break_W;
2602 expect_default_A = expect_default_W;
2604 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2605 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2606 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2607 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2608 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2610 ok(tmA.tmFirstChar == expect_first_A ||
2611 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2612 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2613 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2614 ok(tmA.tmLastChar == expect_last_A ||
2615 tmA.tmLastChar == 0xff /* win9x */,
2616 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2618 skip("tmLastChar is DBCS lead byte\n");
2619 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2620 font_name, tmA.tmBreakChar, expect_break_A);
2621 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2622 "A: tmDefaultChar for %s got %02x expected %02x\n",
2623 font_name, tmA.tmDefaultChar, expect_default_A);
2626 SetLastError(0xdeadbeef);
2627 ret = GetTextMetricsW(hdc, &tmW);
2628 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2629 "GetTextMetricsW error %u\n", GetLastError());
2632 /* Wine uses the os2 first char */
2633 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2634 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2635 font_name, tmW.tmFirstChar, expect_first_W);
2637 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2638 font_name, tmW.tmFirstChar, expect_first_W);
2640 /* Wine uses the os2 last char */
2641 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2642 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2643 font_name, tmW.tmLastChar, expect_last_W);
2645 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2646 font_name, tmW.tmLastChar, expect_last_W);
2647 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2648 font_name, tmW.tmBreakChar, expect_break_W);
2649 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2650 "W: tmDefaultChar for %s got %02x expected %02x\n",
2651 font_name, tmW.tmDefaultChar, expect_default_W);
2653 /* Test the aspect ratio while we have tmW */
2654 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2655 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2656 tmW.tmDigitizedAspectX, ret);
2657 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2658 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2659 tmW.tmDigitizedAspectX, ret);
2663 /* test FF_ values */
2664 switch(tt_os2.panose.bFamilyType)
2668 case PAN_FAMILY_TEXT_DISPLAY:
2669 case PAN_FAMILY_PICTORIAL:
2671 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2672 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2674 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2677 switch(tt_os2.panose.bSerifStyle)
2682 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2685 case PAN_SERIF_COVE:
2686 case PAN_SERIF_OBTUSE_COVE:
2687 case PAN_SERIF_SQUARE_COVE:
2688 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2689 case PAN_SERIF_SQUARE:
2690 case PAN_SERIF_THIN:
2691 case PAN_SERIF_BONE:
2692 case PAN_SERIF_EXAGGERATED:
2693 case PAN_SERIF_TRIANGLE:
2694 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2697 case PAN_SERIF_NORMAL_SANS:
2698 case PAN_SERIF_OBTUSE_SANS:
2699 case PAN_SERIF_PERP_SANS:
2700 case PAN_SERIF_FLARED:
2701 case PAN_SERIF_ROUNDED:
2702 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2707 case PAN_FAMILY_SCRIPT:
2708 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2711 case PAN_FAMILY_DECORATIVE:
2712 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2716 test_negative_width(hdc, lf);
2719 SelectObject(hdc, hfont_old);
2720 DeleteObject(hfont);
2725 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2727 INT *enumed = (INT *)lParam;
2729 if (type == TRUETYPE_FONTTYPE)
2732 test_text_metrics(lf);
2737 static void test_GetTextMetrics(void)
2743 /* Report only once */
2744 if(!pGetGlyphIndicesA)
2745 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2749 memset(&lf, 0, sizeof(lf));
2750 lf.lfCharSet = DEFAULT_CHARSET;
2752 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2753 trace("Tested metrics of %d truetype fonts\n", enumed);
2758 static void test_nonexistent_font(void)
2766 { "Times New Roman Baltic", 186 },
2767 { "Times New Roman CE", 238 },
2768 { "Times New Roman CYR", 204 },
2769 { "Times New Roman Greek", 161 },
2770 { "Times New Roman TUR", 162 }
2776 INT cs, expected_cs, i;
2777 char buf[LF_FACESIZE];
2779 if (!is_truetype_font_installed("Arial") ||
2780 !is_truetype_font_installed("Times New Roman"))
2782 skip("Arial or Times New Roman not installed\n");
2786 expected_cs = GetACP();
2787 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2789 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2792 expected_cs = csi.ciCharset;
2793 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2797 memset(&lf, 0, sizeof(lf));
2799 lf.lfWeight = FW_REGULAR;
2800 lf.lfCharSet = ANSI_CHARSET;
2801 lf.lfPitchAndFamily = FF_SWISS;
2802 strcpy(lf.lfFaceName, "Nonexistent font");
2803 hfont = CreateFontIndirectA(&lf);
2804 hfont = SelectObject(hdc, hfont);
2805 GetTextFaceA(hdc, sizeof(buf), buf);
2806 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2807 cs = GetTextCharset(hdc);
2808 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2809 DeleteObject(SelectObject(hdc, hfont));
2811 memset(&lf, 0, sizeof(lf));
2813 lf.lfWeight = FW_DONTCARE;
2814 strcpy(lf.lfFaceName, "Nonexistent font");
2815 hfont = CreateFontIndirectA(&lf);
2816 hfont = SelectObject(hdc, hfont);
2817 GetTextFaceA(hdc, sizeof(buf), buf);
2818 todo_wine /* Wine uses Arial for all substitutions */
2819 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2820 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2821 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2823 cs = GetTextCharset(hdc);
2824 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2825 DeleteObject(SelectObject(hdc, hfont));
2827 memset(&lf, 0, sizeof(lf));
2829 lf.lfWeight = FW_REGULAR;
2830 strcpy(lf.lfFaceName, "Nonexistent font");
2831 hfont = CreateFontIndirectA(&lf);
2832 hfont = SelectObject(hdc, hfont);
2833 GetTextFaceA(hdc, sizeof(buf), buf);
2834 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2835 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2836 cs = GetTextCharset(hdc);
2837 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2838 DeleteObject(SelectObject(hdc, hfont));
2840 memset(&lf, 0, sizeof(lf));
2842 lf.lfWeight = FW_DONTCARE;
2843 strcpy(lf.lfFaceName, "Times New Roman");
2844 hfont = CreateFontIndirectA(&lf);
2845 hfont = SelectObject(hdc, hfont);
2846 GetTextFaceA(hdc, sizeof(buf), buf);
2847 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2848 cs = GetTextCharset(hdc);
2849 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2850 DeleteObject(SelectObject(hdc, hfont));
2852 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2854 memset(&lf, 0, sizeof(lf));
2856 lf.lfWeight = FW_REGULAR;
2857 strcpy(lf.lfFaceName, font_subst[i].name);
2858 hfont = CreateFontIndirectA(&lf);
2859 hfont = SelectObject(hdc, hfont);
2860 cs = GetTextCharset(hdc);
2861 if (font_subst[i].charset == expected_cs)
2863 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2864 GetTextFaceA(hdc, sizeof(buf), buf);
2865 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2869 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2870 GetTextFaceA(hdc, sizeof(buf), buf);
2871 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2872 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2874 DeleteObject(SelectObject(hdc, hfont));
2876 memset(&lf, 0, sizeof(lf));
2878 lf.lfWeight = FW_DONTCARE;
2879 strcpy(lf.lfFaceName, font_subst[i].name);
2880 hfont = CreateFontIndirectA(&lf);
2881 hfont = SelectObject(hdc, hfont);
2882 GetTextFaceA(hdc, sizeof(buf), buf);
2883 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2884 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2885 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2886 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2887 "got %s for font %s\n", buf, font_subst[i].name);
2888 cs = GetTextCharset(hdc);
2889 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2890 DeleteObject(SelectObject(hdc, hfont));
2896 static void test_GdiRealizationInfo(void)
2901 HFONT hfont, hfont_old;
2904 if(!pGdiRealizationInfo)
2906 win_skip("GdiRealizationInfo not available\n");
2912 memset(info, 0xcc, sizeof(info));
2913 r = pGdiRealizationInfo(hdc, info);
2914 ok(r != 0, "ret 0\n");
2915 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2916 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2918 if (!is_truetype_font_installed("Arial"))
2920 skip("skipping GdiRealizationInfo with truetype font\n");
2924 memset(&lf, 0, sizeof(lf));
2925 strcpy(lf.lfFaceName, "Arial");
2927 lf.lfWeight = FW_NORMAL;
2928 hfont = CreateFontIndirectA(&lf);
2929 hfont_old = SelectObject(hdc, hfont);
2931 memset(info, 0xcc, sizeof(info));
2932 r = pGdiRealizationInfo(hdc, info);
2933 ok(r != 0, "ret 0\n");
2934 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2935 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2937 DeleteObject(SelectObject(hdc, hfont_old));
2943 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2944 the nul in the count of characters copied when the face name buffer is not
2945 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2946 always includes it. */
2947 static void test_GetTextFace(void)
2949 static const char faceA[] = "Tahoma";
2950 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2953 char bufA[LF_FACESIZE];
2954 WCHAR bufW[LF_FACESIZE];
2959 if(!is_font_installed("Tahoma"))
2961 skip("Tahoma is not installed so skipping this test\n");
2966 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2967 f = CreateFontIndirectA(&fA);
2968 ok(f != NULL, "CreateFontIndirectA failed\n");
2971 g = SelectObject(dc, f);
2972 n = GetTextFaceA(dc, sizeof bufA, bufA);
2973 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2974 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2976 /* Play with the count arg. */
2978 n = GetTextFaceA(dc, 0, bufA);
2979 ok(n == 0, "GetTextFaceA returned %d\n", n);
2980 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2983 n = GetTextFaceA(dc, 1, bufA);
2984 ok(n == 0, "GetTextFaceA returned %d\n", n);
2985 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2987 bufA[0] = 'x'; bufA[1] = 'y';
2988 n = GetTextFaceA(dc, 2, bufA);
2989 ok(n == 1, "GetTextFaceA returned %d\n", n);
2990 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2992 n = GetTextFaceA(dc, 0, NULL);
2993 ok(n == sizeof faceA ||
2994 broken(n == 0), /* win98, winMe */
2995 "GetTextFaceA returned %d\n", n);
2997 DeleteObject(SelectObject(dc, g));
2998 ReleaseDC(NULL, dc);
3001 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3002 SetLastError(0xdeadbeef);
3003 f = CreateFontIndirectW(&fW);
3004 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3006 win_skip("CreateFontIndirectW is not implemented\n");
3009 ok(f != NULL, "CreateFontIndirectW failed\n");
3012 g = SelectObject(dc, f);
3013 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3014 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3015 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3017 /* Play with the count arg. */
3019 n = GetTextFaceW(dc, 0, bufW);
3020 ok(n == 0, "GetTextFaceW returned %d\n", n);
3021 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3024 n = GetTextFaceW(dc, 1, bufW);
3025 ok(n == 1, "GetTextFaceW returned %d\n", n);
3026 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3028 bufW[0] = 'x'; bufW[1] = 'y';
3029 n = GetTextFaceW(dc, 2, bufW);
3030 ok(n == 2, "GetTextFaceW returned %d\n", n);
3031 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3033 n = GetTextFaceW(dc, 0, NULL);
3034 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3036 DeleteObject(SelectObject(dc, g));
3037 ReleaseDC(NULL, dc);
3040 static void test_orientation(void)
3042 static const char test_str[11] = "Test String";
3045 HFONT hfont, old_hfont;
3048 if (!is_truetype_font_installed("Arial"))
3050 skip("Arial is not installed\n");
3054 hdc = CreateCompatibleDC(0);
3055 memset(&lf, 0, sizeof(lf));
3056 lstrcpyA(lf.lfFaceName, "Arial");
3058 lf.lfOrientation = lf.lfEscapement = 900;
3059 hfont = create_font("orientation", &lf);
3060 old_hfont = SelectObject(hdc, hfont);
3061 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3062 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3063 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3064 SelectObject(hdc, old_hfont);
3065 DeleteObject(hfont);
3069 static void test_oemcharset(void)
3073 HFONT hfont, old_hfont;
3076 hdc = CreateCompatibleDC(0);
3077 ZeroMemory(&lf, sizeof(lf));
3079 lf.lfCharSet = OEM_CHARSET;
3080 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3081 lstrcpyA(lf.lfFaceName, "Terminal");
3082 hfont = CreateFontIndirectA(&lf);
3083 old_hfont = SelectObject(hdc, hfont);
3084 charset = GetTextCharset(hdc);
3086 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3087 hfont = SelectObject(hdc, old_hfont);
3088 GetObjectA(hfont, sizeof(clf), &clf);
3089 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3090 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3091 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3092 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3093 DeleteObject(hfont);
3097 static void test_GetGlyphOutline(void)
3099 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
3103 HFONT hfont, old_hfont;
3106 if (!is_truetype_font_installed("Tahoma"))
3108 skip("Tahoma is not installed\n");
3112 hdc = CreateCompatibleDC(0);
3113 memset(&lf, 0, sizeof(lf));
3115 lstrcpyA(lf.lfFaceName, "Tahoma");
3116 SetLastError(0xdeadbeef);
3117 hfont = CreateFontIndirectA(&lf);
3118 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3119 old_hfont = SelectObject(hdc, hfont);
3121 memset(&gm, 0, sizeof(gm));
3122 SetLastError(0xdeadbeef);
3123 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3124 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3126 memset(&gm, 0, sizeof(gm));
3127 SetLastError(0xdeadbeef);
3128 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3129 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3130 ok(GetLastError() == 0xdeadbeef ||
3131 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3132 "expected 0xdeadbeef, got %u\n", GetLastError());
3134 memset(&gm, 0, sizeof(gm));
3135 SetLastError(0xdeadbeef);
3136 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3137 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3138 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3140 memset(&gm, 0, sizeof(gm));
3141 SetLastError(0xdeadbeef);
3142 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3143 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3145 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3146 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3149 /* test for needed buffer size request on space char */
3150 memset(&gm, 0, sizeof(gm));
3151 SetLastError(0xdeadbeef);
3152 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3153 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3154 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3156 /* requesting buffer size for space char + error */
3157 memset(&gm, 0, sizeof(gm));
3158 SetLastError(0xdeadbeef);
3159 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3160 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3162 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3163 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3166 SelectObject(hdc, old_hfont);
3167 DeleteObject(hfont);
3171 /* bug #9995: there is a limit to the character width that can be specified */
3172 static void test_GetTextMetrics2(const char *fontname, int font_height)
3178 int ave_width, height, width, ratio, scale;
3180 if (!is_truetype_font_installed( fontname)) {
3181 skip("%s is not installed\n", fontname);
3184 hdc = CreateCompatibleDC(0);
3185 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3186 /* select width = 0 */
3187 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3188 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3189 DEFAULT_QUALITY, VARIABLE_PITCH,
3191 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3192 of = SelectObject( hdc, hf);
3193 ret = GetTextMetricsA( hdc, &tm);
3194 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3195 height = tm.tmHeight;
3196 ave_width = tm.tmAveCharWidth;
3197 SelectObject( hdc, of);
3200 trace("height %d, ave width %d\n", height, ave_width);
3202 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3204 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3205 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3206 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3207 ok(hf != 0, "CreateFont failed\n");
3208 of = SelectObject(hdc, hf);
3209 ret = GetTextMetrics(hdc, &tm);
3210 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3211 SelectObject(hdc, of);
3214 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3220 ratio = width / height;
3221 scale = width / ave_width;
3223 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3224 width, height, ratio, width, ave_width, scale);
3226 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3229 static void test_CreateFontIndirect(void)
3231 LOGFONTA lf, getobj_lf;
3234 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3236 memset(&lf, 0, sizeof(lf));
3237 lf.lfCharSet = ANSI_CHARSET;
3238 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3241 lf.lfQuality = DEFAULT_QUALITY;
3242 lf.lfItalic = FALSE;
3243 lf.lfWeight = FW_DONTCARE;
3245 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3247 lstrcpyA(lf.lfFaceName, TestName[i]);
3248 hfont = CreateFontIndirectA(&lf);
3249 ok(hfont != 0, "CreateFontIndirectA failed\n");
3250 SetLastError(0xdeadbeef);
3251 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3252 ok(ret, "GetObject failed: %d\n", GetLastError());
3253 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3254 ok(lf.lfWeight == getobj_lf.lfWeight ||
3255 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3256 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3257 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3258 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3259 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3260 DeleteObject(hfont);
3264 static void test_CreateFontIndirectEx(void)
3266 ENUMLOGFONTEXDVA lfex;
3269 if (!pCreateFontIndirectExA)
3271 win_skip("CreateFontIndirectExA is not available\n");
3275 if (!is_truetype_font_installed("Arial"))
3277 skip("Arial is not installed\n");
3281 SetLastError(0xdeadbeef);
3282 hfont = pCreateFontIndirectExA(NULL);
3283 ok(hfont == NULL, "got %p\n", hfont);
3284 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3286 memset(&lfex, 0, sizeof(lfex));
3287 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3288 hfont = pCreateFontIndirectExA(&lfex);
3289 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3291 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3292 DeleteObject(hfont);
3295 static void free_font(void *font)
3297 UnmapViewOfFile(font);
3300 static void *load_font(const char *font_name, DWORD *font_size)
3302 char file_name[MAX_PATH];
3303 HANDLE file, mapping;
3306 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3307 strcat(file_name, "\\fonts\\");
3308 strcat(file_name, font_name);
3310 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3311 if (file == INVALID_HANDLE_VALUE) return NULL;
3313 *font_size = GetFileSize(file, NULL);
3315 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3322 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3325 CloseHandle(mapping);
3329 static void test_AddFontMemResource(void)
3332 DWORD font_size, num_fonts;
3336 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3338 win_skip("AddFontMemResourceEx is not available on this platform\n");
3342 font = load_font("sserife.fon", &font_size);
3345 skip("Unable to locate and load font sserife.fon\n");
3349 SetLastError(0xdeadbeef);
3350 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3351 ok(!ret, "AddFontMemResourceEx should fail\n");
3352 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3353 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3356 SetLastError(0xdeadbeef);
3357 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3358 ok(!ret, "AddFontMemResourceEx should fail\n");
3359 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3360 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3363 SetLastError(0xdeadbeef);
3364 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3365 ok(!ret, "AddFontMemResourceEx should fail\n");
3366 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3367 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3370 SetLastError(0xdeadbeef);
3371 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3372 ok(!ret, "AddFontMemResourceEx should fail\n");
3373 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3374 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3377 SetLastError(0xdeadbeef);
3378 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3379 ok(!ret, "AddFontMemResourceEx should fail\n");
3380 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3381 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3384 SetLastError(0xdeadbeef);
3385 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3386 ok(!ret, "AddFontMemResourceEx should fail\n");
3387 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3388 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3391 num_fonts = 0xdeadbeef;
3392 SetLastError(0xdeadbeef);
3393 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3394 ok(!ret, "AddFontMemResourceEx should fail\n");
3395 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3396 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3398 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3400 if (0) /* hangs under windows 2000 */
3402 num_fonts = 0xdeadbeef;
3403 SetLastError(0xdeadbeef);
3404 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3405 ok(!ret, "AddFontMemResourceEx should fail\n");
3406 ok(GetLastError() == 0xdeadbeef,
3407 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3409 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3412 num_fonts = 0xdeadbeef;
3413 SetLastError(0xdeadbeef);
3414 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3415 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3416 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3417 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3421 SetLastError(0xdeadbeef);
3422 bRet = pRemoveFontMemResourceEx(ret);
3423 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3425 /* test invalid pointer to number of loaded fonts */
3426 font = load_font("sserife.fon", &font_size);
3427 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3429 SetLastError(0xdeadbeef);
3430 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3431 ok(!ret, "AddFontMemResourceEx should fail\n");
3432 ok(GetLastError() == 0xdeadbeef,
3433 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3436 SetLastError(0xdeadbeef);
3437 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3438 ok(!ret, "AddFontMemResourceEx should fail\n");
3439 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3440 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3452 test_outline_font();
3453 test_bitmap_font_metrics();
3454 test_GdiGetCharDimensions();
3455 test_GetCharABCWidths();
3456 test_text_extents();
3457 test_GetGlyphIndices();
3458 test_GetKerningPairs();
3459 test_GetOutlineTextMetrics();
3460 test_SetTextJustification();
3461 test_font_charset();
3462 test_GetFontUnicodeRanges();
3463 test_nonexistent_font();
3465 test_height_selection();
3466 test_AddFontMemResource();
3468 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3469 * I'd like to avoid them in this test.
3471 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3472 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3473 if (is_truetype_font_installed("Arial Black") &&
3474 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3476 test_EnumFontFamilies("", ANSI_CHARSET);
3477 test_EnumFontFamilies("", SYMBOL_CHARSET);
3478 test_EnumFontFamilies("", DEFAULT_CHARSET);
3481 skip("Arial Black or Symbol/Wingdings is not installed\n");
3482 test_GetTextMetrics();
3483 test_GdiRealizationInfo();
3485 test_GetGlyphOutline();
3486 test_GetTextMetrics2("Tahoma", -11);
3487 test_GetTextMetrics2("Tahoma", -55);
3488 test_GetTextMetrics2("Tahoma", -110);
3489 test_GetTextMetrics2("Arial", -11);
3490 test_GetTextMetrics2("Arial", -55);
3491 test_GetTextMetrics2("Arial", -110);
3492 test_CreateFontIndirect();
3493 test_CreateFontIndirectEx();