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 BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
46 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
48 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
49 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
50 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
51 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
53 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
55 static HMODULE hgdi32 = 0;
56 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
58 static void init(void)
60 hgdi32 = GetModuleHandleA("gdi32.dll");
62 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
63 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
64 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
65 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
66 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
67 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
68 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
69 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
70 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
71 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
72 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
73 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
74 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
75 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
76 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
79 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
81 if (type != TRUETYPE_FONTTYPE) return 1;
86 static BOOL is_truetype_font_installed(const char *name)
91 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
98 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
103 static BOOL is_font_installed(const char *name)
108 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
115 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
123 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
124 /* NT4 tries to be clever and only returns the minimum length */
125 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
127 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
128 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
129 ok(lf->lfHeight == getobj_lf.lfHeight ||
130 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
131 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
132 ok(lf->lfWidth == getobj_lf.lfWidth ||
133 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
134 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
135 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
136 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
137 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
138 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
139 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
140 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
141 ok(lf->lfWeight == getobj_lf.lfWeight ||
142 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
143 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
144 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
145 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
146 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
147 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
148 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
149 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
150 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
151 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
152 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
153 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
154 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
157 static HFONT create_font(const char* test, const LOGFONTA* lf)
159 HFONT hfont = CreateFontIndirectA(lf);
160 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
162 check_font(test, lf, hfont);
166 static void test_logfont(void)
171 memset(&lf, 0, sizeof lf);
173 lf.lfCharSet = ANSI_CHARSET;
174 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
175 lf.lfWeight = FW_DONTCARE;
178 lf.lfQuality = DEFAULT_QUALITY;
180 lstrcpyA(lf.lfFaceName, "Arial");
181 hfont = create_font("Arial", &lf);
184 memset(&lf, 'A', sizeof(lf));
185 hfont = CreateFontIndirectA(&lf);
186 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
188 lf.lfFaceName[LF_FACESIZE - 1] = 0;
189 check_font("AAA...", &lf, hfont);
193 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
195 if (type & RASTER_FONTTYPE)
197 LOGFONT *lf = (LOGFONT *)lParam;
199 return 0; /* stop enumeration */
202 return 1; /* continue enumeration */
205 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
207 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
208 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
209 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
210 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
211 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
212 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
213 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
214 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
215 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
216 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
217 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
218 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
219 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
220 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
221 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
222 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
223 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
224 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
225 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
226 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
229 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
230 LONG lfWidth, const char *test_str,
231 INT test_str_len, const TEXTMETRICA *tm_orig,
232 const SIZE *size_orig, INT width_of_A_orig,
233 INT scale_x, INT scale_y)
236 OUTLINETEXTMETRIC otm;
239 INT width_of_A, cx, cy;
245 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
247 GetObjectA(hfont, sizeof(lf), &lf);
249 if (GetOutlineTextMetricsA(hdc, 0, NULL))
251 otm.otmSize = sizeof(otm) / 2;
252 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253 ok(ret == sizeof(otm)/2 /* XP */ ||
254 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
256 memset(&otm, 0x1, sizeof(otm));
257 otm.otmSize = sizeof(otm);
258 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259 ok(ret == sizeof(otm) /* XP */ ||
260 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
262 memset(&tm, 0x2, sizeof(tm));
263 ret = GetTextMetricsA(hdc, &tm);
264 ok(ret, "GetTextMetricsA failed\n");
265 /* the structure size is aligned */
266 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
268 ok(0, "tm != otm\n");
269 compare_tm(&tm, &otm.otmTextMetrics);
272 tm = otm.otmTextMetrics;
273 if (0) /* these metrics are scaled too, but with rounding errors */
275 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
276 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
278 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
279 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
280 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
281 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
282 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
283 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
287 ret = GetTextMetricsA(hdc, &tm);
288 ok(ret, "GetTextMetricsA failed\n");
291 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
292 cy = tm.tmHeight / tm_orig->tmHeight;
293 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
294 lfHeight, scale_x, scale_y, cx, cy);
295 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
296 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
297 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
298 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
299 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
301 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
305 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
308 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
310 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
312 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
313 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
315 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
317 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);
320 /* Test how GDI scales bitmap font metrics */
321 static void test_bitmap_font(void)
323 static const char test_str[11] = "Test String";
326 HFONT hfont, old_hfont;
329 INT ret, i, width_orig, height_orig, scale, lfWidth;
331 hdc = CreateCompatibleDC(0);
333 /* "System" has only 1 pixel size defined, otherwise the test breaks */
334 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
338 trace("no bitmap fonts were found, skipping the test\n");
342 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
344 height_orig = bitmap_lf.lfHeight;
345 lfWidth = bitmap_lf.lfWidth;
347 hfont = create_font("bitmap", &bitmap_lf);
348 old_hfont = SelectObject(hdc, hfont);
349 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
350 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
351 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
352 SelectObject(hdc, old_hfont);
355 bitmap_lf.lfHeight = 0;
356 bitmap_lf.lfWidth = 4;
357 hfont = create_font("bitmap", &bitmap_lf);
358 old_hfont = SelectObject(hdc, hfont);
359 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
360 SelectObject(hdc, old_hfont);
363 bitmap_lf.lfHeight = height_orig;
364 bitmap_lf.lfWidth = lfWidth;
366 /* test fractional scaling */
367 for (i = 1; i <= height_orig * 6; i++)
371 bitmap_lf.lfHeight = i;
372 hfont = create_font("fractional", &bitmap_lf);
373 scale = (i + height_orig - 1) / height_orig;
374 nearest_height = scale * height_orig;
375 /* Only jump to the next height if the difference <= 25% original height */
376 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
377 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
378 so we'll not test this particular height. */
379 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
380 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
381 old_hfont = SelectObject(hdc, hfont);
382 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
383 SelectObject(hdc, old_hfont);
387 /* test integer scaling 3x2 */
388 bitmap_lf.lfHeight = height_orig * 2;
389 bitmap_lf.lfWidth *= 3;
390 hfont = create_font("3x2", &bitmap_lf);
391 old_hfont = SelectObject(hdc, hfont);
392 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
393 SelectObject(hdc, old_hfont);
396 /* test integer scaling 3x3 */
397 bitmap_lf.lfHeight = height_orig * 3;
398 bitmap_lf.lfWidth = 0;
399 hfont = create_font("3x3", &bitmap_lf);
400 old_hfont = SelectObject(hdc, hfont);
401 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
402 SelectObject(hdc, old_hfont);
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
411 static const char test_str[11] = "Test String";
414 HFONT hfont, old_hfont, old_hfont_2;
415 OUTLINETEXTMETRICA otm;
417 INT width_orig, height_orig, lfWidth;
420 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
424 if (!is_truetype_font_installed("Arial"))
426 skip("Arial is not installed\n");
430 hdc = CreateCompatibleDC(0);
432 memset(&lf, 0, sizeof(lf));
433 strcpy(lf.lfFaceName, "Arial");
435 hfont = create_font("outline", &lf);
436 old_hfont = SelectObject(hdc, hfont);
437 otm.otmSize = sizeof(otm);
438 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
442 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
443 SelectObject(hdc, old_hfont);
446 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
447 lf.lfHeight = otm.otmEMSquare;
448 lf.lfHeight = -lf.lfHeight;
449 hfont = create_font("outline", &lf);
450 old_hfont = SelectObject(hdc, hfont);
451 otm.otmSize = sizeof(otm);
452 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
453 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
454 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
455 SelectObject(hdc, old_hfont);
458 height_orig = otm.otmTextMetrics.tmHeight;
459 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
461 /* test integer scaling 3x2 */
462 lf.lfHeight = height_orig * 2;
463 lf.lfWidth = lfWidth * 3;
464 hfont = create_font("3x2", &lf);
465 old_hfont = SelectObject(hdc, hfont);
466 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
467 SelectObject(hdc, old_hfont);
470 /* test integer scaling 3x3 */
471 lf.lfHeight = height_orig * 3;
472 lf.lfWidth = lfWidth * 3;
473 hfont = create_font("3x3", &lf);
474 old_hfont = SelectObject(hdc, hfont);
475 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
476 SelectObject(hdc, old_hfont);
479 /* test integer scaling 1x1 */
480 lf.lfHeight = height_orig * 1;
481 lf.lfWidth = lfWidth * 1;
482 hfont = create_font("1x1", &lf);
483 old_hfont = SelectObject(hdc, hfont);
484 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 SelectObject(hdc, old_hfont);
488 /* test integer scaling 1x1 */
489 lf.lfHeight = height_orig;
491 hfont = create_font("1x1", &lf);
492 old_hfont = SelectObject(hdc, hfont);
493 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
495 /* with an identity matrix */
496 memset(&gm, 0, sizeof(gm));
497 SetLastError(0xdeadbeef);
498 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
499 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
500 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
501 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
502 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
503 /* with a custom matrix */
504 memset(&gm, 0, sizeof(gm));
505 SetLastError(0xdeadbeef);
506 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
507 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
508 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
509 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
510 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
512 /* Test that changing the DC transformation affects only the font
513 * selected on this DC and doesn't affect the same font selected on
516 hdc_2 = CreateCompatibleDC(0);
517 old_hfont_2 = SelectObject(hdc_2, hfont);
518 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
520 SetMapMode(hdc, MM_ANISOTROPIC);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* test restrictions of compatibility mode GM_COMPATIBLE */
526 /* part 1: rescaling only X should not change font scaling on screen.
527 So compressing the X axis by 2 is not done, and this
528 appears as X scaling of 2 that no one requested. */
529 SetWindowExtEx(hdc, 100, 100, NULL);
530 SetViewportExtEx(hdc, 50, 100, NULL);
531 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
532 /* font metrics on another DC should be unchanged */
533 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
535 /* part 2: rescaling only Y should change font scaling.
536 As also X is scaled by a factor of 2, but this is not
537 requested by the DC transformation, we get a scaling factor
538 of 2 in the X coordinate. */
539 SetViewportExtEx(hdc, 100, 200, NULL);
540 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
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 /* restore scaling */
545 SetMapMode(hdc, MM_TEXT);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
550 SelectObject(hdc_2, old_hfont_2);
553 if (!SetGraphicsMode(hdc, GM_ADVANCED))
555 SelectObject(hdc, old_hfont);
558 skip("GM_ADVANCED is not supported on this platform\n");
569 SetLastError(0xdeadbeef);
570 ret = SetWorldTransform(hdc, &xform);
571 ok(ret, "SetWorldTransform error %u\n", GetLastError());
573 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
575 /* with an identity matrix */
576 memset(&gm, 0, sizeof(gm));
577 SetLastError(0xdeadbeef);
578 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581 pt.x = width_orig; pt.y = 0;
583 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
584 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
585 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
586 /* with a custom matrix */
587 memset(&gm, 0, sizeof(gm));
588 SetLastError(0xdeadbeef);
589 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
590 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
591 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
592 pt.x = width_orig; pt.y = 0;
594 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
595 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
596 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598 SetLastError(0xdeadbeef);
599 ret = SetMapMode(hdc, MM_LOMETRIC);
600 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
604 /* with an identity matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
612 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
614 /* with a custom matrix */
615 memset(&gm, 0, sizeof(gm));
616 SetLastError(0xdeadbeef);
617 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
618 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
619 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
620 pt.x = width_orig; pt.y = 0;
622 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
623 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
625 SetLastError(0xdeadbeef);
626 ret = SetMapMode(hdc, MM_TEXT);
627 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
629 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
631 /* with an identity matrix */
632 memset(&gm, 0, sizeof(gm));
633 SetLastError(0xdeadbeef);
634 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
635 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
636 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
637 pt.x = width_orig; pt.y = 0;
639 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
640 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
641 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
642 /* with a custom matrix */
643 memset(&gm, 0, sizeof(gm));
644 SetLastError(0xdeadbeef);
645 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
646 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
647 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
648 pt.x = width_orig; pt.y = 0;
650 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
651 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
652 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
654 SelectObject(hdc, old_hfont);
659 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
661 LOGFONT *lf = (LOGFONT *)lParam;
663 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
666 return 0; /* stop enumeration */
668 return 1; /* continue enumeration */
671 #define FH_SCALE 0x80000000
672 static void test_bitmap_font_metrics(void)
674 static const struct font_data
676 const char face_name[LF_FACESIZE];
677 int weight, height, ascent, descent, int_leading, ext_leading;
678 int ave_char_width, max_char_width, dpi;
679 BYTE first_char, last_char, def_char, break_char;
685 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
686 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
687 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
688 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
689 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
690 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
691 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
692 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
693 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
694 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
696 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
697 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
698 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
699 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
700 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
701 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
702 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
703 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
704 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
705 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
707 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
708 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
709 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
710 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
711 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
712 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
713 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
714 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
715 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
716 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
717 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
718 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
719 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
720 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
721 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
722 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
724 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
725 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
726 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
727 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
728 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
729 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
730 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
731 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
732 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
733 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
734 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
735 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
737 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
739 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
740 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
741 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
742 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
743 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
744 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
745 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
746 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
747 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
748 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
749 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
750 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
751 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
752 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
753 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
755 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
756 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
757 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
758 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
759 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
760 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
761 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
762 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
763 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
764 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
765 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
767 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
768 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
769 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
771 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
772 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
773 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
775 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
776 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
777 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
779 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
780 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
782 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
783 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
784 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN },
785 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
786 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
787 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN },
788 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
789 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
790 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC },
791 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN },
792 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
793 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
794 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC },
795 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN },
796 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
797 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
798 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC },
799 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN },
800 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
801 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC },
802 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN },
804 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
805 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
806 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
807 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
808 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
809 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
810 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
811 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
812 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
813 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
814 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
815 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
817 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
818 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
819 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
821 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
823 /* FIXME: add "Terminal" */
825 static const int font_log_pixels[] = { 96, 120 };
828 HFONT hfont, old_hfont;
830 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
832 char face_name[LF_FACESIZE];
835 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
836 trace("system language id %04x\n", system_lang_id);
838 expected_cs = GetACP();
839 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
841 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
844 expected_cs = csi.ciCharset;
845 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
847 hdc = CreateCompatibleDC(0);
850 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
851 GetDeviceCaps(hdc, LOGPIXELSY));
853 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
856 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
858 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
862 font_res = font_log_pixels[i];
865 trace("best font resolution is %d\n", font_res);
867 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
871 memset(&lf, 0, sizeof(lf));
873 height = fd[i].height & ~FH_SCALE;
874 lf.lfHeight = height;
875 strcpy(lf.lfFaceName, fd[i].face_name);
877 for(bit = 0; bit < 32; bit++)
885 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
886 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
888 lf.lfCharSet = csi.ciCharset;
889 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
890 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
891 if (fd[i].height & FH_SCALE)
892 ok(ret, "scaled font height %d should not be enumerated\n", height);
895 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
897 if (ret) /* FIXME: Remove once Wine is fixed */
898 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
900 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
903 if (ret && !(fd[i].height & FH_SCALE))
906 hfont = create_font(lf.lfFaceName, &lf);
907 old_hfont = SelectObject(hdc, hfont);
909 SetLastError(0xdeadbeef);
910 ret = GetTextFace(hdc, sizeof(face_name), face_name);
911 ok(ret, "GetTextFace error %u\n", GetLastError());
913 if (lstrcmp(face_name, fd[i].face_name) != 0)
915 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
916 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
917 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
918 SelectObject(hdc, old_hfont);
923 memset(&gm, 0, sizeof(gm));
924 SetLastError(0xdeadbeef);
925 ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
927 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
928 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
931 bRet = GetTextMetrics(hdc, &tm);
932 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
934 SetLastError(0xdeadbeef);
935 ret = GetTextCharset(hdc);
936 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
938 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
939 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
941 if(fd[i].dpi == tm.tmDigitizedAspectX)
943 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
944 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
946 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
947 if (fd[i].height & FH_SCALE)
948 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
950 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);
951 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
952 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
953 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
954 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
955 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
956 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
957 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
958 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
959 make default char test fail */
960 if (tm.tmCharSet == lf.lfCharSet)
961 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
962 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
963 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
965 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
966 that make the max width bigger */
967 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
968 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
971 skip("Skipping font metrics test for system langid 0x%x\n",
974 SelectObject(hdc, old_hfont);
982 static void test_GdiGetCharDimensions(void)
988 LONG avgwidth, height;
989 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
991 if (!pGdiGetCharDimensions)
993 win_skip("GdiGetCharDimensions not available on this platform\n");
997 hdc = CreateCompatibleDC(NULL);
999 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1000 avgwidth = ((size.cx / 26) + 1) / 2;
1002 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1003 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1004 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1006 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1007 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1009 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1010 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1013 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1014 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1015 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1020 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1021 const TEXTMETRIC *lpntme,
1022 DWORD FontType, LPARAM lParam)
1024 if (FontType & TRUETYPE_FONTTYPE)
1028 hfont = CreateFontIndirect(lpelfe);
1031 *(HFONT *)lParam = hfont;
1039 static void test_GetCharABCWidths(void)
1041 static const WCHAR str[] = {'a',0};
1063 {0xffffff, 0xffffff},
1064 {0x1000000, 0x1000000},
1065 {0xffffff, 0x1000000},
1066 {0xffffffff, 0xffffffff},
1074 BOOL r[sizeof range / sizeof range[0]];
1077 {ANSI_CHARSET, 0x30, 0x30,
1078 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1079 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1080 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1081 {HANGEUL_CHARSET, 0x8141, 0xac02,
1082 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1083 {JOHAB_CHARSET, 0x8446, 0x3135,
1084 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1085 {GB2312_CHARSET, 0x8141, 0x4e04,
1086 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1087 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1088 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1092 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1094 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1098 memset(&lf, 0, sizeof(lf));
1099 strcpy(lf.lfFaceName, "System");
1102 hfont = CreateFontIndirectA(&lf);
1104 hfont = SelectObject(hdc, hfont);
1106 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1107 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1109 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1110 ok(!ret, "GetCharABCWidthsI should have failed\n");
1112 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1113 ok(!ret, "GetCharABCWidthsI should have failed\n");
1115 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1116 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1118 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1119 ok(!ret, "GetCharABCWidthsW should have failed\n");
1121 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1122 ok(!ret, "GetCharABCWidthsW should have failed\n");
1124 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1125 ok(!ret, "GetCharABCWidthsW should have failed\n");
1127 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1128 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1130 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1131 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1133 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1134 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1136 hfont = SelectObject(hdc, hfont);
1137 DeleteObject(hfont);
1139 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1143 UINT code = 0x41, j;
1145 lf.lfFaceName[0] = '\0';
1146 lf.lfCharSet = c[i].cs;
1147 lf.lfPitchAndFamily = 0;
1148 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1150 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1154 memset(a, 0, sizeof a);
1155 memset(w, 0, sizeof w);
1156 hfont = SelectObject(hdc, hfont);
1157 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1158 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1159 memcmp(a, w, sizeof a) == 0,
1160 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1162 memset(a, 0xbb, sizeof a);
1163 ret = pGetCharABCWidthsA(hdc, code, code, a);
1164 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1165 memset(full, 0xcc, sizeof full);
1166 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1167 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1168 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1169 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1171 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1173 memset(full, 0xdd, sizeof full);
1174 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1175 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1176 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1179 UINT last = range[j].last - range[j].first;
1180 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1181 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1182 "GetCharABCWidthsA %x should match. codepage = %u\n",
1183 range[j].last, c[i].cs);
1187 hfont = SelectObject(hdc, hfont);
1188 DeleteObject(hfont);
1191 ReleaseDC(NULL, hdc);
1194 static void test_text_extents(void)
1196 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1198 INT i, len, fit1, fit2;
1207 memset(&lf, 0, sizeof(lf));
1208 strcpy(lf.lfFaceName, "Arial");
1211 hfont = CreateFontIndirectA(&lf);
1213 hfont = SelectObject(hdc, hfont);
1214 GetTextMetricsA(hdc, &tm);
1215 GetTextExtentPointA(hdc, "o", 1, &sz);
1216 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1218 SetLastError(0xdeadbeef);
1219 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1220 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1222 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1223 hfont = SelectObject(hdc, hfont);
1224 DeleteObject(hfont);
1230 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1231 extents[0] = 1; /* So that the increasing sequence test will fail
1232 if the extents array is untouched. */
1233 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1234 GetTextExtentPointW(hdc, wt, len, &sz2);
1235 ok(sz1.cy == sz2.cy,
1236 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1237 /* Because of the '\n' in the string GetTextExtentExPoint and
1238 GetTextExtentPoint return different widths under Win2k, but
1239 under WinXP they return the same width. So we don't test that
1242 for (i = 1; i < len; ++i)
1243 ok(extents[i-1] <= extents[i],
1244 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1246 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1247 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1248 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1249 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1250 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1251 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1252 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1253 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1254 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1255 ok(extents[0] == extents[2] && extents[1] == extents[3],
1256 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1257 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1258 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1259 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1260 HeapFree(GetProcessHeap(), 0, extents);
1262 /* extents functions fail with -ve counts (the interesting case being -1) */
1263 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1264 ok(ret == FALSE, "got %d\n", ret);
1265 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1266 ok(ret == FALSE, "got %d\n", ret);
1267 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1268 ok(ret == FALSE, "got %d\n", ret);
1270 /* max_extent = 0 succeeds and returns zero */
1272 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1274 broken(ret == FALSE), /* NT4, 2k */
1277 broken(fit1 == -215), /* NT4, 2k */
1278 "fit = %d\n", fit1);
1279 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1280 ok(ret == TRUE, "got %d\n", ret);
1281 ok(fit2 == 0, "fit = %d\n", fit2);
1283 /* max_extent = -1 is interpreted as a very large width that will
1284 * definitely fit our three characters */
1286 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1287 ok(ret == TRUE, "got %d\n", ret);
1288 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1289 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1290 ok(ret == TRUE, "got %d\n", ret);
1291 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1293 /* max_extent = -2 is interpreted similarly, but the Ansi version
1294 * rejects it while the Unicode one accepts it */
1296 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1297 todo_wine ok(ret == FALSE, "got %d\n", ret);
1298 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1299 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1300 ok(ret == TRUE, "got %d\n", ret);
1301 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1303 hfont = SelectObject(hdc, hfont);
1304 DeleteObject(hfont);
1305 ReleaseDC(NULL, hdc);
1308 static void test_GetGlyphIndices(void)
1315 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1316 WORD glyphs[(sizeof(testtext)/2)-1];
1320 if (!pGetGlyphIndicesW) {
1321 win_skip("GetGlyphIndicesW not available on platform\n");
1327 memset(&lf, 0, sizeof(lf));
1328 strcpy(lf.lfFaceName, "System");
1330 lf.lfCharSet = ANSI_CHARSET;
1332 hfont = CreateFontIndirectA(&lf);
1333 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1334 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1335 if (textm.tmCharSet == ANSI_CHARSET)
1337 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1338 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1339 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1340 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1342 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1343 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1344 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1345 textm.tmDefaultChar, glyphs[4]);
1348 /* FIXME: Write tests for non-ANSI charsets. */
1349 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1351 if(!is_font_installed("Tahoma"))
1353 skip("Tahoma is not installed so skipping this test\n");
1356 memset(&lf, 0, sizeof(lf));
1357 strcpy(lf.lfFaceName, "Tahoma");
1360 hfont = CreateFontIndirectA(&lf);
1361 hOldFont = SelectObject(hdc, hfont);
1362 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1363 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1364 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1365 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1366 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1368 testtext[0] = textm.tmDefaultChar;
1369 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1370 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1371 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1372 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1373 DeleteObject(SelectObject(hdc, hOldFont));
1376 static void test_GetKerningPairs(void)
1378 static const struct kerning_data
1380 const char face_name[LF_FACESIZE];
1382 /* some interesting fields from OUTLINETEXTMETRIC */
1383 LONG tmHeight, tmAscent, tmDescent;
1388 UINT otmsCapEmHeight;
1393 UINT otmusMinimumPPEM;
1394 /* small subset of kerning pairs to test */
1395 DWORD total_kern_pairs;
1396 const KERNINGPAIR kern_pair[26];
1399 {"Arial", 12, 12, 9, 3,
1400 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1403 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1404 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1405 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1406 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1407 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1408 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1409 {933,970,+1},{933,972,-1}
1412 {"Arial", -34, 39, 32, 7,
1413 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1416 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1417 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1418 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1419 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1420 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1421 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1422 {933,970,+2},{933,972,-3}
1425 { "Arial", 120, 120, 97, 23,
1426 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1429 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1430 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1431 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1432 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1433 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1434 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1435 {933,970,+6},{933,972,-10}
1438 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1439 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1440 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1443 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1444 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1445 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1446 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1447 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1448 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1449 {933,970,+54},{933,972,-83}
1455 HFONT hfont, hfont_old;
1456 KERNINGPAIR *kern_pair;
1458 DWORD total_kern_pairs, ret, i, n, matches;
1462 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1463 * which may render this test unusable, so we're trying to avoid that.
1465 SetLastError(0xdeadbeef);
1466 GetKerningPairsW(hdc, 0, NULL);
1467 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1469 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1474 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1476 OUTLINETEXTMETRICW otm;
1479 if (!is_font_installed(kd[i].face_name))
1481 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1485 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1487 memset(&lf, 0, sizeof(lf));
1488 strcpy(lf.lfFaceName, kd[i].face_name);
1489 lf.lfHeight = kd[i].height;
1490 hfont = CreateFontIndirect(&lf);
1493 hfont_old = SelectObject(hdc, hfont);
1495 SetLastError(0xdeadbeef);
1496 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1497 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1498 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1500 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1501 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1502 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1503 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1504 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1505 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1507 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1508 kd[i].otmEMSquare, otm.otmEMSquare);
1509 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1510 kd[i].otmAscent, otm.otmAscent);
1511 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1512 kd[i].otmDescent, otm.otmDescent);
1513 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1514 kd[i].otmLineGap, otm.otmLineGap);
1515 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1516 kd[i].otmMacDescent, otm.otmMacDescent);
1517 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1518 kd[i].otmMacAscent, otm.otmMacAscent);
1520 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1521 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1522 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1523 kd[i].otmsXHeight, otm.otmsXHeight);
1524 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1525 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1526 kd[i].otmMacLineGap, otm.otmMacLineGap);
1527 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1528 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1531 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1532 trace("total_kern_pairs %u\n", total_kern_pairs);
1533 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1535 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1538 SetLastError(0xdeadbeef);
1539 ret = GetKerningPairsW(hdc, 0, kern_pair);
1540 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1541 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1542 ok(ret == 0, "got %u, expected 0\n", ret);
1544 ret = GetKerningPairsW(hdc, 100, NULL);
1545 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1547 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1548 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1550 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1551 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1555 for (n = 0; n < ret; n++)
1558 /* Disabled to limit console spam */
1559 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1560 trace("{'%c','%c',%d},\n",
1561 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1562 for (j = 0; j < kd[i].total_kern_pairs; j++)
1564 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1565 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1567 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1568 "pair %d:%d got %d, expected %d\n",
1569 kern_pair[n].wFirst, kern_pair[n].wSecond,
1570 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1576 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1577 matches, kd[i].total_kern_pairs);
1579 HeapFree(GetProcessHeap(), 0, kern_pair);
1581 SelectObject(hdc, hfont_old);
1582 DeleteObject(hfont);
1588 static void test_height_selection(void)
1590 static const struct font_data
1592 const char face_name[LF_FACESIZE];
1593 int requested_height;
1594 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1597 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1598 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1599 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1600 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1601 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1602 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1603 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1604 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1605 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1606 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1610 HFONT hfont, old_hfont;
1614 hdc = CreateCompatibleDC(0);
1617 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1619 if (!is_truetype_font_installed(fd[i].face_name))
1621 skip("%s is not installed\n", fd[i].face_name);
1625 memset(&lf, 0, sizeof(lf));
1626 lf.lfHeight = fd[i].requested_height;
1627 lf.lfWeight = fd[i].weight;
1628 strcpy(lf.lfFaceName, fd[i].face_name);
1630 hfont = CreateFontIndirect(&lf);
1633 old_hfont = SelectObject(hdc, hfont);
1634 ret = GetTextMetrics(hdc, &tm);
1635 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1636 if(fd[i].dpi == tm.tmDigitizedAspectX)
1638 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1639 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);
1640 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);
1641 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);
1642 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);
1643 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1644 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);
1646 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);
1649 SelectObject(hdc, old_hfont);
1650 DeleteObject(hfont);
1656 static void test_GetOutlineTextMetrics(void)
1658 OUTLINETEXTMETRIC *otm;
1660 HFONT hfont, hfont_old;
1662 DWORD ret, otm_size;
1665 if (!is_font_installed("Arial"))
1667 skip("Arial is not installed\n");
1673 memset(&lf, 0, sizeof(lf));
1674 strcpy(lf.lfFaceName, "Arial");
1676 lf.lfWeight = FW_NORMAL;
1677 lf.lfPitchAndFamily = DEFAULT_PITCH;
1678 lf.lfQuality = PROOF_QUALITY;
1679 hfont = CreateFontIndirect(&lf);
1682 hfont_old = SelectObject(hdc, hfont);
1683 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1684 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1686 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1688 memset(otm, 0xAA, otm_size);
1689 SetLastError(0xdeadbeef);
1690 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1691 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1692 ok(ret == 1 /* Win9x */ ||
1693 ret == otm->otmSize /* XP*/,
1694 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1695 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1697 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1698 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1699 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1700 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1703 memset(otm, 0xAA, otm_size);
1704 SetLastError(0xdeadbeef);
1705 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1706 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1707 ok(ret == 1 /* Win9x */ ||
1708 ret == otm->otmSize /* XP*/,
1709 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1710 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1712 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1713 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1714 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1715 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1718 /* ask about truncated data */
1719 memset(otm, 0xAA, otm_size);
1720 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1721 SetLastError(0xdeadbeef);
1722 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1723 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1724 ok(ret == 1 /* Win9x */ ||
1725 ret == otm->otmSize /* XP*/,
1726 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1727 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1729 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1730 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1731 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1733 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1735 HeapFree(GetProcessHeap(), 0, otm);
1737 SelectObject(hdc, hfont_old);
1738 DeleteObject(hfont);
1743 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1747 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1748 areaWidth = clientArea->right - clientArea->left,
1750 BOOL lastExtent = FALSE;
1751 PSTR pFirstChar, pLastChar;
1757 int GetTextExtentExPointWWidth;
1760 GetTextMetricsA(hdc, &tm);
1761 y = clientArea->top;
1764 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1770 /* if not at the end of the string, ... */
1771 if (*str == '\0') break;
1772 /* ... add the next word to the current extent */
1773 while (*str != '\0' && *str++ != tm.tmBreakChar);
1775 SetTextJustification(hdc, 0, 0);
1776 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1777 } while ((int) size.cx < areaWidth);
1779 /* ignore trailing break chars */
1781 while (*(pLastChar - 1) == tm.tmBreakChar)
1787 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1789 SetTextJustification(hdc, 0, 0);
1790 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1792 /* do not justify the last extent */
1793 if (*str != '\0' && breakCount > 0)
1795 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1796 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1797 justifiedWidth = size.cx;
1799 else lastExtent = TRUE;
1801 /* catch errors and report them */
1802 if (!lastExtent && (justifiedWidth != areaWidth))
1804 memset(error[nErrors].extent, 0, 100);
1805 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1806 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1812 } while (*str && y < clientArea->bottom);
1814 for (e = 0; e < nErrors; e++)
1816 /* The width returned by GetTextExtentPoint32() is exactly the same
1817 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1818 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1819 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1820 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1824 static void test_SetTextJustification(void)
1831 static char testText[] =
1832 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1833 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1834 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1835 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1836 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1837 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1838 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1840 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1841 GetClientRect( hwnd, &clientArea );
1842 hdc = GetDC( hwnd );
1844 memset(&lf, 0, sizeof lf);
1845 lf.lfCharSet = ANSI_CHARSET;
1846 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1847 lf.lfWeight = FW_DONTCARE;
1849 lf.lfQuality = DEFAULT_QUALITY;
1850 lstrcpyA(lf.lfFaceName, "Times New Roman");
1851 hfont = create_font("Times New Roman", &lf);
1852 SelectObject(hdc, hfont);
1854 testJustification(hdc, testText, &clientArea);
1856 DeleteObject(hfont);
1857 ReleaseDC(hwnd, hdc);
1858 DestroyWindow(hwnd);
1861 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1865 HFONT hfont, hfont_old;
1872 assert(count <= 128);
1874 memset(&lf, 0, sizeof(lf));
1876 lf.lfCharSet = charset;
1878 lstrcpyA(lf.lfFaceName, "Arial");
1879 SetLastError(0xdeadbeef);
1880 hfont = CreateFontIndirectA(&lf);
1881 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1884 hfont_old = SelectObject(hdc, hfont);
1886 cs = GetTextCharsetInfo(hdc, &fs, 0);
1887 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1889 SetLastError(0xdeadbeef);
1890 ret = GetTextFaceA(hdc, sizeof(name), name);
1891 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1893 if (charset == SYMBOL_CHARSET)
1895 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1896 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1900 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1901 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1904 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1906 trace("Can't find codepage for charset %d\n", cs);
1910 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1912 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1914 skip("Font code page %d, looking for code page %d\n",
1915 pGdiGetCodePage(hdc), code_page);
1923 WCHAR unicode_buf[128];
1925 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1927 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1929 SetLastError(0xdeadbeef);
1930 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1931 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1932 count, ret, GetLastError());
1938 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1940 SetLastError(0xdeadbeef);
1941 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1942 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1943 count, ret, GetLastError());
1946 SelectObject(hdc, hfont_old);
1947 DeleteObject(hfont);
1954 static void test_font_charset(void)
1956 static struct charset_data
1960 WORD font_idxA[128], font_idxW[128];
1963 { ANSI_CHARSET, 1252 },
1964 { RUSSIAN_CHARSET, 1251 },
1965 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1969 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1971 win_skip("Skipping the font charset test on a Win9x platform\n");
1975 if (!is_font_installed("Arial"))
1977 skip("Arial is not installed\n");
1981 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1983 if (cd[i].charset == SYMBOL_CHARSET)
1985 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1987 skip("Symbol or Wingdings is not installed\n");
1991 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1992 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1993 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1996 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1999 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2000 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2003 skip("Symbol or Wingdings is not installed\n");
2006 static void test_GetFontUnicodeRanges(void)
2010 HFONT hfont, hfont_old;
2015 if (!pGetFontUnicodeRanges)
2017 win_skip("GetFontUnicodeRanges not available before W2K\n");
2021 memset(&lf, 0, sizeof(lf));
2022 lstrcpyA(lf.lfFaceName, "Arial");
2023 hfont = create_font("Arial", &lf);
2026 hfont_old = SelectObject(hdc, hfont);
2028 size = pGetFontUnicodeRanges(NULL, NULL);
2029 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2031 size = pGetFontUnicodeRanges(hdc, NULL);
2032 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2034 gs = HeapAlloc(GetProcessHeap(), 0, size);
2036 size = pGetFontUnicodeRanges(hdc, gs);
2037 ok(size, "GetFontUnicodeRanges failed\n");
2039 if (0) /* Disabled to limit console spam */
2040 for (i = 0; i < gs->cRanges; i++)
2041 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2042 trace("found %u ranges\n", gs->cRanges);
2044 HeapFree(GetProcessHeap(), 0, gs);
2046 SelectObject(hdc, hfont_old);
2047 DeleteObject(hfont);
2048 ReleaseDC(NULL, hdc);
2051 #define MAX_ENUM_FONTS 4096
2053 struct enum_font_data
2056 LOGFONT lf[MAX_ENUM_FONTS];
2059 struct enum_fullname_data
2062 ENUMLOGFONT elf[MAX_ENUM_FONTS];
2065 struct enum_font_dataW
2068 LOGFONTW lf[MAX_ENUM_FONTS];
2071 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2073 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2074 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2076 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2077 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2079 if (type != TRUETYPE_FONTTYPE) return 1;
2081 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2083 if (0) /* Disabled to limit console spam */
2084 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2085 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2086 if (efd->total < MAX_ENUM_FONTS)
2087 efd->lf[efd->total++] = *lf;
2089 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2094 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2096 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2097 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2099 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2100 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2102 if (type != TRUETYPE_FONTTYPE) return 1;
2104 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2106 if (0) /* Disabled to limit console spam */
2107 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2108 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2109 if (efd->total < MAX_ENUM_FONTS)
2110 efd->lf[efd->total++] = *lf;
2112 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2117 static void get_charset_stats(struct enum_font_data *efd,
2118 int *ansi_charset, int *symbol_charset,
2119 int *russian_charset)
2124 *symbol_charset = 0;
2125 *russian_charset = 0;
2127 for (i = 0; i < efd->total; i++)
2129 switch (efd->lf[i].lfCharSet)
2134 case SYMBOL_CHARSET:
2135 (*symbol_charset)++;
2137 case RUSSIAN_CHARSET:
2138 (*russian_charset)++;
2144 static void get_charset_statsW(struct enum_font_dataW *efd,
2145 int *ansi_charset, int *symbol_charset,
2146 int *russian_charset)
2151 *symbol_charset = 0;
2152 *russian_charset = 0;
2154 for (i = 0; i < efd->total; i++)
2156 switch (efd->lf[i].lfCharSet)
2161 case SYMBOL_CHARSET:
2162 (*symbol_charset)++;
2164 case RUSSIAN_CHARSET:
2165 (*russian_charset)++;
2171 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2173 struct enum_font_data efd;
2174 struct enum_font_dataW efdw;
2177 int i, ret, ansi_charset, symbol_charset, russian_charset;
2179 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2181 if (*font_name && !is_truetype_font_installed(font_name))
2183 skip("%s is not installed\n", font_name);
2189 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2190 * while EnumFontFamiliesEx doesn't.
2192 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2195 * Use EnumFontFamiliesW since win98 crashes when the
2196 * second parameter is NULL using EnumFontFamilies
2199 SetLastError(0xdeadbeef);
2200 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2201 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2204 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2205 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2206 ansi_charset, symbol_charset, russian_charset);
2207 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2208 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2209 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2210 ok(russian_charset > 0 ||
2211 broken(russian_charset == 0), /* NT4 */
2212 "NULL family should enumerate RUSSIAN_CHARSET\n");
2216 SetLastError(0xdeadbeef);
2217 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2218 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2221 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2222 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2223 ansi_charset, symbol_charset, russian_charset);
2224 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2225 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2226 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2227 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2232 SetLastError(0xdeadbeef);
2233 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2234 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2235 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2236 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2237 ansi_charset, symbol_charset, russian_charset,
2238 *font_name ? font_name : "<empty>");
2240 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2242 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2243 for (i = 0; i < efd.total; i++)
2245 /* FIXME: remove completely once Wine is fixed */
2246 if (efd.lf[i].lfCharSet != font_charset)
2249 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2252 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2253 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2254 font_name, efd.lf[i].lfFaceName);
2257 memset(&lf, 0, sizeof(lf));
2258 lf.lfCharSet = ANSI_CHARSET;
2259 lstrcpy(lf.lfFaceName, font_name);
2261 SetLastError(0xdeadbeef);
2262 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2263 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2264 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2265 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2266 ansi_charset, symbol_charset, russian_charset,
2267 *font_name ? font_name : "<empty>");
2268 if (font_charset == SYMBOL_CHARSET)
2271 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2273 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2277 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2278 for (i = 0; i < efd.total; i++)
2280 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2282 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2283 font_name, efd.lf[i].lfFaceName);
2287 /* DEFAULT_CHARSET should enumerate all available charsets */
2288 memset(&lf, 0, sizeof(lf));
2289 lf.lfCharSet = DEFAULT_CHARSET;
2290 lstrcpy(lf.lfFaceName, font_name);
2292 SetLastError(0xdeadbeef);
2293 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2294 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2295 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2296 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2297 ansi_charset, symbol_charset, russian_charset,
2298 *font_name ? font_name : "<empty>");
2299 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2300 for (i = 0; i < efd.total; i++)
2303 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2304 font_name, efd.lf[i].lfFaceName);
2308 switch (font_charset)
2311 ok(ansi_charset > 0,
2312 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2314 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2315 ok(russian_charset > 0,
2316 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2318 case SYMBOL_CHARSET:
2320 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2322 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2323 ok(!russian_charset,
2324 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2326 case DEFAULT_CHARSET:
2327 ok(ansi_charset > 0,
2328 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2329 ok(symbol_charset > 0,
2330 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2331 ok(russian_charset > 0,
2332 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2338 ok(ansi_charset > 0,
2339 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2340 ok(symbol_charset > 0,
2341 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2342 ok(russian_charset > 0,
2343 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2346 memset(&lf, 0, sizeof(lf));
2347 lf.lfCharSet = SYMBOL_CHARSET;
2348 lstrcpy(lf.lfFaceName, font_name);
2350 SetLastError(0xdeadbeef);
2351 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2352 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2353 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2354 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2355 ansi_charset, symbol_charset, russian_charset,
2356 *font_name ? font_name : "<empty>");
2357 if (*font_name && font_charset == ANSI_CHARSET)
2358 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2361 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2362 for (i = 0; i < efd.total; i++)
2364 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2366 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2367 font_name, efd.lf[i].lfFaceName);
2371 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2372 ok(symbol_charset > 0,
2373 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2374 ok(!russian_charset,
2375 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2381 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2383 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2385 if (type != TRUETYPE_FONTTYPE) return 1;
2387 if (efd->total < MAX_ENUM_FONTS)
2388 efd->lf[efd->total++] = *lf;
2390 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2395 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2397 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2399 if (type != TRUETYPE_FONTTYPE) return 1;
2401 if (efnd->total < MAX_ENUM_FONTS)
2402 efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2404 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2409 static void test_EnumFontFamiliesEx_default_charset(void)
2411 struct enum_font_data efd;
2412 LOGFONT gui_font, enum_font;
2416 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2417 ok(ret, "GetObject failed.\n");
2424 memset(&enum_font, 0, sizeof(enum_font));
2425 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2426 enum_font.lfCharSet = DEFAULT_CHARSET;
2427 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2430 if (efd.total == 0) {
2431 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2434 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2436 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2437 "(%s) got charset %d expected %d\n",
2438 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2443 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2445 HFONT hfont, hfont_prev;
2447 GLYPHMETRICS gm1, gm2;
2451 if(!pGetGlyphIndicesA)
2454 /* negative widths are handled just as positive ones */
2455 lf2.lfWidth = -lf->lfWidth;
2457 SetLastError(0xdeadbeef);
2458 hfont = CreateFontIndirectA(lf);
2459 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2460 check_font("original", lf, hfont);
2462 hfont_prev = SelectObject(hdc, hfont);
2464 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2465 if (ret == GDI_ERROR || idx == 0xffff)
2467 SelectObject(hdc, hfont_prev);
2468 DeleteObject(hfont);
2469 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2473 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2474 memset(&gm1, 0xab, sizeof(gm1));
2475 SetLastError(0xdeadbeef);
2476 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2477 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2479 SelectObject(hdc, hfont_prev);
2480 DeleteObject(hfont);
2482 SetLastError(0xdeadbeef);
2483 hfont = CreateFontIndirectA(&lf2);
2484 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2485 check_font("negative width", &lf2, hfont);
2487 hfont_prev = SelectObject(hdc, hfont);
2489 memset(&gm2, 0xbb, sizeof(gm2));
2490 SetLastError(0xdeadbeef);
2491 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2492 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2494 SelectObject(hdc, hfont_prev);
2495 DeleteObject(hfont);
2497 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2498 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2499 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2500 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2501 gm1.gmCellIncX == gm2.gmCellIncX &&
2502 gm1.gmCellIncY == gm2.gmCellIncY,
2503 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2504 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2505 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2506 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2507 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2510 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2511 #include "pshpack2.h"
2515 SHORT xAvgCharWidth;
2516 USHORT usWeightClass;
2517 USHORT usWidthClass;
2519 SHORT ySubscriptXSize;
2520 SHORT ySubscriptYSize;
2521 SHORT ySubscriptXOffset;
2522 SHORT ySubscriptYOffset;
2523 SHORT ySuperscriptXSize;
2524 SHORT ySuperscriptYSize;
2525 SHORT ySuperscriptXOffset;
2526 SHORT ySuperscriptYOffset;
2527 SHORT yStrikeoutSize;
2528 SHORT yStrikeoutPosition;
2531 ULONG ulUnicodeRange1;
2532 ULONG ulUnicodeRange2;
2533 ULONG ulUnicodeRange3;
2534 ULONG ulUnicodeRange4;
2537 USHORT usFirstCharIndex;
2538 USHORT usLastCharIndex;
2539 /* According to the Apple spec, original version didn't have the below fields,
2540 * version numbers were taken from the OpenType spec.
2542 /* version 0 (TrueType 1.5) */
2543 USHORT sTypoAscender;
2544 USHORT sTypoDescender;
2545 USHORT sTypoLineGap;
2547 USHORT usWinDescent;
2548 /* version 1 (TrueType 1.66) */
2549 ULONG ulCodePageRange1;
2550 ULONG ulCodePageRange2;
2551 /* version 2 (OpenType 1.2) */
2554 USHORT usDefaultChar;
2556 USHORT usMaxContext;
2558 #include "poppack.h"
2560 #ifdef WORDS_BIGENDIAN
2561 #define GET_BE_WORD(x) (x)
2562 #define GET_BE_DWORD(x) (x)
2564 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2565 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2568 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2569 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2570 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2571 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2572 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2573 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2586 } cmap_encoding_record;
2594 BYTE glyph_ids[256];
2604 USHORT search_range;
2605 USHORT entry_selector;
2608 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2611 USHORT start_count[seg_countx2 / 2];
2612 USHORT id_delta[seg_countx2 / 2];
2613 USHORT id_range_offset[seg_countx2 / 2];
2623 USHORT id_range_offset;
2624 } cmap_format_4_seg;
2626 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2628 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2629 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2630 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2631 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2632 os2->panose.bWeight, os2->panose.bProportion);
2635 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2638 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2642 for(i = 0; i < 256; i++)
2644 if(cmap->glyph_ids[i] == 0) continue;
2646 if(*first == 256) *first = i;
2648 if(*first == 256) return FALSE;
2652 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2654 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2655 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2656 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2657 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2658 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2661 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2664 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2665 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2666 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2670 for(i = 0; i < seg_count; i++)
2673 cmap_format_4_seg seg;
2675 get_seg4(cmap, i, &seg);
2676 for(code = seg.start_count; code <= seg.end_count; code++)
2678 if(seg.id_range_offset == 0)
2679 index = (seg.id_delta + code) & 0xffff;
2682 index = seg.id_range_offset / 2
2683 + code - seg.start_count
2686 /* some fonts have broken last segment */
2687 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2688 index = GET_BE_WORD(glyph_ids[index]);
2691 trace("segment %04x/%04x index %04x points to nowhere\n",
2692 seg.start_count, seg.end_count, index);
2695 if(index) index += seg.id_delta;
2697 if(*first == 0x10000)
2698 *last = *first = code;
2704 if(*first == 0x10000) return FALSE;
2708 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2711 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2713 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2715 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2716 return (BYTE *)header + GET_BE_DWORD(record->offset);
2729 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2732 cmap_header *header;
2737 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2738 ok(size != GDI_ERROR, "no cmap table found\n");
2739 if(size == GDI_ERROR) return FALSE;
2741 header = HeapAlloc(GetProcessHeap(), 0, size);
2742 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2743 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2744 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2746 cmap = get_cmap(header, 3, 1);
2748 *cmap_type = cmap_ms_unicode;
2751 cmap = get_cmap(header, 3, 0);
2752 if(cmap) *cmap_type = cmap_ms_symbol;
2756 *cmap_type = cmap_none;
2760 format = GET_BE_WORD(*(WORD *)cmap);
2764 r = get_first_last_from_cmap0(cmap, first, last);
2767 r = get_first_last_from_cmap4(cmap, first, last, size);
2770 trace("unhandled cmap format %d\n", format);
2775 HeapFree(GetProcessHeap(), 0, header);
2779 #define TT_PLATFORM_MICROSOFT 3
2780 #define TT_MS_ID_SYMBOL_CS 0
2781 #define TT_MS_ID_UNICODE_CS 1
2782 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2783 #define TT_NAME_ID_FONT_FAMILY 1
2784 #define TT_NAME_ID_FONT_SUBFAMILY 2
2785 #define TT_NAME_ID_UNIQUE_ID 3
2786 #define TT_NAME_ID_FULL_NAME 4
2788 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2790 struct sfnt_name_header
2793 USHORT number_of_record;
2794 USHORT storage_offset;
2806 LONG size, offset, length;
2812 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2813 ok(size != GDI_ERROR, "no name table found\n");
2814 if(size == GDI_ERROR) return FALSE;
2816 data = HeapAlloc(GetProcessHeap(), 0, size);
2817 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2818 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2820 header = (void *)data;
2821 header->format = GET_BE_WORD(header->format);
2822 header->number_of_record = GET_BE_WORD(header->number_of_record);
2823 header->storage_offset = GET_BE_WORD(header->storage_offset);
2824 if (header->format != 0)
2826 trace("got format %u\n", header->format);
2829 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2831 trace("number records out of range: %d\n", header->number_of_record);
2834 if (header->storage_offset >= size)
2836 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2840 entry = (void *)&header[1];
2841 for (i = 0; i < header->number_of_record; i++)
2843 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2844 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
2845 GET_BE_WORD(entry[i].language_id) != language_id ||
2846 GET_BE_WORD(entry[i].name_id) != name_id)
2851 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2852 length = GET_BE_WORD(entry[i].length);
2853 if (offset + length > size)
2855 trace("entry %d is out of range\n", i);
2858 if (length >= out_size)
2860 trace("buffer too small for entry %d\n", i);
2864 name = (WCHAR *)(data + offset);
2865 for (c = 0; c < length / 2; c++)
2866 out_buf[c] = GET_BE_WORD(name[c]);
2874 HeapFree(GetProcessHeap(), 0, data);
2878 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2881 HFONT hfont, hfont_old;
2885 const char *font_name = lf->lfFaceName;
2886 DWORD cmap_first = 0, cmap_last = 0;
2887 UINT ascent, descent, cell_height;
2888 cmap_type cmap_type;
2889 BOOL sys_lang_non_english;
2891 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2894 SetLastError(0xdeadbeef);
2895 hfont = CreateFontIndirectA(lf);
2896 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2898 hfont_old = SelectObject(hdc, hfont);
2900 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2901 if (size == GDI_ERROR)
2903 trace("OS/2 chunk was not found\n");
2906 if (size > sizeof(tt_os2))
2908 trace("got too large OS/2 chunk of size %u\n", size);
2909 size = sizeof(tt_os2);
2912 memset(&tt_os2, 0, sizeof(tt_os2));
2913 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2914 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2916 ascent = GET_BE_WORD(tt_os2.usWinAscent);
2917 descent = GET_BE_WORD(tt_os2.usWinDescent);
2918 cell_height = ascent + descent;
2919 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
2920 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
2922 SetLastError(0xdeadbeef);
2923 ret = GetTextMetricsA(hdc, &tmA);
2924 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2926 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2928 skip("Unable to retrieve first and last glyphs from cmap\n");
2932 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2933 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2934 UINT os2_first_char, os2_last_char, default_char, break_char;
2938 version = GET_BE_WORD(tt_os2.version);
2940 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2941 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2942 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2943 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2945 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2946 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2947 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2949 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2954 case 1257: /* Baltic */
2955 expect_last_W = 0xf8fd;
2958 expect_last_W = 0xf0ff;
2960 expect_break_W = 0x20;
2961 expect_default_W = expect_break_W - 1;
2962 expect_first_A = 0x1e;
2963 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2967 expect_first_W = cmap_first;
2968 expect_last_W = min(cmap_last, os2_last_char);
2969 if(os2_first_char <= 1)
2970 expect_break_W = os2_first_char + 2;
2971 else if(os2_first_char > 0xff)
2972 expect_break_W = 0x20;
2974 expect_break_W = os2_first_char;
2975 expect_default_W = expect_break_W - 1;
2976 expect_first_A = expect_default_W - 1;
2977 expect_last_A = min(expect_last_W, 0xff);
2979 expect_break_A = expect_break_W;
2980 expect_default_A = expect_default_W;
2982 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2983 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2984 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2985 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2986 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2988 ok(tmA.tmFirstChar == expect_first_A ||
2989 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2990 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2991 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2992 ok(tmA.tmLastChar == expect_last_A ||
2993 tmA.tmLastChar == 0xff /* win9x */,
2994 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2996 skip("tmLastChar is DBCS lead byte\n");
2997 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2998 font_name, tmA.tmBreakChar, expect_break_A);
2999 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3000 "A: tmDefaultChar for %s got %02x expected %02x\n",
3001 font_name, tmA.tmDefaultChar, expect_default_A);
3004 SetLastError(0xdeadbeef);
3005 ret = GetTextMetricsW(hdc, &tmW);
3006 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3007 "GetTextMetricsW error %u\n", GetLastError());
3010 /* Wine uses the os2 first char */
3011 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3012 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3013 font_name, tmW.tmFirstChar, expect_first_W);
3015 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3016 font_name, tmW.tmFirstChar, expect_first_W);
3018 /* Wine uses the os2 last char */
3019 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3020 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3021 font_name, tmW.tmLastChar, expect_last_W);
3023 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3024 font_name, tmW.tmLastChar, expect_last_W);
3025 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3026 font_name, tmW.tmBreakChar, expect_break_W);
3027 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3028 "W: tmDefaultChar for %s got %02x expected %02x\n",
3029 font_name, tmW.tmDefaultChar, expect_default_W);
3031 /* Test the aspect ratio while we have tmW */
3032 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3033 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3034 tmW.tmDigitizedAspectX, ret);
3035 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3036 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3037 tmW.tmDigitizedAspectX, ret);
3041 /* test FF_ values */
3042 switch(tt_os2.panose.bFamilyType)
3046 case PAN_FAMILY_TEXT_DISPLAY:
3047 case PAN_FAMILY_PICTORIAL:
3049 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3050 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3052 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3055 switch(tt_os2.panose.bSerifStyle)
3060 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3063 case PAN_SERIF_COVE:
3064 case PAN_SERIF_OBTUSE_COVE:
3065 case PAN_SERIF_SQUARE_COVE:
3066 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3067 case PAN_SERIF_SQUARE:
3068 case PAN_SERIF_THIN:
3069 case PAN_SERIF_BONE:
3070 case PAN_SERIF_EXAGGERATED:
3071 case PAN_SERIF_TRIANGLE:
3072 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3075 case PAN_SERIF_NORMAL_SANS:
3076 case PAN_SERIF_OBTUSE_SANS:
3077 case PAN_SERIF_PERP_SANS:
3078 case PAN_SERIF_FLARED:
3079 case PAN_SERIF_ROUNDED:
3080 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3085 case PAN_FAMILY_SCRIPT:
3086 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3089 case PAN_FAMILY_DECORATIVE:
3090 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3094 test_negative_width(hdc, lf);
3097 SelectObject(hdc, hfont_old);
3098 DeleteObject(hfont);
3103 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3105 INT *enumed = (INT *)lParam;
3107 if (type == TRUETYPE_FONTTYPE)
3110 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3115 static void test_GetTextMetrics(void)
3121 /* Report only once */
3122 if(!pGetGlyphIndicesA)
3123 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3127 memset(&lf, 0, sizeof(lf));
3128 lf.lfCharSet = DEFAULT_CHARSET;
3130 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3131 trace("Tested metrics of %d truetype fonts\n", enumed);
3136 static void test_nonexistent_font(void)
3144 { "Times New Roman Baltic", 186 },
3145 { "Times New Roman CE", 238 },
3146 { "Times New Roman CYR", 204 },
3147 { "Times New Roman Greek", 161 },
3148 { "Times New Roman TUR", 162 }
3154 INT cs, expected_cs, i;
3155 char buf[LF_FACESIZE];
3157 if (!is_truetype_font_installed("Arial") ||
3158 !is_truetype_font_installed("Times New Roman"))
3160 skip("Arial or Times New Roman not installed\n");
3164 expected_cs = GetACP();
3165 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3167 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3170 expected_cs = csi.ciCharset;
3171 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3175 memset(&lf, 0, sizeof(lf));
3177 lf.lfWeight = FW_REGULAR;
3178 lf.lfCharSet = ANSI_CHARSET;
3179 lf.lfPitchAndFamily = FF_SWISS;
3180 strcpy(lf.lfFaceName, "Nonexistent font");
3181 hfont = CreateFontIndirectA(&lf);
3182 hfont = SelectObject(hdc, hfont);
3183 GetTextFaceA(hdc, sizeof(buf), buf);
3184 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3185 cs = GetTextCharset(hdc);
3186 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3187 DeleteObject(SelectObject(hdc, hfont));
3189 memset(&lf, 0, sizeof(lf));
3191 lf.lfWeight = FW_DONTCARE;
3192 strcpy(lf.lfFaceName, "Nonexistent font");
3193 hfont = CreateFontIndirectA(&lf);
3194 hfont = SelectObject(hdc, hfont);
3195 GetTextFaceA(hdc, sizeof(buf), buf);
3196 todo_wine /* Wine uses Arial for all substitutions */
3197 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3198 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3199 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3201 cs = GetTextCharset(hdc);
3202 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3203 DeleteObject(SelectObject(hdc, hfont));
3205 memset(&lf, 0, sizeof(lf));
3207 lf.lfWeight = FW_REGULAR;
3208 strcpy(lf.lfFaceName, "Nonexistent font");
3209 hfont = CreateFontIndirectA(&lf);
3210 hfont = SelectObject(hdc, hfont);
3211 GetTextFaceA(hdc, sizeof(buf), buf);
3212 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3213 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3214 cs = GetTextCharset(hdc);
3215 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3216 DeleteObject(SelectObject(hdc, hfont));
3218 memset(&lf, 0, sizeof(lf));
3220 lf.lfWeight = FW_DONTCARE;
3221 strcpy(lf.lfFaceName, "Times New Roman");
3222 hfont = CreateFontIndirectA(&lf);
3223 hfont = SelectObject(hdc, hfont);
3224 GetTextFaceA(hdc, sizeof(buf), buf);
3225 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3226 cs = GetTextCharset(hdc);
3227 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3228 DeleteObject(SelectObject(hdc, hfont));
3230 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3232 memset(&lf, 0, sizeof(lf));
3234 lf.lfWeight = FW_REGULAR;
3235 strcpy(lf.lfFaceName, font_subst[i].name);
3236 hfont = CreateFontIndirectA(&lf);
3237 hfont = SelectObject(hdc, hfont);
3238 cs = GetTextCharset(hdc);
3239 if (font_subst[i].charset == expected_cs)
3241 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3242 GetTextFaceA(hdc, sizeof(buf), buf);
3243 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3247 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3248 GetTextFaceA(hdc, sizeof(buf), buf);
3249 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3250 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3252 DeleteObject(SelectObject(hdc, hfont));
3254 memset(&lf, 0, sizeof(lf));
3256 lf.lfWeight = FW_DONTCARE;
3257 strcpy(lf.lfFaceName, font_subst[i].name);
3258 hfont = CreateFontIndirectA(&lf);
3259 hfont = SelectObject(hdc, hfont);
3260 GetTextFaceA(hdc, sizeof(buf), buf);
3261 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3262 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3263 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3264 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3265 "got %s for font %s\n", buf, font_subst[i].name);
3266 cs = GetTextCharset(hdc);
3267 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3268 DeleteObject(SelectObject(hdc, hfont));
3274 static void test_GdiRealizationInfo(void)
3279 HFONT hfont, hfont_old;
3282 if(!pGdiRealizationInfo)
3284 win_skip("GdiRealizationInfo not available\n");
3290 memset(info, 0xcc, sizeof(info));
3291 r = pGdiRealizationInfo(hdc, info);
3292 ok(r != 0, "ret 0\n");
3293 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3294 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3296 if (!is_truetype_font_installed("Arial"))
3298 skip("skipping GdiRealizationInfo with truetype font\n");
3302 memset(&lf, 0, sizeof(lf));
3303 strcpy(lf.lfFaceName, "Arial");
3305 lf.lfWeight = FW_NORMAL;
3306 hfont = CreateFontIndirectA(&lf);
3307 hfont_old = SelectObject(hdc, hfont);
3309 memset(info, 0xcc, sizeof(info));
3310 r = pGdiRealizationInfo(hdc, info);
3311 ok(r != 0, "ret 0\n");
3312 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3313 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3315 DeleteObject(SelectObject(hdc, hfont_old));
3321 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3322 the nul in the count of characters copied when the face name buffer is not
3323 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3324 always includes it. */
3325 static void test_GetTextFace(void)
3327 static const char faceA[] = "Tahoma";
3328 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3331 char bufA[LF_FACESIZE];
3332 WCHAR bufW[LF_FACESIZE];
3337 if(!is_font_installed("Tahoma"))
3339 skip("Tahoma is not installed so skipping this test\n");
3344 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3345 f = CreateFontIndirectA(&fA);
3346 ok(f != NULL, "CreateFontIndirectA failed\n");
3349 g = SelectObject(dc, f);
3350 n = GetTextFaceA(dc, sizeof bufA, bufA);
3351 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3352 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3354 /* Play with the count arg. */
3356 n = GetTextFaceA(dc, 0, bufA);
3357 ok(n == 0, "GetTextFaceA returned %d\n", n);
3358 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3361 n = GetTextFaceA(dc, 1, bufA);
3362 ok(n == 0, "GetTextFaceA returned %d\n", n);
3363 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3365 bufA[0] = 'x'; bufA[1] = 'y';
3366 n = GetTextFaceA(dc, 2, bufA);
3367 ok(n == 1, "GetTextFaceA returned %d\n", n);
3368 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3370 n = GetTextFaceA(dc, 0, NULL);
3371 ok(n == sizeof faceA ||
3372 broken(n == 0), /* win98, winMe */
3373 "GetTextFaceA returned %d\n", n);
3375 DeleteObject(SelectObject(dc, g));
3376 ReleaseDC(NULL, dc);
3379 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3380 SetLastError(0xdeadbeef);
3381 f = CreateFontIndirectW(&fW);
3382 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3384 win_skip("CreateFontIndirectW is not implemented\n");
3387 ok(f != NULL, "CreateFontIndirectW failed\n");
3390 g = SelectObject(dc, f);
3391 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3392 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3393 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3395 /* Play with the count arg. */
3397 n = GetTextFaceW(dc, 0, bufW);
3398 ok(n == 0, "GetTextFaceW returned %d\n", n);
3399 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3402 n = GetTextFaceW(dc, 1, bufW);
3403 ok(n == 1, "GetTextFaceW returned %d\n", n);
3404 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3406 bufW[0] = 'x'; bufW[1] = 'y';
3407 n = GetTextFaceW(dc, 2, bufW);
3408 ok(n == 2, "GetTextFaceW returned %d\n", n);
3409 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3411 n = GetTextFaceW(dc, 0, NULL);
3412 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3414 DeleteObject(SelectObject(dc, g));
3415 ReleaseDC(NULL, dc);
3418 static void test_orientation(void)
3420 static const char test_str[11] = "Test String";
3423 HFONT hfont, old_hfont;
3426 if (!is_truetype_font_installed("Arial"))
3428 skip("Arial is not installed\n");
3432 hdc = CreateCompatibleDC(0);
3433 memset(&lf, 0, sizeof(lf));
3434 lstrcpyA(lf.lfFaceName, "Arial");
3436 lf.lfOrientation = lf.lfEscapement = 900;
3437 hfont = create_font("orientation", &lf);
3438 old_hfont = SelectObject(hdc, hfont);
3439 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3440 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3441 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3442 SelectObject(hdc, old_hfont);
3443 DeleteObject(hfont);
3447 static void test_oemcharset(void)
3451 HFONT hfont, old_hfont;
3454 hdc = CreateCompatibleDC(0);
3455 ZeroMemory(&lf, sizeof(lf));
3457 lf.lfCharSet = OEM_CHARSET;
3458 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3459 lstrcpyA(lf.lfFaceName, "Terminal");
3460 hfont = CreateFontIndirectA(&lf);
3461 old_hfont = SelectObject(hdc, hfont);
3462 charset = GetTextCharset(hdc);
3464 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3465 hfont = SelectObject(hdc, old_hfont);
3466 GetObjectA(hfont, sizeof(clf), &clf);
3467 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3468 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3469 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3470 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3471 DeleteObject(hfont);
3475 static void test_GetGlyphOutline(void)
3478 GLYPHMETRICS gm, gm2;
3480 HFONT hfont, old_hfont;
3489 {ANSI_CHARSET, 0x30, 0x30},
3490 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3491 {HANGEUL_CHARSET, 0x8141, 0xac02},
3492 {JOHAB_CHARSET, 0x8446, 0x3135},
3493 {GB2312_CHARSET, 0x8141, 0x4e04},
3494 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3498 if (!is_truetype_font_installed("Tahoma"))
3500 skip("Tahoma is not installed\n");
3504 hdc = CreateCompatibleDC(0);
3505 memset(&lf, 0, sizeof(lf));
3507 lstrcpyA(lf.lfFaceName, "Tahoma");
3508 SetLastError(0xdeadbeef);
3509 hfont = CreateFontIndirectA(&lf);
3510 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3511 old_hfont = SelectObject(hdc, hfont);
3513 memset(&gm, 0, sizeof(gm));
3514 SetLastError(0xdeadbeef);
3515 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3516 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3518 memset(&gm, 0, sizeof(gm));
3519 SetLastError(0xdeadbeef);
3520 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3521 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3522 ok(GetLastError() == 0xdeadbeef ||
3523 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3524 "expected 0xdeadbeef, got %u\n", GetLastError());
3526 memset(&gm, 0, sizeof(gm));
3527 SetLastError(0xdeadbeef);
3528 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3529 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3530 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3532 memset(&gm, 0, sizeof(gm));
3533 SetLastError(0xdeadbeef);
3534 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3535 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3537 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3538 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3541 /* test for needed buffer size request on space char */
3542 memset(&gm, 0, sizeof(gm));
3543 SetLastError(0xdeadbeef);
3544 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3545 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3546 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3548 /* requesting buffer size for space char + error */
3549 memset(&gm, 0, sizeof(gm));
3550 SetLastError(0xdeadbeef);
3551 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3552 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3554 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3555 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3558 SelectObject(hdc, old_hfont);
3559 DeleteObject(hfont);
3561 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3563 lf.lfFaceName[0] = '\0';
3564 lf.lfCharSet = c[i].cs;
3565 lf.lfPitchAndFamily = 0;
3566 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3568 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3572 old_hfont = SelectObject(hdc, hfont);
3574 /* expected to ignore superfluous bytes (sigle-byte character) */
3575 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3576 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3577 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3579 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3580 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3581 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3583 /* expected to ignore superfluous bytes (double-byte character) */
3584 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3585 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3586 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3587 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3589 /* expected to match wide-char version results */
3590 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3591 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3593 hfont = SelectObject(hdc, old_hfont);
3594 DeleteObject(hfont);
3600 /* bug #9995: there is a limit to the character width that can be specified */
3601 static void test_GetTextMetrics2(const char *fontname, int font_height)
3607 int ave_width, height, width, ratio, scale;
3609 if (!is_truetype_font_installed( fontname)) {
3610 skip("%s is not installed\n", fontname);
3613 hdc = CreateCompatibleDC(0);
3614 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3615 /* select width = 0 */
3616 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3617 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3618 DEFAULT_QUALITY, VARIABLE_PITCH,
3620 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3621 of = SelectObject( hdc, hf);
3622 ret = GetTextMetricsA( hdc, &tm);
3623 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3624 height = tm.tmHeight;
3625 ave_width = tm.tmAveCharWidth;
3626 SelectObject( hdc, of);
3629 trace("height %d, ave width %d\n", height, ave_width);
3631 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3633 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3634 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3635 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3636 ok(hf != 0, "CreateFont failed\n");
3637 of = SelectObject(hdc, hf);
3638 ret = GetTextMetrics(hdc, &tm);
3639 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3640 SelectObject(hdc, of);
3643 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3649 ratio = width / height;
3650 scale = width / ave_width;
3652 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3653 width, height, ratio, width, ave_width, scale);
3655 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3658 static void test_CreateFontIndirect(void)
3660 LOGFONTA lf, getobj_lf;
3663 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3665 memset(&lf, 0, sizeof(lf));
3666 lf.lfCharSet = ANSI_CHARSET;
3667 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3670 lf.lfQuality = DEFAULT_QUALITY;
3671 lf.lfItalic = FALSE;
3672 lf.lfWeight = FW_DONTCARE;
3674 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3676 lstrcpyA(lf.lfFaceName, TestName[i]);
3677 hfont = CreateFontIndirectA(&lf);
3678 ok(hfont != 0, "CreateFontIndirectA failed\n");
3679 SetLastError(0xdeadbeef);
3680 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3681 ok(ret, "GetObject failed: %d\n", GetLastError());
3682 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3683 ok(lf.lfWeight == getobj_lf.lfWeight ||
3684 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3685 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3686 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3687 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3688 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3689 DeleteObject(hfont);
3693 static void test_CreateFontIndirectEx(void)
3695 ENUMLOGFONTEXDVA lfex;
3698 if (!pCreateFontIndirectExA)
3700 win_skip("CreateFontIndirectExA is not available\n");
3704 if (!is_truetype_font_installed("Arial"))
3706 skip("Arial is not installed\n");
3710 SetLastError(0xdeadbeef);
3711 hfont = pCreateFontIndirectExA(NULL);
3712 ok(hfont == NULL, "got %p\n", hfont);
3713 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3715 memset(&lfex, 0, sizeof(lfex));
3716 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3717 hfont = pCreateFontIndirectExA(&lfex);
3718 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3720 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3721 DeleteObject(hfont);
3724 static void free_font(void *font)
3726 UnmapViewOfFile(font);
3729 static void *load_font(const char *font_name, DWORD *font_size)
3731 char file_name[MAX_PATH];
3732 HANDLE file, mapping;
3735 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3736 strcat(file_name, "\\fonts\\");
3737 strcat(file_name, font_name);
3739 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3740 if (file == INVALID_HANDLE_VALUE) return NULL;
3742 *font_size = GetFileSize(file, NULL);
3744 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3751 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3754 CloseHandle(mapping);
3758 static void test_AddFontMemResource(void)
3761 DWORD font_size, num_fonts;
3765 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3767 win_skip("AddFontMemResourceEx is not available on this platform\n");
3771 font = load_font("sserife.fon", &font_size);
3774 skip("Unable to locate and load font sserife.fon\n");
3778 SetLastError(0xdeadbeef);
3779 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3780 ok(!ret, "AddFontMemResourceEx should fail\n");
3781 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3782 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3785 SetLastError(0xdeadbeef);
3786 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3787 ok(!ret, "AddFontMemResourceEx should fail\n");
3788 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3789 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3792 SetLastError(0xdeadbeef);
3793 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3794 ok(!ret, "AddFontMemResourceEx should fail\n");
3795 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3796 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3799 SetLastError(0xdeadbeef);
3800 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3801 ok(!ret, "AddFontMemResourceEx should fail\n");
3802 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3803 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3806 SetLastError(0xdeadbeef);
3807 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3808 ok(!ret, "AddFontMemResourceEx should fail\n");
3809 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3810 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3813 SetLastError(0xdeadbeef);
3814 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3815 ok(!ret, "AddFontMemResourceEx should fail\n");
3816 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3817 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3820 num_fonts = 0xdeadbeef;
3821 SetLastError(0xdeadbeef);
3822 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3823 ok(!ret, "AddFontMemResourceEx should fail\n");
3824 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3825 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3827 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3829 if (0) /* hangs under windows 2000 */
3831 num_fonts = 0xdeadbeef;
3832 SetLastError(0xdeadbeef);
3833 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3834 ok(!ret, "AddFontMemResourceEx should fail\n");
3835 ok(GetLastError() == 0xdeadbeef,
3836 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3838 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3841 num_fonts = 0xdeadbeef;
3842 SetLastError(0xdeadbeef);
3843 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3844 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3845 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3846 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3850 SetLastError(0xdeadbeef);
3851 bRet = pRemoveFontMemResourceEx(ret);
3852 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3854 /* test invalid pointer to number of loaded fonts */
3855 font = load_font("sserife.fon", &font_size);
3856 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3858 SetLastError(0xdeadbeef);
3859 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3860 ok(!ret, "AddFontMemResourceEx should fail\n");
3861 ok(GetLastError() == 0xdeadbeef,
3862 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3865 SetLastError(0xdeadbeef);
3866 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3867 ok(!ret, "AddFontMemResourceEx should fail\n");
3868 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3869 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3875 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3879 if (type != TRUETYPE_FONTTYPE) return 1;
3881 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3883 lf = (LOGFONT *)lparam;
3888 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3893 if (type != TRUETYPE_FONTTYPE) return 1;
3895 lf = (LOGFONT *)lparam;
3896 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3899 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3906 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3911 static void test_EnumFonts(void)
3917 if (!is_truetype_font_installed("Arial"))
3919 skip("Arial is not installed\n");
3923 /* Windows uses localized font face names, so Arial Bold won't be found */
3924 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3926 skip("User locale is not English, skipping the test\n");
3930 hdc = CreateCompatibleDC(0);
3932 /* check that the enumproc's retval is returned */
3933 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
3934 ok(ret == 0xcafe, "got %08x\n", ret);
3936 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3937 ok(!ret, "font Arial is not enumerated\n");
3938 ret = strcmp(lf.lfFaceName, "Arial");
3939 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3940 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3942 lstrcpy(lf.lfFaceName, "Arial");
3943 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3944 ok(!ret, "font Arial is not enumerated\n");
3945 ret = strcmp(lf.lfFaceName, "Arial");
3946 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3947 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3949 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3950 ok(!ret, "font Arial Bold is not enumerated\n");
3951 ret = strcmp(lf.lfFaceName, "Arial");
3952 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3953 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3955 lstrcpy(lf.lfFaceName, "Arial Bold");
3956 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3957 ok(ret, "font Arial Bold should not be enumerated\n");
3959 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3960 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3961 ret = strcmp(lf.lfFaceName, "Arial");
3962 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3963 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3965 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3966 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3967 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3969 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3970 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3972 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3973 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3974 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3979 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3981 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3982 const char *fullname = (const char *)lParam;
3984 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3989 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3994 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4001 static void test_fullname(void)
4003 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4004 WCHAR bufW[LF_FULLFACESIZE];
4005 char bufA[LF_FULLFACESIZE];
4012 hdc = CreateCompatibleDC(0);
4013 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4015 memset(&lf, 0, sizeof(lf));
4016 lf.lfCharSet = ANSI_CHARSET;
4017 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4020 lf.lfQuality = DEFAULT_QUALITY;
4021 lf.lfItalic = FALSE;
4022 lf.lfWeight = FW_DONTCARE;
4024 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4026 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4028 skip("%s is not installed\n", TestName[i]);
4032 lstrcpyA(lf.lfFaceName, TestName[i]);
4033 hfont = CreateFontIndirectA(&lf);
4034 ok(hfont != 0, "CreateFontIndirectA failed\n");
4036 of = SelectObject(hdc, hfont);
4039 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4040 ok(ret, "face full name could not be read\n");
4041 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4042 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4043 SelectObject(hdc, of);
4044 DeleteObject(hfont);
4049 static void test_fullname2_helper(const char *Family)
4051 char *FamilyName, *FaceName, *StyleName, *otmStr;
4052 struct enum_fullname_data efnd;
4059 DWORD otm_size, ret, buf_size;
4060 OUTLINETEXTMETRICA *otm;
4061 BOOL want_vertical, get_vertical;
4062 want_vertical = ( Family[0] == '@' );
4064 hdc = CreateCompatibleDC(0);
4065 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4067 memset(&lf, 0, sizeof(lf));
4068 lf.lfCharSet = DEFAULT_CHARSET;
4069 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4072 lf.lfQuality = DEFAULT_QUALITY;
4073 lf.lfItalic = FALSE;
4074 lf.lfWeight = FW_DONTCARE;
4075 lstrcpy(lf.lfFaceName, Family);
4077 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4078 if (efnd.total == 0)
4079 skip("%s is not installed\n", lf.lfFaceName);
4081 for (i = 0; i < efnd.total; i++)
4083 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4084 FaceName = (char *)efnd.elf[i].elfFullName;
4085 StyleName = (char *)efnd.elf[i].elfStyle;
4087 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4089 get_vertical = ( FamilyName[0] == '@' );
4092 todo_wine ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4096 lstrcpyA(lf.lfFaceName, FaceName);
4097 hfont = CreateFontIndirectA(&lf);
4098 ok(hfont != 0, "CreateFontIndirectA failed\n");
4100 of = SelectObject(hdc, hfont);
4101 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4102 ok(buf_size != GDI_ERROR, "no name table found\n");
4103 if (buf_size == GDI_ERROR) continue;
4105 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4106 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4108 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4109 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4110 memset(otm, 0, otm_size);
4111 ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4112 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4113 if (ret == 0) continue;
4117 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4120 trace("no localized FONT_FAMILY found.\n");
4121 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4123 ok(ret, "FAMILY (family name) could not be read\n");
4124 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4125 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4126 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4127 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4131 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4134 trace("no localized FULL_NAME found.\n");
4135 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4137 ok(ret, "FULL_NAME (face name) could not be read\n");
4138 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4139 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4140 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4141 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4145 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4148 trace("no localized FONT_SUBFAMILY font.\n");
4149 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4151 ok(ret, "SUBFAMILY (style name) could not be read\n");
4152 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4153 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4154 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4155 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4159 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4162 trace("no localized UNIQUE_ID found.\n");
4163 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4165 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4166 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4167 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4168 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4170 SelectObject(hdc, of);
4171 DeleteObject(hfont);
4173 HeapFree(GetProcessHeap(), 0, otm);
4174 HeapFree(GetProcessHeap(), 0, bufW);
4175 HeapFree(GetProcessHeap(), 0, bufA);
4180 static void test_fullname2(void)
4182 test_fullname2_helper("Arial");
4183 test_fullname2_helper("DejaVu Sans");
4184 test_fullname2_helper("Lucida Sans");
4185 test_fullname2_helper("Tahoma");
4186 test_fullname2_helper("Webdings");
4187 test_fullname2_helper("Wingdings");
4188 test_fullname2_helper("SimSun");
4189 test_fullname2_helper("NSimSun");
4190 test_fullname2_helper("MingLiu");
4191 test_fullname2_helper("PMingLiu");
4192 test_fullname2_helper("WenQuanYi Micro Hei");
4193 test_fullname2_helper("MS UI Gothic");
4194 test_fullname2_helper("Ume UI Gothic");
4195 test_fullname2_helper("MS Gothic");
4196 test_fullname2_helper("Ume Gothic");
4197 test_fullname2_helper("MS PGothic");
4198 test_fullname2_helper("Ume P Gothic");
4199 test_fullname2_helper("Gulim");
4200 test_fullname2_helper("Batang");
4201 test_fullname2_helper("UnBatang");
4202 test_fullname2_helper("UnDotum");
4206 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4208 char tmp_path[MAX_PATH];
4215 SetLastError(0xdeadbeef);
4216 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4217 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4218 if (!rsrc) return FALSE;
4219 SetLastError(0xdeadbeef);
4220 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4221 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4222 if (!rsrc_data) return FALSE;
4223 SetLastError(0xdeadbeef);
4224 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4225 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4226 if (!rsrc_size) return FALSE;
4228 SetLastError(0xdeadbeef);
4229 ret = GetTempPath(MAX_PATH, tmp_path);
4230 ok(ret, "GetTempPath() error %d\n", GetLastError());
4231 SetLastError(0xdeadbeef);
4232 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4233 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4235 SetLastError(0xdeadbeef);
4236 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4237 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4238 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4240 SetLastError(0xdeadbeef);
4241 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4242 ok(ret, "WriteFile() error %d\n", GetLastError());
4248 static void test_CreateScalableFontResource(void)
4250 char ttf_name[MAX_PATH];
4251 char tmp_path[MAX_PATH];
4252 char fot_name[MAX_PATH];
4256 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4258 win_skip("AddFontResourceExA is not available on this platform\n");
4262 if (!write_ttf_file("wine_test.ttf", ttf_name))
4264 skip("Failed to create ttf file for testing\n");
4268 trace("created %s\n", ttf_name);
4270 ret = is_truetype_font_installed("wine_test");
4271 ok(!ret, "font wine_test should not be enumerated\n");
4273 ret = GetTempPath(MAX_PATH, tmp_path);
4274 ok(ret, "GetTempPath() error %d\n", GetLastError());
4275 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4276 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4278 ret = GetFileAttributes(fot_name);
4279 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4281 SetLastError(0xdeadbeef);
4282 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4283 ok(!ret, "CreateScalableFontResource() should fail\n");
4284 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4286 SetLastError(0xdeadbeef);
4287 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4288 ok(!ret, "CreateScalableFontResource() should fail\n");
4289 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4291 file_part = strrchr(ttf_name, '\\');
4292 SetLastError(0xdeadbeef);
4293 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4294 ok(!ret, "CreateScalableFontResource() should fail\n");
4295 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4297 SetLastError(0xdeadbeef);
4298 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4299 ok(!ret, "CreateScalableFontResource() should fail\n");
4300 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4302 SetLastError(0xdeadbeef);
4303 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4304 ok(!ret, "CreateScalableFontResource() should fail\n");
4305 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4307 ret = DeleteFile(fot_name);
4308 ok(ret, "DeleteFile() error %d\n", GetLastError());
4310 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4312 ok(!ret, "RemoveFontResourceEx() should fail\n");
4314 /* test public font resource */
4315 SetLastError(0xdeadbeef);
4316 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4317 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4319 ret = is_truetype_font_installed("wine_test");
4320 ok(!ret, "font wine_test should not be enumerated\n");
4322 SetLastError(0xdeadbeef);
4323 ret = pAddFontResourceExA(fot_name, 0, 0);
4324 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4326 ret = is_truetype_font_installed("wine_test");
4327 ok(ret, "font wine_test should be enumerated\n");
4329 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4331 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4333 SetLastError(0xdeadbeef);
4334 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4335 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4337 ret = is_truetype_font_installed("wine_test");
4339 ok(!ret, "font wine_test should not be enumerated\n");
4341 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4344 /* remove once RemoveFontResource is implemented */
4345 DeleteFile(fot_name);
4346 DeleteFile(ttf_name);
4350 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4351 ok(!ret, "RemoveFontResourceEx() should fail\n");
4353 DeleteFile(fot_name);
4355 /* test hidden font resource */
4356 SetLastError(0xdeadbeef);
4357 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4358 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4360 ret = is_truetype_font_installed("wine_test");
4361 ok(!ret, "font wine_test should not be enumerated\n");
4363 SetLastError(0xdeadbeef);
4364 ret = pAddFontResourceExA(fot_name, 0, 0);
4365 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4367 ret = is_truetype_font_installed("wine_test");
4368 ok(!ret, "font wine_test should not be enumerated\n");
4370 /* XP allows removing a private font added with 0 flags */
4371 SetLastError(0xdeadbeef);
4372 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4373 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4375 ret = is_truetype_font_installed("wine_test");
4376 ok(!ret, "font wine_test should not be enumerated\n");
4378 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4379 ok(!ret, "RemoveFontResourceEx() should fail\n");
4381 DeleteFile(fot_name);
4382 DeleteFile(ttf_name);
4385 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4388 HFONT hfont, hfont_prev;
4392 static const WCHAR str[] = { 0x2025 };
4394 *installed = is_truetype_font_installed(name);
4398 lf.lfEscapement = 0;
4399 lf.lfOrientation = 0;
4400 lf.lfWeight = FW_DONTCARE;
4404 lf.lfCharSet = DEFAULT_CHARSET;
4405 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4406 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4407 lf.lfQuality = DEFAULT_QUALITY;
4408 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4409 strcpy(lf.lfFaceName, name);
4411 hfont = CreateFontIndirectA(&lf);
4412 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4416 hfont_prev = SelectObject(hdc, hfont);
4417 ok(hfont_prev != NULL, "SelectObject failed\n");
4419 ret = GetTextFaceA(hdc, sizeof facename, facename);
4420 ok(ret, "GetTextFaceA failed\n");
4421 *selected = !strcmp(facename, name);
4423 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4424 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4426 memset(gm, 0, sizeof *gm);
4428 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4429 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4431 SelectObject(hdc, hfont_prev);
4432 DeleteObject(hfont);
4433 ReleaseDC(NULL, hdc);
4436 static void test_vertical_font(void)
4438 char ttf_name[MAX_PATH];
4440 BOOL ret, installed, selected;
4444 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4446 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4450 if (!write_ttf_file("vertical.ttf", ttf_name))
4452 skip("Failed to create ttf file for testing\n");
4456 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4457 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4459 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4460 ok(installed, "@WineTestVertical is not installed\n");
4461 ok(selected, "@WineTestVertical is not selected\n");
4462 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4463 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4464 gm.gmBlackBoxX, gm.gmBlackBoxY);
4466 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4467 ok(installed, "@@WineTestVertical is not installed\n");
4468 ok(selected, "@@WineTestVertical is not selected\n");
4469 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4470 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4471 gm.gmBlackBoxX, gm.gmBlackBoxY);
4473 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4475 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4476 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4478 DeleteFile(ttf_name);
4481 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4482 DWORD type, LPARAM lParam)
4484 if (lf->lfFaceName[0] == '@') {
4490 static void test_east_asian_font_selection(void)
4493 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4494 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4499 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4503 char face_name[LF_FACESIZE];
4506 memset(&lf, 0, sizeof lf);
4507 lf.lfFaceName[0] = '\0';
4508 lf.lfCharSet = charset[i];
4510 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4512 skip("Vertical font for charset %u is not installed\n", charset[i]);
4516 hfont = CreateFontIndirectA(&lf);
4517 hfont = SelectObject(hdc, hfont);
4518 memset(face_name, 0, sizeof face_name);
4519 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4520 ok(ret && face_name[0] != '@',
4521 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4522 DeleteObject(SelectObject(hdc, hfont));
4524 memset(&lf, 0, sizeof lf);
4525 strcpy(lf.lfFaceName, "@");
4526 lf.lfCharSet = charset[i];
4527 hfont = CreateFontIndirectA(&lf);
4528 hfont = SelectObject(hdc, hfont);
4529 memset(face_name, 0, sizeof face_name);
4530 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4531 ok(ret && face_name[0] == '@',
4532 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4533 DeleteObject(SelectObject(hdc, hfont));
4535 ReleaseDC(NULL, hdc);
4538 static int get_font_dpi(const LOGFONT *lf)
4540 HDC hdc = CreateCompatibleDC(0);
4545 hfont = CreateFontIndirect(lf);
4546 ok(hfont != 0, "CreateFontIndirect failed\n");
4548 SelectObject(hdc, hfont);
4549 ret = GetTextMetrics(hdc, &tm);
4550 ok(ret, "GetTextMetrics failed\n");
4551 ret = tm.tmDigitizedAspectX;
4554 DeleteObject(hfont);
4559 static void test_stock_fonts(void)
4561 static const int font[] =
4563 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4564 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4566 static const struct test_data
4568 int charset, weight, height, dpi;
4569 const char face_name[LF_FACESIZE];
4572 { /* ANSI_FIXED_FONT */
4573 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4574 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4577 { /* ANSI_VAR_FONT */
4578 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4579 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4583 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4584 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4585 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4586 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4587 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4588 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4591 { /* DEVICE_DEFAULT_FONT */
4592 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4593 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4594 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4595 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4596 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4597 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4600 { /* DEFAULT_GUI_FONT */
4601 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4602 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4603 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4604 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4605 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4606 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4607 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4608 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4609 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4610 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4616 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4622 hfont = GetStockObject(font[i]);
4623 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4625 ret = GetObject(hfont, sizeof(lf), &lf);
4626 if (ret != sizeof(lf))
4629 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4633 for (j = 0; td[i][j].face_name[0] != 0; j++)
4635 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4640 ret = get_font_dpi(&lf);
4641 if (ret != td[i][j].dpi)
4643 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4644 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4648 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4649 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4650 if (td[i][j].face_name[0] == '?')
4652 /* Wine doesn't have this font, skip this case for now.
4653 Actually, the face name is localized on Windows and varies
4654 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4655 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4659 ok(!lstrcmp(td[i][j].face_name, lf.lfFaceName), "%d(%d): expected lfFaceName %s, got %s\n", i, j, td[i][j].face_name, lf.lfFaceName);
4673 test_outline_font();
4674 test_bitmap_font_metrics();
4675 test_GdiGetCharDimensions();
4676 test_GetCharABCWidths();
4677 test_text_extents();
4678 test_GetGlyphIndices();
4679 test_GetKerningPairs();
4680 test_GetOutlineTextMetrics();
4681 test_SetTextJustification();
4682 test_font_charset();
4683 test_GetFontUnicodeRanges();
4684 test_nonexistent_font();
4686 test_height_selection();
4687 test_AddFontMemResource();
4690 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4691 * I'd like to avoid them in this test.
4693 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4694 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4695 if (is_truetype_font_installed("Arial Black") &&
4696 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4698 test_EnumFontFamilies("", ANSI_CHARSET);
4699 test_EnumFontFamilies("", SYMBOL_CHARSET);
4700 test_EnumFontFamilies("", DEFAULT_CHARSET);
4703 skip("Arial Black or Symbol/Wingdings is not installed\n");
4704 test_EnumFontFamiliesEx_default_charset();
4705 test_GetTextMetrics();
4706 test_GdiRealizationInfo();
4708 test_GetGlyphOutline();
4709 test_GetTextMetrics2("Tahoma", -11);
4710 test_GetTextMetrics2("Tahoma", -55);
4711 test_GetTextMetrics2("Tahoma", -110);
4712 test_GetTextMetrics2("Arial", -11);
4713 test_GetTextMetrics2("Arial", -55);
4714 test_GetTextMetrics2("Arial", -110);
4715 test_CreateFontIndirect();
4716 test_CreateFontIndirectEx();
4720 test_east_asian_font_selection();
4722 /* These tests should be last test until RemoveFontResource
4723 * is properly implemented.
4725 test_vertical_font();
4726 test_CreateScalableFontResource();