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} };
57 static WORD system_lang_id;
59 static void init(void)
61 hgdi32 = GetModuleHandleA("gdi32.dll");
63 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
64 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
65 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
66 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
67 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
68 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
69 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
70 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
71 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
72 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
73 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
74 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
75 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
76 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
77 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
79 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
82 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
84 if (type != TRUETYPE_FONTTYPE) return 1;
89 static BOOL is_truetype_font_installed(const char *name)
94 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
101 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
106 static BOOL is_font_installed(const char *name)
111 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
118 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
126 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
127 /* NT4 tries to be clever and only returns the minimum length */
128 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
130 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
131 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
132 ok(lf->lfHeight == getobj_lf.lfHeight ||
133 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
134 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
135 ok(lf->lfWidth == getobj_lf.lfWidth ||
136 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
137 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
138 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
139 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
140 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
141 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
142 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
143 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
144 ok(lf->lfWeight == getobj_lf.lfWeight ||
145 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
146 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
147 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
148 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
149 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
150 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
151 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
152 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
153 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
154 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
155 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
156 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
157 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
160 static HFONT create_font(const char* test, const LOGFONTA* lf)
162 HFONT hfont = CreateFontIndirectA(lf);
163 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
165 check_font(test, lf, hfont);
169 static void test_logfont(void)
174 memset(&lf, 0, sizeof lf);
176 lf.lfCharSet = ANSI_CHARSET;
177 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
178 lf.lfWeight = FW_DONTCARE;
181 lf.lfQuality = DEFAULT_QUALITY;
183 lstrcpyA(lf.lfFaceName, "Arial");
184 hfont = create_font("Arial", &lf);
187 memset(&lf, 'A', sizeof(lf));
188 hfont = CreateFontIndirectA(&lf);
189 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
191 lf.lfFaceName[LF_FACESIZE - 1] = 0;
192 check_font("AAA...", &lf, hfont);
196 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
198 if (type & RASTER_FONTTYPE)
200 LOGFONT *lf = (LOGFONT *)lParam;
202 return 0; /* stop enumeration */
205 return 1; /* continue enumeration */
208 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
210 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
211 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
212 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
213 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
214 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
215 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
216 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
217 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
218 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
219 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
220 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
221 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
222 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
223 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
224 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
225 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
226 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
227 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
228 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
229 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
232 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
233 LONG lfWidth, const char *test_str,
234 INT test_str_len, const TEXTMETRICA *tm_orig,
235 const SIZE *size_orig, INT width_of_A_orig,
236 INT scale_x, INT scale_y)
239 OUTLINETEXTMETRIC otm;
242 INT width_of_A, cx, cy;
248 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
250 GetObjectA(hfont, sizeof(lf), &lf);
252 if (GetOutlineTextMetricsA(hdc, 0, NULL))
254 otm.otmSize = sizeof(otm) / 2;
255 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
256 ok(ret == sizeof(otm)/2 /* XP */ ||
257 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
259 memset(&otm, 0x1, sizeof(otm));
260 otm.otmSize = sizeof(otm);
261 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
262 ok(ret == sizeof(otm) /* XP */ ||
263 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
265 memset(&tm, 0x2, sizeof(tm));
266 ret = GetTextMetricsA(hdc, &tm);
267 ok(ret, "GetTextMetricsA failed\n");
268 /* the structure size is aligned */
269 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
271 ok(0, "tm != otm\n");
272 compare_tm(&tm, &otm.otmTextMetrics);
275 tm = otm.otmTextMetrics;
276 if (0) /* these metrics are scaled too, but with rounding errors */
278 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
279 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
281 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
282 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
283 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
284 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
285 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
286 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
290 ret = GetTextMetricsA(hdc, &tm);
291 ok(ret, "GetTextMetricsA failed\n");
294 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
295 cy = tm.tmHeight / tm_orig->tmHeight;
296 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
297 lfHeight, scale_x, scale_y, cx, cy);
298 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
299 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
300 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
301 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
302 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
304 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
308 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
311 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
313 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
315 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
316 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
318 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
320 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);
323 /* Test how GDI scales bitmap font metrics */
324 static void test_bitmap_font(void)
326 static const char test_str[11] = "Test String";
329 HFONT hfont, old_hfont;
332 INT ret, i, width_orig, height_orig, scale, lfWidth;
334 hdc = CreateCompatibleDC(0);
336 /* "System" has only 1 pixel size defined, otherwise the test breaks */
337 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
341 trace("no bitmap fonts were found, skipping the test\n");
345 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
347 height_orig = bitmap_lf.lfHeight;
348 lfWidth = bitmap_lf.lfWidth;
350 hfont = create_font("bitmap", &bitmap_lf);
351 old_hfont = SelectObject(hdc, hfont);
352 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
353 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
354 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
355 SelectObject(hdc, old_hfont);
358 bitmap_lf.lfHeight = 0;
359 bitmap_lf.lfWidth = 4;
360 hfont = create_font("bitmap", &bitmap_lf);
361 old_hfont = SelectObject(hdc, hfont);
362 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
363 SelectObject(hdc, old_hfont);
366 bitmap_lf.lfHeight = height_orig;
367 bitmap_lf.lfWidth = lfWidth;
369 /* test fractional scaling */
370 for (i = 1; i <= height_orig * 6; i++)
374 bitmap_lf.lfHeight = i;
375 hfont = create_font("fractional", &bitmap_lf);
376 scale = (i + height_orig - 1) / height_orig;
377 nearest_height = scale * height_orig;
378 /* Only jump to the next height if the difference <= 25% original height */
379 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
380 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
381 so we'll not test this particular height. */
382 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
383 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
384 old_hfont = SelectObject(hdc, hfont);
385 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
386 SelectObject(hdc, old_hfont);
390 /* test integer scaling 3x2 */
391 bitmap_lf.lfHeight = height_orig * 2;
392 bitmap_lf.lfWidth *= 3;
393 hfont = create_font("3x2", &bitmap_lf);
394 old_hfont = SelectObject(hdc, hfont);
395 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
396 SelectObject(hdc, old_hfont);
399 /* test integer scaling 3x3 */
400 bitmap_lf.lfHeight = height_orig * 3;
401 bitmap_lf.lfWidth = 0;
402 hfont = create_font("3x3", &bitmap_lf);
403 old_hfont = SelectObject(hdc, hfont);
404 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
405 SelectObject(hdc, old_hfont);
411 /* Test how GDI scales outline font metrics */
412 static void test_outline_font(void)
414 static const char test_str[11] = "Test String";
417 HFONT hfont, old_hfont, old_hfont_2;
418 OUTLINETEXTMETRICA otm;
420 INT width_orig, height_orig, lfWidth;
423 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
427 if (!is_truetype_font_installed("Arial"))
429 skip("Arial is not installed\n");
433 hdc = CreateCompatibleDC(0);
435 memset(&lf, 0, sizeof(lf));
436 strcpy(lf.lfFaceName, "Arial");
438 hfont = create_font("outline", &lf);
439 old_hfont = SelectObject(hdc, hfont);
440 otm.otmSize = sizeof(otm);
441 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
442 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
443 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
445 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
446 SelectObject(hdc, old_hfont);
449 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
450 lf.lfHeight = otm.otmEMSquare;
451 lf.lfHeight = -lf.lfHeight;
452 hfont = create_font("outline", &lf);
453 old_hfont = SelectObject(hdc, hfont);
454 otm.otmSize = sizeof(otm);
455 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
456 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
457 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
458 SelectObject(hdc, old_hfont);
461 height_orig = otm.otmTextMetrics.tmHeight;
462 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
464 /* test integer scaling 3x2 */
465 lf.lfHeight = height_orig * 2;
466 lf.lfWidth = lfWidth * 3;
467 hfont = create_font("3x2", &lf);
468 old_hfont = SelectObject(hdc, hfont);
469 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
470 SelectObject(hdc, old_hfont);
473 /* test integer scaling 3x3 */
474 lf.lfHeight = height_orig * 3;
475 lf.lfWidth = lfWidth * 3;
476 hfont = create_font("3x3", &lf);
477 old_hfont = SelectObject(hdc, hfont);
478 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
479 SelectObject(hdc, old_hfont);
482 /* test integer scaling 1x1 */
483 lf.lfHeight = height_orig * 1;
484 lf.lfWidth = lfWidth * 1;
485 hfont = create_font("1x1", &lf);
486 old_hfont = SelectObject(hdc, hfont);
487 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
488 SelectObject(hdc, old_hfont);
491 /* test integer scaling 1x1 */
492 lf.lfHeight = height_orig;
494 hfont = create_font("1x1", &lf);
495 old_hfont = SelectObject(hdc, hfont);
496 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
498 /* with an identity matrix */
499 memset(&gm, 0, sizeof(gm));
500 SetLastError(0xdeadbeef);
501 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
502 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
503 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
504 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
505 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
506 /* with a custom matrix */
507 memset(&gm, 0, sizeof(gm));
508 SetLastError(0xdeadbeef);
509 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
510 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
511 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
512 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
513 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
515 /* Test that changing the DC transformation affects only the font
516 * selected on this DC and doesn't affect the same font selected on
519 hdc_2 = CreateCompatibleDC(0);
520 old_hfont_2 = SelectObject(hdc_2, hfont);
521 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
523 SetMapMode(hdc, MM_ANISOTROPIC);
525 /* font metrics on another DC should be unchanged */
526 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
528 /* test restrictions of compatibility mode GM_COMPATIBLE */
529 /* part 1: rescaling only X should not change font scaling on screen.
530 So compressing the X axis by 2 is not done, and this
531 appears as X scaling of 2 that no one requested. */
532 SetWindowExtEx(hdc, 100, 100, NULL);
533 SetViewportExtEx(hdc, 50, 100, NULL);
534 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
535 /* font metrics on another DC should be unchanged */
536 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
538 /* part 2: rescaling only Y should change font scaling.
539 As also X is scaled by a factor of 2, but this is not
540 requested by the DC transformation, we get a scaling factor
541 of 2 in the X coordinate. */
542 SetViewportExtEx(hdc, 100, 200, NULL);
543 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
544 /* font metrics on another DC should be unchanged */
545 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
547 /* restore scaling */
548 SetMapMode(hdc, MM_TEXT);
550 /* font metrics on another DC should be unchanged */
551 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
553 SelectObject(hdc_2, old_hfont_2);
556 if (!SetGraphicsMode(hdc, GM_ADVANCED))
558 SelectObject(hdc, old_hfont);
561 skip("GM_ADVANCED is not supported on this platform\n");
572 SetLastError(0xdeadbeef);
573 ret = SetWorldTransform(hdc, &xform);
574 ok(ret, "SetWorldTransform error %u\n", GetLastError());
576 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
578 /* with an identity matrix */
579 memset(&gm, 0, sizeof(gm));
580 SetLastError(0xdeadbeef);
581 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
582 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
583 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
584 pt.x = width_orig; pt.y = 0;
586 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
587 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
588 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
589 /* with a custom matrix */
590 memset(&gm, 0, sizeof(gm));
591 SetLastError(0xdeadbeef);
592 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
593 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
594 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
595 pt.x = width_orig; pt.y = 0;
597 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
598 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
599 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
601 SetLastError(0xdeadbeef);
602 ret = SetMapMode(hdc, MM_LOMETRIC);
603 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
605 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
607 /* with an identity matrix */
608 memset(&gm, 0, sizeof(gm));
609 SetLastError(0xdeadbeef);
610 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
611 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
612 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
613 pt.x = width_orig; pt.y = 0;
615 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
616 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
617 /* with a custom matrix */
618 memset(&gm, 0, sizeof(gm));
619 SetLastError(0xdeadbeef);
620 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
621 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
622 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
623 pt.x = width_orig; pt.y = 0;
625 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
626 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
628 SetLastError(0xdeadbeef);
629 ret = SetMapMode(hdc, MM_TEXT);
630 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
632 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
634 /* with an identity matrix */
635 memset(&gm, 0, sizeof(gm));
636 SetLastError(0xdeadbeef);
637 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
638 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
639 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
640 pt.x = width_orig; pt.y = 0;
642 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
643 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
644 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
645 /* with a custom matrix */
646 memset(&gm, 0, sizeof(gm));
647 SetLastError(0xdeadbeef);
648 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
649 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
650 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
651 pt.x = width_orig; pt.y = 0;
653 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
654 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
655 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
657 SelectObject(hdc, old_hfont);
662 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
664 LOGFONT *lf = (LOGFONT *)lParam;
666 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
669 return 0; /* stop enumeration */
671 return 1; /* continue enumeration */
674 static BOOL is_CJK(void)
676 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
679 #define FH_SCALE 0x80000000
680 static void test_bitmap_font_metrics(void)
682 static const struct font_data
684 const char face_name[LF_FACESIZE];
685 int weight, height, ascent, descent, int_leading, ext_leading;
686 int ave_char_width, max_char_width, dpi;
687 BYTE first_char, last_char, def_char, break_char;
693 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
694 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
695 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
696 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
697 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
698 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
699 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
700 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
701 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 16 },
702 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
704 { "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 },
705 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
706 { "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 },
707 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
708 { "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 },
709 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
710 { "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 },
711 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
712 { "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 },
713 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
715 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
716 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
717 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
718 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
719 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
720 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
721 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
722 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
723 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
724 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
725 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
726 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
727 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
728 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
729 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
730 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
732 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
733 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
734 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
735 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
736 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
737 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
738 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
739 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
740 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
741 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
742 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
743 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
745 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
746 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
747 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
748 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
749 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
750 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
751 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
752 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
753 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
754 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
755 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
756 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
757 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
758 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
759 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
760 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
761 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
763 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
764 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
765 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
766 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
767 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
768 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
769 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
770 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
771 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
772 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
773 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
775 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
776 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
777 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
779 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
780 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
781 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
783 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
784 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
785 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
787 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
788 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
790 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
791 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
792 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
793 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
794 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
795 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
796 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
797 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
798 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
799 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
800 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
801 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
802 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
803 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
804 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
805 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
806 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
807 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
808 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
809 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
810 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
812 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
813 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
814 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
815 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
816 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
817 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
818 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
819 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
820 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
821 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
822 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
823 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
826 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
827 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
829 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
831 /* FIXME: add "Terminal" */
833 static const int font_log_pixels[] = { 96, 120 };
836 HFONT hfont, old_hfont;
838 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
839 char face_name[LF_FACESIZE];
842 trace("system language id %04x\n", system_lang_id);
844 expected_cs = GetACP();
845 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
847 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
850 expected_cs = csi.ciCharset;
851 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
853 hdc = CreateCompatibleDC(0);
856 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
857 GetDeviceCaps(hdc, LOGPIXELSY));
859 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
862 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
864 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
868 font_res = font_log_pixels[i];
871 trace("best font resolution is %d\n", font_res);
873 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
877 memset(&lf, 0, sizeof(lf));
879 height = fd[i].height & ~FH_SCALE;
880 lf.lfHeight = height;
881 strcpy(lf.lfFaceName, fd[i].face_name);
883 for(bit = 0; bit < 32; bit++)
891 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
892 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
894 lf.lfCharSet = csi.ciCharset;
895 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
896 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
897 if (fd[i].height & FH_SCALE)
898 ok(ret, "scaled font height %d should not be enumerated\n", height);
901 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
903 if (ret) /* FIXME: Remove once Wine is fixed */
904 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
906 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
909 if (ret && !(fd[i].height & FH_SCALE))
912 hfont = create_font(lf.lfFaceName, &lf);
913 old_hfont = SelectObject(hdc, hfont);
915 SetLastError(0xdeadbeef);
916 ret = GetTextFace(hdc, sizeof(face_name), face_name);
917 ok(ret, "GetTextFace error %u\n", GetLastError());
919 if (lstrcmp(face_name, fd[i].face_name) != 0)
921 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
922 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
923 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
924 SelectObject(hdc, old_hfont);
929 memset(&gm, 0, sizeof(gm));
930 SetLastError(0xdeadbeef);
931 ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
933 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
934 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
937 bRet = GetTextMetrics(hdc, &tm);
938 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
940 SetLastError(0xdeadbeef);
941 ret = GetTextCharset(hdc);
942 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
943 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
945 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
947 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
948 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
950 if(fd[i].dpi == tm.tmDigitizedAspectX)
952 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
953 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
955 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
956 if (fd[i].height & FH_SCALE)
957 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);
959 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);
960 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
961 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
962 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);
963 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);
964 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);
965 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
966 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
967 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
968 make default char test fail */
969 if (tm.tmCharSet == lf.lfCharSet)
970 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
971 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
972 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);
974 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
975 that make the max width bigger */
976 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
977 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);
980 skip("Skipping font metrics test for system langid 0x%x\n",
983 SelectObject(hdc, old_hfont);
991 static void test_GdiGetCharDimensions(void)
997 LONG avgwidth, height;
998 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1000 if (!pGdiGetCharDimensions)
1002 win_skip("GdiGetCharDimensions not available on this platform\n");
1006 hdc = CreateCompatibleDC(NULL);
1008 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1009 avgwidth = ((size.cx / 26) + 1) / 2;
1011 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1012 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1013 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1015 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1016 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1018 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1019 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1022 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1023 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1024 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1029 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1030 const TEXTMETRIC *lpntme,
1031 DWORD FontType, LPARAM lParam)
1033 if (FontType & TRUETYPE_FONTTYPE)
1037 hfont = CreateFontIndirect(lpelfe);
1040 *(HFONT *)lParam = hfont;
1048 static void test_GetCharABCWidths(void)
1050 static const WCHAR str[] = {'a',0};
1072 {0xffffff, 0xffffff},
1073 {0x1000000, 0x1000000},
1074 {0xffffff, 0x1000000},
1075 {0xffffffff, 0xffffffff},
1083 BOOL r[sizeof range / sizeof range[0]];
1086 {ANSI_CHARSET, 0x30, 0x30,
1087 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1088 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1089 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1090 {HANGEUL_CHARSET, 0x8141, 0xac02,
1091 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1092 {JOHAB_CHARSET, 0x8446, 0x3135,
1093 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1094 {GB2312_CHARSET, 0x8141, 0x4e04,
1095 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1096 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1097 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1101 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1103 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1107 memset(&lf, 0, sizeof(lf));
1108 strcpy(lf.lfFaceName, "System");
1111 hfont = CreateFontIndirectA(&lf);
1113 hfont = SelectObject(hdc, hfont);
1115 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1116 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1118 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1119 ok(!ret, "GetCharABCWidthsI should have failed\n");
1121 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1122 ok(!ret, "GetCharABCWidthsI should have failed\n");
1124 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1125 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1127 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1128 ok(!ret, "GetCharABCWidthsW should have failed\n");
1130 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1131 ok(!ret, "GetCharABCWidthsW should have failed\n");
1133 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1134 ok(!ret, "GetCharABCWidthsW should have failed\n");
1136 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1137 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1139 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1140 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1142 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1143 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1145 hfont = SelectObject(hdc, hfont);
1146 DeleteObject(hfont);
1148 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1152 UINT code = 0x41, j;
1154 lf.lfFaceName[0] = '\0';
1155 lf.lfCharSet = c[i].cs;
1156 lf.lfPitchAndFamily = 0;
1157 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1159 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1163 memset(a, 0, sizeof a);
1164 memset(w, 0, sizeof w);
1165 hfont = SelectObject(hdc, hfont);
1166 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1167 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1168 memcmp(a, w, sizeof a) == 0,
1169 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1171 memset(a, 0xbb, sizeof a);
1172 ret = pGetCharABCWidthsA(hdc, code, code, a);
1173 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1174 memset(full, 0xcc, sizeof full);
1175 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1176 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1177 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1178 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1180 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1182 memset(full, 0xdd, sizeof full);
1183 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1184 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1185 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1188 UINT last = range[j].last - range[j].first;
1189 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1190 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1191 "GetCharABCWidthsA %x should match. codepage = %u\n",
1192 range[j].last, c[i].cs);
1196 hfont = SelectObject(hdc, hfont);
1197 DeleteObject(hfont);
1200 ReleaseDC(NULL, hdc);
1203 static void test_text_extents(void)
1205 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1207 INT i, len, fit1, fit2;
1216 memset(&lf, 0, sizeof(lf));
1217 strcpy(lf.lfFaceName, "Arial");
1220 hfont = CreateFontIndirectA(&lf);
1222 hfont = SelectObject(hdc, hfont);
1223 GetTextMetricsA(hdc, &tm);
1224 GetTextExtentPointA(hdc, "o", 1, &sz);
1225 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1227 SetLastError(0xdeadbeef);
1228 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1229 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1231 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1232 hfont = SelectObject(hdc, hfont);
1233 DeleteObject(hfont);
1239 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1240 extents[0] = 1; /* So that the increasing sequence test will fail
1241 if the extents array is untouched. */
1242 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1243 GetTextExtentPointW(hdc, wt, len, &sz2);
1244 ok(sz1.cy == sz2.cy,
1245 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1246 /* Because of the '\n' in the string GetTextExtentExPoint and
1247 GetTextExtentPoint return different widths under Win2k, but
1248 under WinXP they return the same width. So we don't test that
1251 for (i = 1; i < len; ++i)
1252 ok(extents[i-1] <= extents[i],
1253 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1255 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1256 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1257 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1258 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1259 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1260 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1261 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1262 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1263 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1264 ok(extents[0] == extents[2] && extents[1] == extents[3],
1265 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1266 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1267 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1268 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1269 HeapFree(GetProcessHeap(), 0, extents);
1271 /* extents functions fail with -ve counts (the interesting case being -1) */
1272 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1273 ok(ret == FALSE, "got %d\n", ret);
1274 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1275 ok(ret == FALSE, "got %d\n", ret);
1276 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1277 ok(ret == FALSE, "got %d\n", ret);
1279 /* max_extent = 0 succeeds and returns zero */
1281 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1283 broken(ret == FALSE), /* NT4, 2k */
1286 broken(fit1 == -215), /* NT4, 2k */
1287 "fit = %d\n", fit1);
1288 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1289 ok(ret == TRUE, "got %d\n", ret);
1290 ok(fit2 == 0, "fit = %d\n", fit2);
1292 /* max_extent = -1 is interpreted as a very large width that will
1293 * definitely fit our three characters */
1295 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1296 ok(ret == TRUE, "got %d\n", ret);
1297 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1298 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1299 ok(ret == TRUE, "got %d\n", ret);
1300 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1302 /* max_extent = -2 is interpreted similarly, but the Ansi version
1303 * rejects it while the Unicode one accepts it */
1305 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1306 todo_wine ok(ret == FALSE, "got %d\n", ret);
1307 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1308 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1309 ok(ret == TRUE, "got %d\n", ret);
1310 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1312 hfont = SelectObject(hdc, hfont);
1313 DeleteObject(hfont);
1314 ReleaseDC(NULL, hdc);
1317 static void test_GetGlyphIndices(void)
1324 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1325 WORD glyphs[(sizeof(testtext)/2)-1];
1329 if (!pGetGlyphIndicesW) {
1330 win_skip("GetGlyphIndicesW not available on platform\n");
1336 memset(&lf, 0, sizeof(lf));
1337 strcpy(lf.lfFaceName, "System");
1339 lf.lfCharSet = ANSI_CHARSET;
1341 hfont = CreateFontIndirectA(&lf);
1342 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1343 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1344 if (textm.tmCharSet == ANSI_CHARSET)
1346 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1347 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1348 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1349 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1351 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1352 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1353 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1354 textm.tmDefaultChar, glyphs[4]);
1357 /* FIXME: Write tests for non-ANSI charsets. */
1358 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1360 if(!is_font_installed("Tahoma"))
1362 skip("Tahoma is not installed so skipping this test\n");
1365 memset(&lf, 0, sizeof(lf));
1366 strcpy(lf.lfFaceName, "Tahoma");
1369 hfont = CreateFontIndirectA(&lf);
1370 hOldFont = SelectObject(hdc, hfont);
1371 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1372 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1373 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1374 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1375 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1377 testtext[0] = textm.tmDefaultChar;
1378 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1379 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1380 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1381 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1382 DeleteObject(SelectObject(hdc, hOldFont));
1385 static void test_GetKerningPairs(void)
1387 static const struct kerning_data
1389 const char face_name[LF_FACESIZE];
1391 /* some interesting fields from OUTLINETEXTMETRIC */
1392 LONG tmHeight, tmAscent, tmDescent;
1397 UINT otmsCapEmHeight;
1402 UINT otmusMinimumPPEM;
1403 /* small subset of kerning pairs to test */
1404 DWORD total_kern_pairs;
1405 const KERNINGPAIR kern_pair[26];
1408 {"Arial", 12, 12, 9, 3,
1409 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1412 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1413 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1414 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1415 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1416 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1417 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1418 {933,970,+1},{933,972,-1}
1421 {"Arial", -34, 39, 32, 7,
1422 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1425 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1426 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1427 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1428 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1429 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1430 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1431 {933,970,+2},{933,972,-3}
1434 { "Arial", 120, 120, 97, 23,
1435 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1438 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1439 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1440 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1441 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1442 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1443 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1444 {933,970,+6},{933,972,-10}
1447 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1448 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1449 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1452 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1453 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1454 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1455 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1456 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1457 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1458 {933,970,+54},{933,972,-83}
1464 HFONT hfont, hfont_old;
1465 KERNINGPAIR *kern_pair;
1467 DWORD total_kern_pairs, ret, i, n, matches;
1471 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1472 * which may render this test unusable, so we're trying to avoid that.
1474 SetLastError(0xdeadbeef);
1475 GetKerningPairsW(hdc, 0, NULL);
1476 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1478 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1483 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1485 OUTLINETEXTMETRICW otm;
1488 if (!is_font_installed(kd[i].face_name))
1490 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1494 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1496 memset(&lf, 0, sizeof(lf));
1497 strcpy(lf.lfFaceName, kd[i].face_name);
1498 lf.lfHeight = kd[i].height;
1499 hfont = CreateFontIndirect(&lf);
1502 hfont_old = SelectObject(hdc, hfont);
1504 SetLastError(0xdeadbeef);
1505 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1506 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1507 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1509 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1510 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1511 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1512 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1513 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1514 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1516 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1517 kd[i].otmEMSquare, otm.otmEMSquare);
1518 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1519 kd[i].otmAscent, otm.otmAscent);
1520 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1521 kd[i].otmDescent, otm.otmDescent);
1522 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1523 kd[i].otmLineGap, otm.otmLineGap);
1524 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1525 kd[i].otmMacDescent, otm.otmMacDescent);
1526 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1527 kd[i].otmMacAscent, otm.otmMacAscent);
1529 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1530 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1531 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1532 kd[i].otmsXHeight, otm.otmsXHeight);
1533 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1534 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1535 kd[i].otmMacLineGap, otm.otmMacLineGap);
1536 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1537 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1540 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1541 trace("total_kern_pairs %u\n", total_kern_pairs);
1542 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1544 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1547 SetLastError(0xdeadbeef);
1548 ret = GetKerningPairsW(hdc, 0, kern_pair);
1549 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1550 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1551 ok(ret == 0, "got %u, expected 0\n", ret);
1553 ret = GetKerningPairsW(hdc, 100, NULL);
1554 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1556 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1557 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1559 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1560 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1564 for (n = 0; n < ret; n++)
1567 /* Disabled to limit console spam */
1568 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1569 trace("{'%c','%c',%d},\n",
1570 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1571 for (j = 0; j < kd[i].total_kern_pairs; j++)
1573 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1574 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1576 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1577 "pair %d:%d got %d, expected %d\n",
1578 kern_pair[n].wFirst, kern_pair[n].wSecond,
1579 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1585 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1586 matches, kd[i].total_kern_pairs);
1588 HeapFree(GetProcessHeap(), 0, kern_pair);
1590 SelectObject(hdc, hfont_old);
1591 DeleteObject(hfont);
1597 static void test_height_selection(void)
1599 static const struct font_data
1601 const char face_name[LF_FACESIZE];
1602 int requested_height;
1603 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1606 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1607 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1608 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1609 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1610 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1611 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1612 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1613 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1614 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1615 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1619 HFONT hfont, old_hfont;
1623 hdc = CreateCompatibleDC(0);
1626 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1628 if (!is_truetype_font_installed(fd[i].face_name))
1630 skip("%s is not installed\n", fd[i].face_name);
1634 memset(&lf, 0, sizeof(lf));
1635 lf.lfHeight = fd[i].requested_height;
1636 lf.lfWeight = fd[i].weight;
1637 strcpy(lf.lfFaceName, fd[i].face_name);
1639 hfont = CreateFontIndirect(&lf);
1642 old_hfont = SelectObject(hdc, hfont);
1643 ret = GetTextMetrics(hdc, &tm);
1644 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1645 if(fd[i].dpi == tm.tmDigitizedAspectX)
1647 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1648 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);
1649 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);
1650 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);
1651 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);
1652 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1653 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);
1655 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);
1658 SelectObject(hdc, old_hfont);
1659 DeleteObject(hfont);
1665 static void test_GetOutlineTextMetrics(void)
1667 OUTLINETEXTMETRIC *otm;
1669 HFONT hfont, hfont_old;
1671 DWORD ret, otm_size;
1674 if (!is_font_installed("Arial"))
1676 skip("Arial is not installed\n");
1682 memset(&lf, 0, sizeof(lf));
1683 strcpy(lf.lfFaceName, "Arial");
1685 lf.lfWeight = FW_NORMAL;
1686 lf.lfPitchAndFamily = DEFAULT_PITCH;
1687 lf.lfQuality = PROOF_QUALITY;
1688 hfont = CreateFontIndirect(&lf);
1691 hfont_old = SelectObject(hdc, hfont);
1692 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1693 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1695 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1697 memset(otm, 0xAA, otm_size);
1698 SetLastError(0xdeadbeef);
1699 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1700 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1701 ok(ret == 1 /* Win9x */ ||
1702 ret == otm->otmSize /* XP*/,
1703 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1704 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1706 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1707 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1708 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1709 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1712 memset(otm, 0xAA, otm_size);
1713 SetLastError(0xdeadbeef);
1714 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1715 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1716 ok(ret == 1 /* Win9x */ ||
1717 ret == otm->otmSize /* XP*/,
1718 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1719 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1721 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1722 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1723 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1724 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1727 /* ask about truncated data */
1728 memset(otm, 0xAA, otm_size);
1729 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1730 SetLastError(0xdeadbeef);
1731 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1732 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1733 ok(ret == 1 /* Win9x */ ||
1734 ret == otm->otmSize /* XP*/,
1735 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1736 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1738 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1739 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1740 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1742 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1744 HeapFree(GetProcessHeap(), 0, otm);
1746 SelectObject(hdc, hfont_old);
1747 DeleteObject(hfont);
1752 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1756 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1757 areaWidth = clientArea->right - clientArea->left,
1759 BOOL lastExtent = FALSE;
1760 PSTR pFirstChar, pLastChar;
1766 int GetTextExtentExPointWWidth;
1769 GetTextMetricsA(hdc, &tm);
1770 y = clientArea->top;
1773 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1779 /* if not at the end of the string, ... */
1780 if (*str == '\0') break;
1781 /* ... add the next word to the current extent */
1782 while (*str != '\0' && *str++ != tm.tmBreakChar);
1784 SetTextJustification(hdc, 0, 0);
1785 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1786 } while ((int) size.cx < areaWidth);
1788 /* ignore trailing break chars */
1790 while (*(pLastChar - 1) == tm.tmBreakChar)
1796 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1798 SetTextJustification(hdc, 0, 0);
1799 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1801 /* do not justify the last extent */
1802 if (*str != '\0' && breakCount > 0)
1804 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1805 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1806 justifiedWidth = size.cx;
1808 else lastExtent = TRUE;
1810 /* catch errors and report them */
1811 if (!lastExtent && (justifiedWidth != areaWidth))
1813 memset(error[nErrors].extent, 0, 100);
1814 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1815 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1821 } while (*str && y < clientArea->bottom);
1823 for (e = 0; e < nErrors; e++)
1825 /* The width returned by GetTextExtentPoint32() is exactly the same
1826 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1827 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1828 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1829 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1833 static void test_SetTextJustification(void)
1840 static char testText[] =
1841 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1842 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1843 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1844 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1845 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1846 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1847 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1849 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1850 GetClientRect( hwnd, &clientArea );
1851 hdc = GetDC( hwnd );
1853 memset(&lf, 0, sizeof lf);
1854 lf.lfCharSet = ANSI_CHARSET;
1855 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1856 lf.lfWeight = FW_DONTCARE;
1858 lf.lfQuality = DEFAULT_QUALITY;
1859 lstrcpyA(lf.lfFaceName, "Times New Roman");
1860 hfont = create_font("Times New Roman", &lf);
1861 SelectObject(hdc, hfont);
1863 testJustification(hdc, testText, &clientArea);
1865 DeleteObject(hfont);
1866 ReleaseDC(hwnd, hdc);
1867 DestroyWindow(hwnd);
1870 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1874 HFONT hfont, hfont_old;
1881 assert(count <= 128);
1883 memset(&lf, 0, sizeof(lf));
1885 lf.lfCharSet = charset;
1887 lstrcpyA(lf.lfFaceName, "Arial");
1888 SetLastError(0xdeadbeef);
1889 hfont = CreateFontIndirectA(&lf);
1890 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1893 hfont_old = SelectObject(hdc, hfont);
1895 cs = GetTextCharsetInfo(hdc, &fs, 0);
1896 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1898 SetLastError(0xdeadbeef);
1899 ret = GetTextFaceA(hdc, sizeof(name), name);
1900 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1902 if (charset == SYMBOL_CHARSET)
1904 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1905 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1909 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1910 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1913 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1915 trace("Can't find codepage for charset %d\n", cs);
1919 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1921 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1923 skip("Font code page %d, looking for code page %d\n",
1924 pGdiGetCodePage(hdc), code_page);
1932 WCHAR unicode_buf[128];
1934 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1936 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1938 SetLastError(0xdeadbeef);
1939 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1940 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1941 count, ret, GetLastError());
1947 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1949 SetLastError(0xdeadbeef);
1950 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1951 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1952 count, ret, GetLastError());
1955 SelectObject(hdc, hfont_old);
1956 DeleteObject(hfont);
1963 static void test_font_charset(void)
1965 static struct charset_data
1969 WORD font_idxA[128], font_idxW[128];
1972 { ANSI_CHARSET, 1252 },
1973 { RUSSIAN_CHARSET, 1251 },
1974 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1978 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1980 win_skip("Skipping the font charset test on a Win9x platform\n");
1984 if (!is_font_installed("Arial"))
1986 skip("Arial is not installed\n");
1990 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1992 if (cd[i].charset == SYMBOL_CHARSET)
1994 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1996 skip("Symbol or Wingdings is not installed\n");
2000 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2001 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2002 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2005 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2008 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2009 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2012 skip("Symbol or Wingdings is not installed\n");
2015 static void test_GetFontUnicodeRanges(void)
2019 HFONT hfont, hfont_old;
2024 if (!pGetFontUnicodeRanges)
2026 win_skip("GetFontUnicodeRanges not available before W2K\n");
2030 memset(&lf, 0, sizeof(lf));
2031 lstrcpyA(lf.lfFaceName, "Arial");
2032 hfont = create_font("Arial", &lf);
2035 hfont_old = SelectObject(hdc, hfont);
2037 size = pGetFontUnicodeRanges(NULL, NULL);
2038 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2040 size = pGetFontUnicodeRanges(hdc, NULL);
2041 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2043 gs = HeapAlloc(GetProcessHeap(), 0, size);
2045 size = pGetFontUnicodeRanges(hdc, gs);
2046 ok(size, "GetFontUnicodeRanges failed\n");
2048 if (0) /* Disabled to limit console spam */
2049 for (i = 0; i < gs->cRanges; i++)
2050 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2051 trace("found %u ranges\n", gs->cRanges);
2053 HeapFree(GetProcessHeap(), 0, gs);
2055 SelectObject(hdc, hfont_old);
2056 DeleteObject(hfont);
2057 ReleaseDC(NULL, hdc);
2060 #define MAX_ENUM_FONTS 4096
2062 struct enum_font_data
2065 LOGFONT lf[MAX_ENUM_FONTS];
2068 struct enum_fullname_data
2071 ENUMLOGFONT elf[MAX_ENUM_FONTS];
2074 struct enum_font_dataW
2077 LOGFONTW lf[MAX_ENUM_FONTS];
2080 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2082 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2083 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2085 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2086 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2088 if (type != TRUETYPE_FONTTYPE) return 1;
2090 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2092 if (0) /* Disabled to limit console spam */
2093 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2094 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2095 if (efd->total < MAX_ENUM_FONTS)
2096 efd->lf[efd->total++] = *lf;
2098 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2103 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2105 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2106 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2108 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2109 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2111 if (type != TRUETYPE_FONTTYPE) return 1;
2113 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2115 if (0) /* Disabled to limit console spam */
2116 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2117 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2118 if (efd->total < MAX_ENUM_FONTS)
2119 efd->lf[efd->total++] = *lf;
2121 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2126 static void get_charset_stats(struct enum_font_data *efd,
2127 int *ansi_charset, int *symbol_charset,
2128 int *russian_charset)
2133 *symbol_charset = 0;
2134 *russian_charset = 0;
2136 for (i = 0; i < efd->total; i++)
2138 switch (efd->lf[i].lfCharSet)
2143 case SYMBOL_CHARSET:
2144 (*symbol_charset)++;
2146 case RUSSIAN_CHARSET:
2147 (*russian_charset)++;
2153 static void get_charset_statsW(struct enum_font_dataW *efd,
2154 int *ansi_charset, int *symbol_charset,
2155 int *russian_charset)
2160 *symbol_charset = 0;
2161 *russian_charset = 0;
2163 for (i = 0; i < efd->total; i++)
2165 switch (efd->lf[i].lfCharSet)
2170 case SYMBOL_CHARSET:
2171 (*symbol_charset)++;
2173 case RUSSIAN_CHARSET:
2174 (*russian_charset)++;
2180 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2182 struct enum_font_data efd;
2183 struct enum_font_dataW efdw;
2186 int i, ret, ansi_charset, symbol_charset, russian_charset;
2188 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2190 if (*font_name && !is_truetype_font_installed(font_name))
2192 skip("%s is not installed\n", font_name);
2198 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2199 * while EnumFontFamiliesEx doesn't.
2201 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2204 * Use EnumFontFamiliesW since win98 crashes when the
2205 * second parameter is NULL using EnumFontFamilies
2208 SetLastError(0xdeadbeef);
2209 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2210 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2213 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2214 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2215 ansi_charset, symbol_charset, russian_charset);
2216 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2217 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2218 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2219 ok(russian_charset > 0 ||
2220 broken(russian_charset == 0), /* NT4 */
2221 "NULL family should enumerate RUSSIAN_CHARSET\n");
2225 SetLastError(0xdeadbeef);
2226 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2227 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2230 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2231 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2232 ansi_charset, symbol_charset, russian_charset);
2233 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2234 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2235 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2236 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2241 SetLastError(0xdeadbeef);
2242 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2243 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2244 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2245 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2246 ansi_charset, symbol_charset, russian_charset,
2247 *font_name ? font_name : "<empty>");
2249 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2251 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2252 for (i = 0; i < efd.total; i++)
2254 /* FIXME: remove completely once Wine is fixed */
2255 if (efd.lf[i].lfCharSet != font_charset)
2258 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2261 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2262 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2263 font_name, efd.lf[i].lfFaceName);
2266 memset(&lf, 0, sizeof(lf));
2267 lf.lfCharSet = ANSI_CHARSET;
2268 lstrcpy(lf.lfFaceName, font_name);
2270 SetLastError(0xdeadbeef);
2271 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2272 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2273 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2274 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2275 ansi_charset, symbol_charset, russian_charset,
2276 *font_name ? font_name : "<empty>");
2277 if (font_charset == SYMBOL_CHARSET)
2280 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2282 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2286 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2287 for (i = 0; i < efd.total; i++)
2289 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2291 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2292 font_name, efd.lf[i].lfFaceName);
2296 /* DEFAULT_CHARSET should enumerate all available charsets */
2297 memset(&lf, 0, sizeof(lf));
2298 lf.lfCharSet = DEFAULT_CHARSET;
2299 lstrcpy(lf.lfFaceName, font_name);
2301 SetLastError(0xdeadbeef);
2302 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2303 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2304 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2305 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2306 ansi_charset, symbol_charset, russian_charset,
2307 *font_name ? font_name : "<empty>");
2308 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2309 for (i = 0; i < efd.total; i++)
2312 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2313 font_name, efd.lf[i].lfFaceName);
2317 switch (font_charset)
2320 ok(ansi_charset > 0,
2321 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2323 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2324 ok(russian_charset > 0,
2325 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2327 case SYMBOL_CHARSET:
2329 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2331 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2332 ok(!russian_charset,
2333 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2335 case DEFAULT_CHARSET:
2336 ok(ansi_charset > 0,
2337 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2338 ok(symbol_charset > 0,
2339 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2340 ok(russian_charset > 0,
2341 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2347 ok(ansi_charset > 0,
2348 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2349 ok(symbol_charset > 0,
2350 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2351 ok(russian_charset > 0,
2352 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2355 memset(&lf, 0, sizeof(lf));
2356 lf.lfCharSet = SYMBOL_CHARSET;
2357 lstrcpy(lf.lfFaceName, font_name);
2359 SetLastError(0xdeadbeef);
2360 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2361 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2362 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2363 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2364 ansi_charset, symbol_charset, russian_charset,
2365 *font_name ? font_name : "<empty>");
2366 if (*font_name && font_charset == ANSI_CHARSET)
2367 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2370 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2371 for (i = 0; i < efd.total; i++)
2373 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2375 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2376 font_name, efd.lf[i].lfFaceName);
2380 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2381 ok(symbol_charset > 0,
2382 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2383 ok(!russian_charset,
2384 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2390 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2392 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2394 if (type != TRUETYPE_FONTTYPE) return 1;
2396 if (efd->total < MAX_ENUM_FONTS)
2397 efd->lf[efd->total++] = *lf;
2399 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2404 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2406 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2408 if (type != TRUETYPE_FONTTYPE) return 1;
2410 if (efnd->total < MAX_ENUM_FONTS)
2411 efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2413 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2418 static void test_EnumFontFamiliesEx_default_charset(void)
2420 struct enum_font_data efd;
2421 LOGFONT gui_font, enum_font;
2425 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2426 ok(ret, "GetObject failed.\n");
2433 memset(&enum_font, 0, sizeof(enum_font));
2434 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2435 enum_font.lfCharSet = DEFAULT_CHARSET;
2436 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2439 if (efd.total == 0) {
2440 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2443 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2445 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet || broken(system_lang_id == LANG_ARABIC),
2446 "(%s) got charset %d expected %d\n",
2447 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2452 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2454 HFONT hfont, hfont_prev;
2456 GLYPHMETRICS gm1, gm2;
2460 if(!pGetGlyphIndicesA)
2463 /* negative widths are handled just as positive ones */
2464 lf2.lfWidth = -lf->lfWidth;
2466 SetLastError(0xdeadbeef);
2467 hfont = CreateFontIndirectA(lf);
2468 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2469 check_font("original", lf, hfont);
2471 hfont_prev = SelectObject(hdc, hfont);
2473 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2474 if (ret == GDI_ERROR || idx == 0xffff)
2476 SelectObject(hdc, hfont_prev);
2477 DeleteObject(hfont);
2478 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2482 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2483 memset(&gm1, 0xab, sizeof(gm1));
2484 SetLastError(0xdeadbeef);
2485 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2486 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2488 SelectObject(hdc, hfont_prev);
2489 DeleteObject(hfont);
2491 SetLastError(0xdeadbeef);
2492 hfont = CreateFontIndirectA(&lf2);
2493 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2494 check_font("negative width", &lf2, hfont);
2496 hfont_prev = SelectObject(hdc, hfont);
2498 memset(&gm2, 0xbb, sizeof(gm2));
2499 SetLastError(0xdeadbeef);
2500 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2501 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2503 SelectObject(hdc, hfont_prev);
2504 DeleteObject(hfont);
2506 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2507 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2508 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2509 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2510 gm1.gmCellIncX == gm2.gmCellIncX &&
2511 gm1.gmCellIncY == gm2.gmCellIncY,
2512 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2513 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2514 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2515 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2516 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2519 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2520 #include "pshpack2.h"
2524 SHORT xAvgCharWidth;
2525 USHORT usWeightClass;
2526 USHORT usWidthClass;
2528 SHORT ySubscriptXSize;
2529 SHORT ySubscriptYSize;
2530 SHORT ySubscriptXOffset;
2531 SHORT ySubscriptYOffset;
2532 SHORT ySuperscriptXSize;
2533 SHORT ySuperscriptYSize;
2534 SHORT ySuperscriptXOffset;
2535 SHORT ySuperscriptYOffset;
2536 SHORT yStrikeoutSize;
2537 SHORT yStrikeoutPosition;
2540 ULONG ulUnicodeRange1;
2541 ULONG ulUnicodeRange2;
2542 ULONG ulUnicodeRange3;
2543 ULONG ulUnicodeRange4;
2546 USHORT usFirstCharIndex;
2547 USHORT usLastCharIndex;
2548 /* According to the Apple spec, original version didn't have the below fields,
2549 * version numbers were taken from the OpenType spec.
2551 /* version 0 (TrueType 1.5) */
2552 USHORT sTypoAscender;
2553 USHORT sTypoDescender;
2554 USHORT sTypoLineGap;
2556 USHORT usWinDescent;
2557 /* version 1 (TrueType 1.66) */
2558 ULONG ulCodePageRange1;
2559 ULONG ulCodePageRange2;
2560 /* version 2 (OpenType 1.2) */
2563 USHORT usDefaultChar;
2565 USHORT usMaxContext;
2567 #include "poppack.h"
2569 #ifdef WORDS_BIGENDIAN
2570 #define GET_BE_WORD(x) (x)
2571 #define GET_BE_DWORD(x) (x)
2573 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2574 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2577 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2578 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2579 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2580 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2581 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2582 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2595 } cmap_encoding_record;
2603 BYTE glyph_ids[256];
2613 USHORT search_range;
2614 USHORT entry_selector;
2617 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2620 USHORT start_count[seg_countx2 / 2];
2621 USHORT id_delta[seg_countx2 / 2];
2622 USHORT id_range_offset[seg_countx2 / 2];
2632 USHORT id_range_offset;
2633 } cmap_format_4_seg;
2635 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2637 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2638 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2639 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2640 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2641 os2->panose.bWeight, os2->panose.bProportion);
2644 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2647 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2651 for(i = 0; i < 256; i++)
2653 if(cmap->glyph_ids[i] == 0) continue;
2655 if(*first == 256) *first = i;
2657 if(*first == 256) return FALSE;
2661 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2663 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2664 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2665 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2666 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2667 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2670 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2673 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2674 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2675 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2679 for(i = 0; i < seg_count; i++)
2682 cmap_format_4_seg seg;
2684 get_seg4(cmap, i, &seg);
2685 for(code = seg.start_count; code <= seg.end_count; code++)
2687 if(seg.id_range_offset == 0)
2688 index = (seg.id_delta + code) & 0xffff;
2691 index = seg.id_range_offset / 2
2692 + code - seg.start_count
2695 /* some fonts have broken last segment */
2696 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2697 index = GET_BE_WORD(glyph_ids[index]);
2700 trace("segment %04x/%04x index %04x points to nowhere\n",
2701 seg.start_count, seg.end_count, index);
2704 if(index) index += seg.id_delta;
2706 if(*first == 0x10000)
2707 *last = *first = code;
2713 if(*first == 0x10000) return FALSE;
2717 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2720 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2722 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2724 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2725 return (BYTE *)header + GET_BE_DWORD(record->offset);
2738 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2741 cmap_header *header;
2746 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2747 ok(size != GDI_ERROR, "no cmap table found\n");
2748 if(size == GDI_ERROR) return FALSE;
2750 header = HeapAlloc(GetProcessHeap(), 0, size);
2751 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2752 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2753 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2755 cmap = get_cmap(header, 3, 1);
2757 *cmap_type = cmap_ms_unicode;
2760 cmap = get_cmap(header, 3, 0);
2761 if(cmap) *cmap_type = cmap_ms_symbol;
2765 *cmap_type = cmap_none;
2769 format = GET_BE_WORD(*(WORD *)cmap);
2773 r = get_first_last_from_cmap0(cmap, first, last);
2776 r = get_first_last_from_cmap4(cmap, first, last, size);
2779 trace("unhandled cmap format %d\n", format);
2784 HeapFree(GetProcessHeap(), 0, header);
2788 #define TT_PLATFORM_MICROSOFT 3
2789 #define TT_MS_ID_SYMBOL_CS 0
2790 #define TT_MS_ID_UNICODE_CS 1
2791 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2792 #define TT_NAME_ID_FONT_FAMILY 1
2793 #define TT_NAME_ID_FONT_SUBFAMILY 2
2794 #define TT_NAME_ID_UNIQUE_ID 3
2795 #define TT_NAME_ID_FULL_NAME 4
2797 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2799 struct sfnt_name_header
2802 USHORT number_of_record;
2803 USHORT storage_offset;
2815 LONG size, offset, length;
2821 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2822 ok(size != GDI_ERROR, "no name table found\n");
2823 if(size == GDI_ERROR) return FALSE;
2825 data = HeapAlloc(GetProcessHeap(), 0, size);
2826 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2827 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2829 header = (void *)data;
2830 header->format = GET_BE_WORD(header->format);
2831 header->number_of_record = GET_BE_WORD(header->number_of_record);
2832 header->storage_offset = GET_BE_WORD(header->storage_offset);
2833 if (header->format != 0)
2835 trace("got format %u\n", header->format);
2838 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2840 trace("number records out of range: %d\n", header->number_of_record);
2843 if (header->storage_offset >= size)
2845 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2849 entry = (void *)&header[1];
2850 for (i = 0; i < header->number_of_record; i++)
2852 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2853 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
2854 GET_BE_WORD(entry[i].language_id) != language_id ||
2855 GET_BE_WORD(entry[i].name_id) != name_id)
2860 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2861 length = GET_BE_WORD(entry[i].length);
2862 if (offset + length > size)
2864 trace("entry %d is out of range\n", i);
2867 if (length >= out_size)
2869 trace("buffer too small for entry %d\n", i);
2873 name = (WCHAR *)(data + offset);
2874 for (c = 0; c < length / 2; c++)
2875 out_buf[c] = GET_BE_WORD(name[c]);
2883 HeapFree(GetProcessHeap(), 0, data);
2887 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2890 HFONT hfont, hfont_old;
2894 const char *font_name = lf->lfFaceName;
2895 DWORD cmap_first = 0, cmap_last = 0;
2896 UINT ascent, descent, cell_height;
2897 cmap_type cmap_type;
2898 BOOL sys_lang_non_english;
2900 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2903 SetLastError(0xdeadbeef);
2904 hfont = CreateFontIndirectA(lf);
2905 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2907 hfont_old = SelectObject(hdc, hfont);
2909 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2910 if (size == GDI_ERROR)
2912 trace("OS/2 chunk was not found\n");
2915 if (size > sizeof(tt_os2))
2917 trace("got too large OS/2 chunk of size %u\n", size);
2918 size = sizeof(tt_os2);
2921 memset(&tt_os2, 0, sizeof(tt_os2));
2922 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2923 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2925 ascent = GET_BE_WORD(tt_os2.usWinAscent);
2926 descent = GET_BE_WORD(tt_os2.usWinDescent);
2927 cell_height = ascent + descent;
2928 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
2929 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
2931 SetLastError(0xdeadbeef);
2932 ret = GetTextMetricsA(hdc, &tmA);
2933 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2935 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2937 skip("Unable to retrieve first and last glyphs from cmap\n");
2941 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2942 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2943 UINT os2_first_char, os2_last_char, default_char, break_char;
2947 version = GET_BE_WORD(tt_os2.version);
2949 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2950 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2951 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2952 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2954 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2955 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2956 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2958 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2963 case 1257: /* Baltic */
2964 expect_last_W = 0xf8fd;
2967 expect_last_W = 0xf0ff;
2969 expect_break_W = 0x20;
2970 expect_default_W = expect_break_W - 1;
2971 expect_first_A = 0x1e;
2972 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2976 expect_first_W = cmap_first;
2977 expect_last_W = min(cmap_last, os2_last_char);
2978 if(os2_first_char <= 1)
2979 expect_break_W = os2_first_char + 2;
2980 else if(os2_first_char > 0xff)
2981 expect_break_W = 0x20;
2983 expect_break_W = os2_first_char;
2984 expect_default_W = expect_break_W - 1;
2985 expect_first_A = expect_default_W - 1;
2986 expect_last_A = min(expect_last_W, 0xff);
2988 expect_break_A = expect_break_W;
2989 expect_default_A = expect_default_W;
2991 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2992 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2993 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2994 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2995 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2997 ok(tmA.tmFirstChar == expect_first_A ||
2998 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2999 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3000 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3001 ok(tmA.tmLastChar == expect_last_A ||
3002 tmA.tmLastChar == 0xff /* win9x */,
3003 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3005 skip("tmLastChar is DBCS lead byte\n");
3006 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3007 font_name, tmA.tmBreakChar, expect_break_A);
3008 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3009 "A: tmDefaultChar for %s got %02x expected %02x\n",
3010 font_name, tmA.tmDefaultChar, expect_default_A);
3013 SetLastError(0xdeadbeef);
3014 ret = GetTextMetricsW(hdc, &tmW);
3015 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3016 "GetTextMetricsW error %u\n", GetLastError());
3019 /* Wine uses the os2 first char */
3020 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3021 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3022 font_name, tmW.tmFirstChar, expect_first_W);
3024 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3025 font_name, tmW.tmFirstChar, expect_first_W);
3027 /* Wine uses the os2 last char */
3028 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3029 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3030 font_name, tmW.tmLastChar, expect_last_W);
3032 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3033 font_name, tmW.tmLastChar, expect_last_W);
3034 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3035 font_name, tmW.tmBreakChar, expect_break_W);
3036 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3037 "W: tmDefaultChar for %s got %02x expected %02x\n",
3038 font_name, tmW.tmDefaultChar, expect_default_W);
3040 /* Test the aspect ratio while we have tmW */
3041 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3042 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3043 tmW.tmDigitizedAspectX, ret);
3044 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3045 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3046 tmW.tmDigitizedAspectX, ret);
3050 /* test FF_ values */
3051 switch(tt_os2.panose.bFamilyType)
3055 case PAN_FAMILY_TEXT_DISPLAY:
3056 case PAN_FAMILY_PICTORIAL:
3058 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3059 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3061 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3064 switch(tt_os2.panose.bSerifStyle)
3069 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3072 case PAN_SERIF_COVE:
3073 case PAN_SERIF_OBTUSE_COVE:
3074 case PAN_SERIF_SQUARE_COVE:
3075 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3076 case PAN_SERIF_SQUARE:
3077 case PAN_SERIF_THIN:
3078 case PAN_SERIF_BONE:
3079 case PAN_SERIF_EXAGGERATED:
3080 case PAN_SERIF_TRIANGLE:
3081 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3084 case PAN_SERIF_NORMAL_SANS:
3085 case PAN_SERIF_OBTUSE_SANS:
3086 case PAN_SERIF_PERP_SANS:
3087 case PAN_SERIF_FLARED:
3088 case PAN_SERIF_ROUNDED:
3089 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3094 case PAN_FAMILY_SCRIPT:
3095 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3098 case PAN_FAMILY_DECORATIVE:
3099 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3103 test_negative_width(hdc, lf);
3106 SelectObject(hdc, hfont_old);
3107 DeleteObject(hfont);
3112 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3114 INT *enumed = (INT *)lParam;
3116 if (type == TRUETYPE_FONTTYPE)
3119 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3124 static void test_GetTextMetrics(void)
3130 /* Report only once */
3131 if(!pGetGlyphIndicesA)
3132 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3136 memset(&lf, 0, sizeof(lf));
3137 lf.lfCharSet = DEFAULT_CHARSET;
3139 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3140 trace("Tested metrics of %d truetype fonts\n", enumed);
3145 static void test_nonexistent_font(void)
3153 { "Times New Roman Baltic", 186 },
3154 { "Times New Roman CE", 238 },
3155 { "Times New Roman CYR", 204 },
3156 { "Times New Roman Greek", 161 },
3157 { "Times New Roman TUR", 162 }
3163 INT cs, expected_cs, i;
3164 char buf[LF_FACESIZE];
3166 if (!is_truetype_font_installed("Arial") ||
3167 !is_truetype_font_installed("Times New Roman"))
3169 skip("Arial or Times New Roman not installed\n");
3173 expected_cs = GetACP();
3174 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3176 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3179 expected_cs = csi.ciCharset;
3180 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3184 memset(&lf, 0, sizeof(lf));
3186 lf.lfWeight = FW_REGULAR;
3187 lf.lfCharSet = ANSI_CHARSET;
3188 lf.lfPitchAndFamily = FF_SWISS;
3189 strcpy(lf.lfFaceName, "Nonexistent font");
3190 hfont = CreateFontIndirectA(&lf);
3191 hfont = SelectObject(hdc, hfont);
3192 GetTextFaceA(hdc, sizeof(buf), buf);
3193 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3194 cs = GetTextCharset(hdc);
3195 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3196 DeleteObject(SelectObject(hdc, hfont));
3198 memset(&lf, 0, sizeof(lf));
3200 lf.lfWeight = FW_DONTCARE;
3201 strcpy(lf.lfFaceName, "Nonexistent font");
3202 hfont = CreateFontIndirectA(&lf);
3203 hfont = SelectObject(hdc, hfont);
3204 GetTextFaceA(hdc, sizeof(buf), buf);
3205 todo_wine /* Wine uses Arial for all substitutions */
3206 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3207 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3208 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3210 cs = GetTextCharset(hdc);
3211 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3212 DeleteObject(SelectObject(hdc, hfont));
3214 memset(&lf, 0, sizeof(lf));
3216 lf.lfWeight = FW_REGULAR;
3217 strcpy(lf.lfFaceName, "Nonexistent font");
3218 hfont = CreateFontIndirectA(&lf);
3219 hfont = SelectObject(hdc, hfont);
3220 GetTextFaceA(hdc, sizeof(buf), buf);
3221 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3222 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3223 cs = GetTextCharset(hdc);
3224 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3225 DeleteObject(SelectObject(hdc, hfont));
3227 memset(&lf, 0, sizeof(lf));
3229 lf.lfWeight = FW_DONTCARE;
3230 strcpy(lf.lfFaceName, "Times New Roman");
3231 hfont = CreateFontIndirectA(&lf);
3232 hfont = SelectObject(hdc, hfont);
3233 GetTextFaceA(hdc, sizeof(buf), buf);
3234 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3235 cs = GetTextCharset(hdc);
3236 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3237 DeleteObject(SelectObject(hdc, hfont));
3239 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3241 memset(&lf, 0, sizeof(lf));
3243 lf.lfWeight = FW_REGULAR;
3244 strcpy(lf.lfFaceName, font_subst[i].name);
3245 hfont = CreateFontIndirectA(&lf);
3246 hfont = SelectObject(hdc, hfont);
3247 cs = GetTextCharset(hdc);
3248 if (font_subst[i].charset == expected_cs)
3250 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3251 GetTextFaceA(hdc, sizeof(buf), buf);
3252 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3256 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3257 GetTextFaceA(hdc, sizeof(buf), buf);
3258 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3259 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3261 DeleteObject(SelectObject(hdc, hfont));
3263 memset(&lf, 0, sizeof(lf));
3265 lf.lfWeight = FW_DONTCARE;
3266 strcpy(lf.lfFaceName, font_subst[i].name);
3267 hfont = CreateFontIndirectA(&lf);
3268 hfont = SelectObject(hdc, hfont);
3269 GetTextFaceA(hdc, sizeof(buf), buf);
3270 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3271 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3272 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3273 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3274 "got %s for font %s\n", buf, font_subst[i].name);
3275 cs = GetTextCharset(hdc);
3276 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3277 DeleteObject(SelectObject(hdc, hfont));
3283 static void test_GdiRealizationInfo(void)
3288 HFONT hfont, hfont_old;
3291 if(!pGdiRealizationInfo)
3293 win_skip("GdiRealizationInfo not available\n");
3299 memset(info, 0xcc, sizeof(info));
3300 r = pGdiRealizationInfo(hdc, info);
3301 ok(r != 0, "ret 0\n");
3302 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3303 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3305 if (!is_truetype_font_installed("Arial"))
3307 skip("skipping GdiRealizationInfo with truetype font\n");
3311 memset(&lf, 0, sizeof(lf));
3312 strcpy(lf.lfFaceName, "Arial");
3314 lf.lfWeight = FW_NORMAL;
3315 hfont = CreateFontIndirectA(&lf);
3316 hfont_old = SelectObject(hdc, hfont);
3318 memset(info, 0xcc, sizeof(info));
3319 r = pGdiRealizationInfo(hdc, info);
3320 ok(r != 0, "ret 0\n");
3321 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3322 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3324 DeleteObject(SelectObject(hdc, hfont_old));
3330 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3331 the nul in the count of characters copied when the face name buffer is not
3332 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3333 always includes it. */
3334 static void test_GetTextFace(void)
3336 static const char faceA[] = "Tahoma";
3337 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3340 char bufA[LF_FACESIZE];
3341 WCHAR bufW[LF_FACESIZE];
3346 if(!is_font_installed("Tahoma"))
3348 skip("Tahoma is not installed so skipping this test\n");
3353 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3354 f = CreateFontIndirectA(&fA);
3355 ok(f != NULL, "CreateFontIndirectA failed\n");
3358 g = SelectObject(dc, f);
3359 n = GetTextFaceA(dc, sizeof bufA, bufA);
3360 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3361 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3363 /* Play with the count arg. */
3365 n = GetTextFaceA(dc, 0, bufA);
3366 ok(n == 0, "GetTextFaceA returned %d\n", n);
3367 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3370 n = GetTextFaceA(dc, 1, bufA);
3371 ok(n == 0, "GetTextFaceA returned %d\n", n);
3372 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3374 bufA[0] = 'x'; bufA[1] = 'y';
3375 n = GetTextFaceA(dc, 2, bufA);
3376 ok(n == 1, "GetTextFaceA returned %d\n", n);
3377 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3379 n = GetTextFaceA(dc, 0, NULL);
3380 ok(n == sizeof faceA ||
3381 broken(n == 0), /* win98, winMe */
3382 "GetTextFaceA returned %d\n", n);
3384 DeleteObject(SelectObject(dc, g));
3385 ReleaseDC(NULL, dc);
3388 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3389 SetLastError(0xdeadbeef);
3390 f = CreateFontIndirectW(&fW);
3391 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3393 win_skip("CreateFontIndirectW is not implemented\n");
3396 ok(f != NULL, "CreateFontIndirectW failed\n");
3399 g = SelectObject(dc, f);
3400 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3401 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3402 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3404 /* Play with the count arg. */
3406 n = GetTextFaceW(dc, 0, bufW);
3407 ok(n == 0, "GetTextFaceW returned %d\n", n);
3408 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3411 n = GetTextFaceW(dc, 1, bufW);
3412 ok(n == 1, "GetTextFaceW returned %d\n", n);
3413 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3415 bufW[0] = 'x'; bufW[1] = 'y';
3416 n = GetTextFaceW(dc, 2, bufW);
3417 ok(n == 2, "GetTextFaceW returned %d\n", n);
3418 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3420 n = GetTextFaceW(dc, 0, NULL);
3421 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3423 DeleteObject(SelectObject(dc, g));
3424 ReleaseDC(NULL, dc);
3427 static void test_orientation(void)
3429 static const char test_str[11] = "Test String";
3432 HFONT hfont, old_hfont;
3435 if (!is_truetype_font_installed("Arial"))
3437 skip("Arial is not installed\n");
3441 hdc = CreateCompatibleDC(0);
3442 memset(&lf, 0, sizeof(lf));
3443 lstrcpyA(lf.lfFaceName, "Arial");
3445 lf.lfOrientation = lf.lfEscapement = 900;
3446 hfont = create_font("orientation", &lf);
3447 old_hfont = SelectObject(hdc, hfont);
3448 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3449 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3450 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3451 SelectObject(hdc, old_hfont);
3452 DeleteObject(hfont);
3456 static void test_oemcharset(void)
3460 HFONT hfont, old_hfont;
3463 hdc = CreateCompatibleDC(0);
3464 ZeroMemory(&lf, sizeof(lf));
3466 lf.lfCharSet = OEM_CHARSET;
3467 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3468 lstrcpyA(lf.lfFaceName, "Terminal");
3469 hfont = CreateFontIndirectA(&lf);
3470 old_hfont = SelectObject(hdc, hfont);
3471 charset = GetTextCharset(hdc);
3473 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3474 hfont = SelectObject(hdc, old_hfont);
3475 GetObjectA(hfont, sizeof(clf), &clf);
3476 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3477 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3478 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3479 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3480 DeleteObject(hfont);
3484 static void test_GetGlyphOutline(void)
3487 GLYPHMETRICS gm, gm2;
3489 HFONT hfont, old_hfont;
3498 {ANSI_CHARSET, 0x30, 0x30},
3499 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3500 {HANGEUL_CHARSET, 0x8141, 0xac02},
3501 {JOHAB_CHARSET, 0x8446, 0x3135},
3502 {GB2312_CHARSET, 0x8141, 0x4e04},
3503 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3507 if (!is_truetype_font_installed("Tahoma"))
3509 skip("Tahoma is not installed\n");
3513 hdc = CreateCompatibleDC(0);
3514 memset(&lf, 0, sizeof(lf));
3516 lstrcpyA(lf.lfFaceName, "Tahoma");
3517 SetLastError(0xdeadbeef);
3518 hfont = CreateFontIndirectA(&lf);
3519 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3520 old_hfont = SelectObject(hdc, hfont);
3522 memset(&gm, 0, sizeof(gm));
3523 SetLastError(0xdeadbeef);
3524 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3525 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3527 memset(&gm, 0, sizeof(gm));
3528 SetLastError(0xdeadbeef);
3529 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3530 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3531 ok(GetLastError() == 0xdeadbeef ||
3532 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3533 "expected 0xdeadbeef, got %u\n", GetLastError());
3535 memset(&gm, 0, sizeof(gm));
3536 SetLastError(0xdeadbeef);
3537 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3538 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3539 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3541 memset(&gm, 0, sizeof(gm));
3542 SetLastError(0xdeadbeef);
3543 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3544 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3546 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3547 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3550 /* test for needed buffer size request on space char */
3551 memset(&gm, 0, sizeof(gm));
3552 SetLastError(0xdeadbeef);
3553 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3554 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3555 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3557 /* requesting buffer size for space char + error */
3558 memset(&gm, 0, sizeof(gm));
3559 SetLastError(0xdeadbeef);
3560 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3561 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3563 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3564 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3567 SelectObject(hdc, old_hfont);
3568 DeleteObject(hfont);
3570 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3572 lf.lfFaceName[0] = '\0';
3573 lf.lfCharSet = c[i].cs;
3574 lf.lfPitchAndFamily = 0;
3575 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3577 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3581 old_hfont = SelectObject(hdc, hfont);
3583 /* expected to ignore superfluous bytes (sigle-byte character) */
3584 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3585 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3586 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3588 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3589 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3590 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3592 /* expected to ignore superfluous bytes (double-byte character) */
3593 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3594 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3595 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3596 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3598 /* expected to match wide-char version results */
3599 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3600 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3602 hfont = SelectObject(hdc, old_hfont);
3603 DeleteObject(hfont);
3609 /* bug #9995: there is a limit to the character width that can be specified */
3610 static void test_GetTextMetrics2(const char *fontname, int font_height)
3616 int ave_width, height, width, ratio, scale;
3618 if (!is_truetype_font_installed( fontname)) {
3619 skip("%s is not installed\n", fontname);
3622 hdc = CreateCompatibleDC(0);
3623 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3624 /* select width = 0 */
3625 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3626 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3627 DEFAULT_QUALITY, VARIABLE_PITCH,
3629 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3630 of = SelectObject( hdc, hf);
3631 ret = GetTextMetricsA( hdc, &tm);
3632 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3633 height = tm.tmHeight;
3634 ave_width = tm.tmAveCharWidth;
3635 SelectObject( hdc, of);
3638 trace("height %d, ave width %d\n", height, ave_width);
3640 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3642 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3643 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3644 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3645 ok(hf != 0, "CreateFont failed\n");
3646 of = SelectObject(hdc, hf);
3647 ret = GetTextMetrics(hdc, &tm);
3648 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3649 SelectObject(hdc, of);
3652 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3658 ratio = width / height;
3659 scale = width / ave_width;
3661 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3662 width, height, ratio, width, ave_width, scale);
3664 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3667 static void test_CreateFontIndirect(void)
3669 LOGFONTA lf, getobj_lf;
3672 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3674 memset(&lf, 0, sizeof(lf));
3675 lf.lfCharSet = ANSI_CHARSET;
3676 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3679 lf.lfQuality = DEFAULT_QUALITY;
3680 lf.lfItalic = FALSE;
3681 lf.lfWeight = FW_DONTCARE;
3683 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3685 lstrcpyA(lf.lfFaceName, TestName[i]);
3686 hfont = CreateFontIndirectA(&lf);
3687 ok(hfont != 0, "CreateFontIndirectA failed\n");
3688 SetLastError(0xdeadbeef);
3689 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3690 ok(ret, "GetObject failed: %d\n", GetLastError());
3691 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3692 ok(lf.lfWeight == getobj_lf.lfWeight ||
3693 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3694 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3695 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3696 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3697 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3698 DeleteObject(hfont);
3702 static void test_CreateFontIndirectEx(void)
3704 ENUMLOGFONTEXDVA lfex;
3707 if (!pCreateFontIndirectExA)
3709 win_skip("CreateFontIndirectExA is not available\n");
3713 if (!is_truetype_font_installed("Arial"))
3715 skip("Arial is not installed\n");
3719 SetLastError(0xdeadbeef);
3720 hfont = pCreateFontIndirectExA(NULL);
3721 ok(hfont == NULL, "got %p\n", hfont);
3722 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3724 memset(&lfex, 0, sizeof(lfex));
3725 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3726 hfont = pCreateFontIndirectExA(&lfex);
3727 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3729 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3730 DeleteObject(hfont);
3733 static void free_font(void *font)
3735 UnmapViewOfFile(font);
3738 static void *load_font(const char *font_name, DWORD *font_size)
3740 char file_name[MAX_PATH];
3741 HANDLE file, mapping;
3744 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3745 strcat(file_name, "\\fonts\\");
3746 strcat(file_name, font_name);
3748 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3749 if (file == INVALID_HANDLE_VALUE) return NULL;
3751 *font_size = GetFileSize(file, NULL);
3753 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3760 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3763 CloseHandle(mapping);
3767 static void test_AddFontMemResource(void)
3770 DWORD font_size, num_fonts;
3774 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3776 win_skip("AddFontMemResourceEx is not available on this platform\n");
3780 font = load_font("sserife.fon", &font_size);
3783 skip("Unable to locate and load font sserife.fon\n");
3787 SetLastError(0xdeadbeef);
3788 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3789 ok(!ret, "AddFontMemResourceEx should fail\n");
3790 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3791 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3794 SetLastError(0xdeadbeef);
3795 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3796 ok(!ret, "AddFontMemResourceEx should fail\n");
3797 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3798 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3801 SetLastError(0xdeadbeef);
3802 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3803 ok(!ret, "AddFontMemResourceEx should fail\n");
3804 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3805 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3808 SetLastError(0xdeadbeef);
3809 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3810 ok(!ret, "AddFontMemResourceEx should fail\n");
3811 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3812 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3815 SetLastError(0xdeadbeef);
3816 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3817 ok(!ret, "AddFontMemResourceEx should fail\n");
3818 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3819 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3822 SetLastError(0xdeadbeef);
3823 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3824 ok(!ret, "AddFontMemResourceEx should fail\n");
3825 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3826 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3829 num_fonts = 0xdeadbeef;
3830 SetLastError(0xdeadbeef);
3831 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3832 ok(!ret, "AddFontMemResourceEx should fail\n");
3833 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3834 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3836 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3838 if (0) /* hangs under windows 2000 */
3840 num_fonts = 0xdeadbeef;
3841 SetLastError(0xdeadbeef);
3842 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3843 ok(!ret, "AddFontMemResourceEx should fail\n");
3844 ok(GetLastError() == 0xdeadbeef,
3845 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3847 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3850 num_fonts = 0xdeadbeef;
3851 SetLastError(0xdeadbeef);
3852 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3853 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3854 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3855 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3859 SetLastError(0xdeadbeef);
3860 bRet = pRemoveFontMemResourceEx(ret);
3861 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3863 /* test invalid pointer to number of loaded fonts */
3864 font = load_font("sserife.fon", &font_size);
3865 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3867 SetLastError(0xdeadbeef);
3868 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3869 ok(!ret, "AddFontMemResourceEx should fail\n");
3870 ok(GetLastError() == 0xdeadbeef,
3871 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3874 SetLastError(0xdeadbeef);
3875 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3876 ok(!ret, "AddFontMemResourceEx should fail\n");
3877 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3878 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3884 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3888 if (type != TRUETYPE_FONTTYPE) return 1;
3890 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3892 lf = (LOGFONT *)lparam;
3897 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3902 if (type != TRUETYPE_FONTTYPE) return 1;
3904 lf = (LOGFONT *)lparam;
3905 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3908 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3915 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3920 static void test_EnumFonts(void)
3926 if (!is_truetype_font_installed("Arial"))
3928 skip("Arial is not installed\n");
3932 /* Windows uses localized font face names, so Arial Bold won't be found */
3933 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3935 skip("User locale is not English, skipping the test\n");
3939 hdc = CreateCompatibleDC(0);
3941 /* check that the enumproc's retval is returned */
3942 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
3943 ok(ret == 0xcafe, "got %08x\n", ret);
3945 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3946 ok(!ret, "font Arial is not enumerated\n");
3947 ret = strcmp(lf.lfFaceName, "Arial");
3948 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3949 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3951 lstrcpy(lf.lfFaceName, "Arial");
3952 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3953 ok(!ret, "font Arial is not enumerated\n");
3954 ret = strcmp(lf.lfFaceName, "Arial");
3955 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3956 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3958 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3959 ok(!ret, "font Arial Bold is not enumerated\n");
3960 ret = strcmp(lf.lfFaceName, "Arial");
3961 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3962 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3964 lstrcpy(lf.lfFaceName, "Arial Bold");
3965 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3966 ok(ret, "font Arial Bold should not be enumerated\n");
3968 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3969 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3970 ret = strcmp(lf.lfFaceName, "Arial");
3971 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3972 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3974 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3975 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3976 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3978 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3979 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3981 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3982 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3983 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3988 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3990 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3991 const char *fullname = (const char *)lParam;
3993 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3998 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4003 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4010 static void test_fullname(void)
4012 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4013 WCHAR bufW[LF_FULLFACESIZE];
4014 char bufA[LF_FULLFACESIZE];
4021 hdc = CreateCompatibleDC(0);
4022 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4024 memset(&lf, 0, sizeof(lf));
4025 lf.lfCharSet = ANSI_CHARSET;
4026 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4029 lf.lfQuality = DEFAULT_QUALITY;
4030 lf.lfItalic = FALSE;
4031 lf.lfWeight = FW_DONTCARE;
4033 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4035 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4037 skip("%s is not installed\n", TestName[i]);
4041 lstrcpyA(lf.lfFaceName, TestName[i]);
4042 hfont = CreateFontIndirectA(&lf);
4043 ok(hfont != 0, "CreateFontIndirectA failed\n");
4045 of = SelectObject(hdc, hfont);
4048 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4049 ok(ret, "face full name could not be read\n");
4050 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4051 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4052 SelectObject(hdc, of);
4053 DeleteObject(hfont);
4058 static WCHAR *prepend_at(WCHAR *family)
4063 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4068 static void test_fullname2_helper(const char *Family)
4070 char *FamilyName, *FaceName, *StyleName, *otmStr;
4071 struct enum_fullname_data efnd;
4078 DWORD otm_size, ret, buf_size;
4079 OUTLINETEXTMETRICA *otm;
4080 BOOL want_vertical, get_vertical;
4081 want_vertical = ( Family[0] == '@' );
4083 hdc = CreateCompatibleDC(0);
4084 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4086 memset(&lf, 0, sizeof(lf));
4087 lf.lfCharSet = DEFAULT_CHARSET;
4088 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4091 lf.lfQuality = DEFAULT_QUALITY;
4092 lf.lfItalic = FALSE;
4093 lf.lfWeight = FW_DONTCARE;
4094 lstrcpy(lf.lfFaceName, Family);
4096 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4097 if (efnd.total == 0)
4098 skip("%s is not installed\n", lf.lfFaceName);
4100 for (i = 0; i < efnd.total; i++)
4102 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4103 FaceName = (char *)efnd.elf[i].elfFullName;
4104 StyleName = (char *)efnd.elf[i].elfStyle;
4106 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4108 get_vertical = ( FamilyName[0] == '@' );
4109 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4111 lstrcpyA(lf.lfFaceName, FaceName);
4112 hfont = CreateFontIndirectA(&lf);
4113 ok(hfont != 0, "CreateFontIndirectA failed\n");
4115 of = SelectObject(hdc, hfont);
4116 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4117 ok(buf_size != GDI_ERROR, "no name table found\n");
4118 if (buf_size == GDI_ERROR) continue;
4120 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4121 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4123 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4124 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4125 memset(otm, 0, otm_size);
4126 ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4127 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4128 if (ret == 0) continue;
4132 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4135 trace("no localized FONT_FAMILY found.\n");
4136 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4138 ok(ret, "FAMILY (family name) could not be read\n");
4139 if (want_vertical) bufW = prepend_at(bufW);
4140 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4141 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4142 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4143 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4147 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4150 trace("no localized FULL_NAME found.\n");
4151 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4153 ok(ret, "FULL_NAME (face name) could not be read\n");
4154 if (want_vertical) bufW = prepend_at(bufW);
4155 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4156 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4157 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4158 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4162 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4165 trace("no localized FONT_SUBFAMILY font.\n");
4166 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4168 ok(ret, "SUBFAMILY (style name) could not be read\n");
4169 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4170 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4171 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4172 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4176 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4179 trace("no localized UNIQUE_ID found.\n");
4180 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4182 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4183 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4184 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4185 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4187 SelectObject(hdc, of);
4188 DeleteObject(hfont);
4190 HeapFree(GetProcessHeap(), 0, otm);
4191 HeapFree(GetProcessHeap(), 0, bufW);
4192 HeapFree(GetProcessHeap(), 0, bufA);
4197 static void test_fullname2(void)
4199 test_fullname2_helper("Arial");
4200 test_fullname2_helper("DejaVu Sans");
4201 test_fullname2_helper("Lucida Sans");
4202 test_fullname2_helper("Tahoma");
4203 test_fullname2_helper("Webdings");
4204 test_fullname2_helper("Wingdings");
4205 test_fullname2_helper("SimSun");
4206 test_fullname2_helper("NSimSun");
4207 test_fullname2_helper("MingLiu");
4208 test_fullname2_helper("PMingLiu");
4209 test_fullname2_helper("WenQuanYi Micro Hei");
4210 test_fullname2_helper("MS UI Gothic");
4211 test_fullname2_helper("Ume UI Gothic");
4212 test_fullname2_helper("MS Gothic");
4213 test_fullname2_helper("Ume Gothic");
4214 test_fullname2_helper("MS PGothic");
4215 test_fullname2_helper("Ume P Gothic");
4216 test_fullname2_helper("Gulim");
4217 test_fullname2_helper("Batang");
4218 test_fullname2_helper("UnBatang");
4219 test_fullname2_helper("UnDotum");
4220 test_fullname2_helper("@SimSun");
4221 test_fullname2_helper("@NSimSun");
4222 test_fullname2_helper("@MingLiu");
4223 test_fullname2_helper("@PMingLiu");
4224 test_fullname2_helper("@WenQuanYi Micro Hei");
4225 test_fullname2_helper("@MS UI Gothic");
4226 test_fullname2_helper("@Ume UI Gothic");
4227 test_fullname2_helper("@MS Gothic");
4228 test_fullname2_helper("@Ume Gothic");
4229 test_fullname2_helper("@MS PGothic");
4230 test_fullname2_helper("@Ume P Gothic");
4231 test_fullname2_helper("@Gulim");
4232 test_fullname2_helper("@Batang");
4233 test_fullname2_helper("@UnBatang");
4234 test_fullname2_helper("@UnDotum");
4238 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4240 char tmp_path[MAX_PATH];
4247 SetLastError(0xdeadbeef);
4248 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4249 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4250 if (!rsrc) return FALSE;
4251 SetLastError(0xdeadbeef);
4252 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4253 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4254 if (!rsrc_data) return FALSE;
4255 SetLastError(0xdeadbeef);
4256 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4257 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4258 if (!rsrc_size) return FALSE;
4260 SetLastError(0xdeadbeef);
4261 ret = GetTempPath(MAX_PATH, tmp_path);
4262 ok(ret, "GetTempPath() error %d\n", GetLastError());
4263 SetLastError(0xdeadbeef);
4264 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4265 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4267 SetLastError(0xdeadbeef);
4268 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4269 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4270 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4272 SetLastError(0xdeadbeef);
4273 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4274 ok(ret, "WriteFile() error %d\n", GetLastError());
4280 static void test_CreateScalableFontResource(void)
4282 char ttf_name[MAX_PATH];
4283 char tmp_path[MAX_PATH];
4284 char fot_name[MAX_PATH];
4288 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4290 win_skip("AddFontResourceExA is not available on this platform\n");
4294 if (!write_ttf_file("wine_test.ttf", ttf_name))
4296 skip("Failed to create ttf file for testing\n");
4300 trace("created %s\n", ttf_name);
4302 ret = is_truetype_font_installed("wine_test");
4303 ok(!ret, "font wine_test should not be enumerated\n");
4305 ret = GetTempPath(MAX_PATH, tmp_path);
4306 ok(ret, "GetTempPath() error %d\n", GetLastError());
4307 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4308 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4310 ret = GetFileAttributes(fot_name);
4311 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4313 SetLastError(0xdeadbeef);
4314 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4315 ok(!ret, "CreateScalableFontResource() should fail\n");
4316 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4318 SetLastError(0xdeadbeef);
4319 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4320 ok(!ret, "CreateScalableFontResource() should fail\n");
4321 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4323 file_part = strrchr(ttf_name, '\\');
4324 SetLastError(0xdeadbeef);
4325 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4326 ok(!ret, "CreateScalableFontResource() should fail\n");
4327 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4329 SetLastError(0xdeadbeef);
4330 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4331 ok(!ret, "CreateScalableFontResource() should fail\n");
4332 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4334 SetLastError(0xdeadbeef);
4335 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4336 ok(!ret, "CreateScalableFontResource() should fail\n");
4337 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4339 ret = DeleteFile(fot_name);
4340 ok(ret, "DeleteFile() error %d\n", GetLastError());
4342 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4344 ok(!ret, "RemoveFontResourceEx() should fail\n");
4346 /* test public font resource */
4347 SetLastError(0xdeadbeef);
4348 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4349 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4351 ret = is_truetype_font_installed("wine_test");
4352 ok(!ret, "font wine_test should not be enumerated\n");
4354 SetLastError(0xdeadbeef);
4355 ret = pAddFontResourceExA(fot_name, 0, 0);
4356 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4358 ret = is_truetype_font_installed("wine_test");
4359 ok(ret, "font wine_test should be enumerated\n");
4361 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4363 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4365 SetLastError(0xdeadbeef);
4366 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4367 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4369 ret = is_truetype_font_installed("wine_test");
4371 ok(!ret, "font wine_test should not be enumerated\n");
4373 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4376 /* remove once RemoveFontResource is implemented */
4377 DeleteFile(fot_name);
4378 DeleteFile(ttf_name);
4382 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4383 ok(!ret, "RemoveFontResourceEx() should fail\n");
4385 DeleteFile(fot_name);
4387 /* test hidden font resource */
4388 SetLastError(0xdeadbeef);
4389 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4390 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4392 ret = is_truetype_font_installed("wine_test");
4393 ok(!ret, "font wine_test should not be enumerated\n");
4395 SetLastError(0xdeadbeef);
4396 ret = pAddFontResourceExA(fot_name, 0, 0);
4397 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4399 ret = is_truetype_font_installed("wine_test");
4400 ok(!ret, "font wine_test should not be enumerated\n");
4402 /* XP allows removing a private font added with 0 flags */
4403 SetLastError(0xdeadbeef);
4404 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4405 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4407 ret = is_truetype_font_installed("wine_test");
4408 ok(!ret, "font wine_test should not be enumerated\n");
4410 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4411 ok(!ret, "RemoveFontResourceEx() should fail\n");
4413 DeleteFile(fot_name);
4414 DeleteFile(ttf_name);
4417 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4420 HFONT hfont, hfont_prev;
4424 static const WCHAR str[] = { 0x2025 };
4426 *installed = is_truetype_font_installed(name);
4430 lf.lfEscapement = 0;
4431 lf.lfOrientation = 0;
4432 lf.lfWeight = FW_DONTCARE;
4436 lf.lfCharSet = DEFAULT_CHARSET;
4437 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4438 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4439 lf.lfQuality = DEFAULT_QUALITY;
4440 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4441 strcpy(lf.lfFaceName, name);
4443 hfont = CreateFontIndirectA(&lf);
4444 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4448 hfont_prev = SelectObject(hdc, hfont);
4449 ok(hfont_prev != NULL, "SelectObject failed\n");
4451 ret = GetTextFaceA(hdc, sizeof facename, facename);
4452 ok(ret, "GetTextFaceA failed\n");
4453 *selected = !strcmp(facename, name);
4455 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4456 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4458 memset(gm, 0, sizeof *gm);
4460 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4461 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4463 SelectObject(hdc, hfont_prev);
4464 DeleteObject(hfont);
4465 ReleaseDC(NULL, hdc);
4468 static void test_vertical_font(void)
4470 char ttf_name[MAX_PATH];
4472 BOOL ret, installed, selected;
4476 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4478 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4482 if (!write_ttf_file("vertical.ttf", ttf_name))
4484 skip("Failed to create ttf file for testing\n");
4488 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4489 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4491 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4492 ok(installed, "@WineTestVertical is not installed\n");
4493 ok(selected, "@WineTestVertical is not selected\n");
4494 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4495 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4496 gm.gmBlackBoxX, gm.gmBlackBoxY);
4498 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4499 ok(installed, "@@WineTestVertical is not installed\n");
4500 ok(selected, "@@WineTestVertical is not selected\n");
4501 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4502 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4503 gm.gmBlackBoxX, gm.gmBlackBoxY);
4505 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4507 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4508 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4510 DeleteFile(ttf_name);
4513 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4514 DWORD type, LPARAM lParam)
4516 if (lf->lfFaceName[0] == '@') {
4522 static void test_east_asian_font_selection(void)
4525 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4526 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4531 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4535 char face_name[LF_FACESIZE];
4538 memset(&lf, 0, sizeof lf);
4539 lf.lfFaceName[0] = '\0';
4540 lf.lfCharSet = charset[i];
4542 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4544 skip("Vertical font for charset %u is not installed\n", charset[i]);
4548 hfont = CreateFontIndirectA(&lf);
4549 hfont = SelectObject(hdc, hfont);
4550 memset(face_name, 0, sizeof face_name);
4551 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4552 ok(ret && face_name[0] != '@',
4553 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4554 DeleteObject(SelectObject(hdc, hfont));
4556 memset(&lf, 0, sizeof lf);
4557 strcpy(lf.lfFaceName, "@");
4558 lf.lfCharSet = charset[i];
4559 hfont = CreateFontIndirectA(&lf);
4560 hfont = SelectObject(hdc, hfont);
4561 memset(face_name, 0, sizeof face_name);
4562 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4563 ok(ret && face_name[0] == '@',
4564 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4565 DeleteObject(SelectObject(hdc, hfont));
4567 ReleaseDC(NULL, hdc);
4570 static int get_font_dpi(const LOGFONT *lf)
4572 HDC hdc = CreateCompatibleDC(0);
4577 hfont = CreateFontIndirect(lf);
4578 ok(hfont != 0, "CreateFontIndirect failed\n");
4580 SelectObject(hdc, hfont);
4581 ret = GetTextMetrics(hdc, &tm);
4582 ok(ret, "GetTextMetrics failed\n");
4583 ret = tm.tmDigitizedAspectX;
4586 DeleteObject(hfont);
4591 static void test_stock_fonts(void)
4593 static const int font[] =
4595 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4596 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4598 static const struct test_data
4600 int charset, weight, height, dpi;
4601 const char face_name[LF_FACESIZE];
4604 { /* ANSI_FIXED_FONT */
4605 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4606 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4609 { /* ANSI_VAR_FONT */
4610 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4611 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4615 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4616 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4617 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4618 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4619 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4620 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4623 { /* DEVICE_DEFAULT_FONT */
4624 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4625 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4626 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4627 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4628 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4629 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4632 { /* DEFAULT_GUI_FONT */
4633 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4634 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4635 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4636 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4637 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4638 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4639 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4640 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4641 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4642 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4648 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4654 hfont = GetStockObject(font[i]);
4655 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4657 ret = GetObject(hfont, sizeof(lf), &lf);
4658 if (ret != sizeof(lf))
4661 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4665 for (j = 0; td[i][j].face_name[0] != 0; j++)
4667 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4672 ret = get_font_dpi(&lf);
4673 if (ret != td[i][j].dpi)
4675 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4676 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4680 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4681 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4682 if (td[i][j].face_name[0] == '?')
4684 /* Wine doesn't have this font, skip this case for now.
4685 Actually, the face name is localized on Windows and varies
4686 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4687 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4691 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);
4705 test_outline_font();
4706 test_bitmap_font_metrics();
4707 test_GdiGetCharDimensions();
4708 test_GetCharABCWidths();
4709 test_text_extents();
4710 test_GetGlyphIndices();
4711 test_GetKerningPairs();
4712 test_GetOutlineTextMetrics();
4713 test_SetTextJustification();
4714 test_font_charset();
4715 test_GetFontUnicodeRanges();
4716 test_nonexistent_font();
4718 test_height_selection();
4719 test_AddFontMemResource();
4722 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4723 * I'd like to avoid them in this test.
4725 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4726 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4727 if (is_truetype_font_installed("Arial Black") &&
4728 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4730 test_EnumFontFamilies("", ANSI_CHARSET);
4731 test_EnumFontFamilies("", SYMBOL_CHARSET);
4732 test_EnumFontFamilies("", DEFAULT_CHARSET);
4735 skip("Arial Black or Symbol/Wingdings is not installed\n");
4736 test_EnumFontFamiliesEx_default_charset();
4737 test_GetTextMetrics();
4738 test_GdiRealizationInfo();
4740 test_GetGlyphOutline();
4741 test_GetTextMetrics2("Tahoma", -11);
4742 test_GetTextMetrics2("Tahoma", -55);
4743 test_GetTextMetrics2("Tahoma", -110);
4744 test_GetTextMetrics2("Arial", -11);
4745 test_GetTextMetrics2("Arial", -55);
4746 test_GetTextMetrics2("Arial", -110);
4747 test_CreateFontIndirect();
4748 test_CreateFontIndirectEx();
4752 test_east_asian_font_selection();
4754 /* These tests should be last test until RemoveFontResource
4755 * is properly implemented.
4757 test_vertical_font();
4758 test_CreateScalableFontResource();