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 areaWidth = clientArea->right - clientArea->left,
1758 PSTR pFirstChar, pLastChar;
1765 int GetTextExtentExPointWWidth;
1768 GetTextMetricsA(hdc, &tm);
1769 y = clientArea->top;
1772 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1778 /* if not at the end of the string, ... */
1779 if (*str == '\0') break;
1780 /* ... add the next word to the current extent */
1781 while (*str != '\0' && *str++ != tm.tmBreakChar);
1783 SetTextJustification(hdc, 0, 0);
1784 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1785 } while ((int) size.cx < areaWidth);
1787 /* ignore trailing break chars */
1789 while (*(pLastChar - 1) == tm.tmBreakChar)
1795 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1797 SetTextJustification(hdc, 0, 0);
1798 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1800 /* do not justify the last extent */
1801 if (*str != '\0' && breakCount > 0)
1803 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1804 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1805 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
1807 error[nErrors].start = pFirstChar;
1808 error[nErrors].len = pLastChar - pFirstChar;
1809 error[nErrors].GetTextExtentExPointWWidth = size.cx;
1814 trace( "%u %.*s\n", size.cx, (int)(pLastChar - pFirstChar), pFirstChar);
1818 } while (*str && y < clientArea->bottom);
1820 for (e = 0; e < nErrors; e++)
1822 /* The width returned by GetTextExtentPoint32() is exactly the same
1823 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1824 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1825 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
1826 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
1830 static void test_SetTextJustification(void)
1837 static char testText[] =
1838 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1839 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1840 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1841 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1842 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1843 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1844 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1846 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1847 GetClientRect( hwnd, &clientArea );
1848 hdc = GetDC( hwnd );
1850 memset(&lf, 0, sizeof lf);
1851 lf.lfCharSet = ANSI_CHARSET;
1852 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1853 lf.lfWeight = FW_DONTCARE;
1855 lf.lfQuality = DEFAULT_QUALITY;
1856 lstrcpyA(lf.lfFaceName, "Times New Roman");
1857 hfont = create_font("Times New Roman", &lf);
1858 SelectObject(hdc, hfont);
1860 testJustification(hdc, testText, &clientArea);
1862 SetMapMode( hdc, MM_ANISOTROPIC );
1863 SetWindowExtEx( hdc, 2, 2, NULL );
1864 GetClientRect( hwnd, &clientArea );
1865 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1866 testJustification(hdc, testText, &clientArea);
1868 SetViewportExtEx( hdc, 3, 3, NULL );
1869 GetClientRect( hwnd, &clientArea );
1870 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1871 testJustification(hdc, testText, &clientArea);
1873 DeleteObject(hfont);
1874 ReleaseDC(hwnd, hdc);
1875 DestroyWindow(hwnd);
1878 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1882 HFONT hfont, hfont_old;
1889 assert(count <= 128);
1891 memset(&lf, 0, sizeof(lf));
1893 lf.lfCharSet = charset;
1895 lstrcpyA(lf.lfFaceName, "Arial");
1896 SetLastError(0xdeadbeef);
1897 hfont = CreateFontIndirectA(&lf);
1898 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1901 hfont_old = SelectObject(hdc, hfont);
1903 cs = GetTextCharsetInfo(hdc, &fs, 0);
1904 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1906 SetLastError(0xdeadbeef);
1907 ret = GetTextFaceA(hdc, sizeof(name), name);
1908 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1910 if (charset == SYMBOL_CHARSET)
1912 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1913 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1917 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1918 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1921 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1923 trace("Can't find codepage for charset %d\n", cs);
1927 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1929 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1931 skip("Font code page %d, looking for code page %d\n",
1932 pGdiGetCodePage(hdc), code_page);
1940 WCHAR unicode_buf[128];
1942 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1944 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1946 SetLastError(0xdeadbeef);
1947 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1948 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1949 count, ret, GetLastError());
1955 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1957 SetLastError(0xdeadbeef);
1958 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1959 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1960 count, ret, GetLastError());
1963 SelectObject(hdc, hfont_old);
1964 DeleteObject(hfont);
1971 static void test_font_charset(void)
1973 static struct charset_data
1977 WORD font_idxA[128], font_idxW[128];
1980 { ANSI_CHARSET, 1252 },
1981 { RUSSIAN_CHARSET, 1251 },
1982 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1986 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1988 win_skip("Skipping the font charset test on a Win9x platform\n");
1992 if (!is_font_installed("Arial"))
1994 skip("Arial is not installed\n");
1998 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2000 if (cd[i].charset == SYMBOL_CHARSET)
2002 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2004 skip("Symbol or Wingdings is not installed\n");
2008 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2009 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2010 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2013 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2016 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2017 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2020 skip("Symbol or Wingdings is not installed\n");
2023 static void test_GetFontUnicodeRanges(void)
2027 HFONT hfont, hfont_old;
2032 if (!pGetFontUnicodeRanges)
2034 win_skip("GetFontUnicodeRanges not available before W2K\n");
2038 memset(&lf, 0, sizeof(lf));
2039 lstrcpyA(lf.lfFaceName, "Arial");
2040 hfont = create_font("Arial", &lf);
2043 hfont_old = SelectObject(hdc, hfont);
2045 size = pGetFontUnicodeRanges(NULL, NULL);
2046 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2048 size = pGetFontUnicodeRanges(hdc, NULL);
2049 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2051 gs = HeapAlloc(GetProcessHeap(), 0, size);
2053 size = pGetFontUnicodeRanges(hdc, gs);
2054 ok(size, "GetFontUnicodeRanges failed\n");
2056 if (0) /* Disabled to limit console spam */
2057 for (i = 0; i < gs->cRanges; i++)
2058 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2059 trace("found %u ranges\n", gs->cRanges);
2061 HeapFree(GetProcessHeap(), 0, gs);
2063 SelectObject(hdc, hfont_old);
2064 DeleteObject(hfont);
2065 ReleaseDC(NULL, hdc);
2068 #define MAX_ENUM_FONTS 4096
2070 struct enum_font_data
2073 LOGFONT lf[MAX_ENUM_FONTS];
2076 struct enum_fullname_data
2079 ENUMLOGFONT elf[MAX_ENUM_FONTS];
2082 struct enum_font_dataW
2085 LOGFONTW lf[MAX_ENUM_FONTS];
2088 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2090 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2091 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2093 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2094 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2096 if (type != TRUETYPE_FONTTYPE) return 1;
2098 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2100 if (0) /* Disabled to limit console spam */
2101 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2102 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2103 if (efd->total < MAX_ENUM_FONTS)
2104 efd->lf[efd->total++] = *lf;
2106 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2111 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2113 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2114 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2116 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2117 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2119 if (type != TRUETYPE_FONTTYPE) return 1;
2121 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2123 if (0) /* Disabled to limit console spam */
2124 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2125 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2126 if (efd->total < MAX_ENUM_FONTS)
2127 efd->lf[efd->total++] = *lf;
2129 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2134 static void get_charset_stats(struct enum_font_data *efd,
2135 int *ansi_charset, int *symbol_charset,
2136 int *russian_charset)
2141 *symbol_charset = 0;
2142 *russian_charset = 0;
2144 for (i = 0; i < efd->total; i++)
2146 switch (efd->lf[i].lfCharSet)
2151 case SYMBOL_CHARSET:
2152 (*symbol_charset)++;
2154 case RUSSIAN_CHARSET:
2155 (*russian_charset)++;
2161 static void get_charset_statsW(struct enum_font_dataW *efd,
2162 int *ansi_charset, int *symbol_charset,
2163 int *russian_charset)
2168 *symbol_charset = 0;
2169 *russian_charset = 0;
2171 for (i = 0; i < efd->total; i++)
2173 switch (efd->lf[i].lfCharSet)
2178 case SYMBOL_CHARSET:
2179 (*symbol_charset)++;
2181 case RUSSIAN_CHARSET:
2182 (*russian_charset)++;
2188 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2190 struct enum_font_data efd;
2191 struct enum_font_dataW efdw;
2194 int i, ret, ansi_charset, symbol_charset, russian_charset;
2196 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2198 if (*font_name && !is_truetype_font_installed(font_name))
2200 skip("%s is not installed\n", font_name);
2206 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2207 * while EnumFontFamiliesEx doesn't.
2209 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2212 * Use EnumFontFamiliesW since win98 crashes when the
2213 * second parameter is NULL using EnumFontFamilies
2216 SetLastError(0xdeadbeef);
2217 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2218 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2221 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2222 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2223 ansi_charset, symbol_charset, russian_charset);
2224 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2225 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2226 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2227 ok(russian_charset > 0 ||
2228 broken(russian_charset == 0), /* NT4 */
2229 "NULL family should enumerate RUSSIAN_CHARSET\n");
2233 SetLastError(0xdeadbeef);
2234 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2235 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2238 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2239 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2240 ansi_charset, symbol_charset, russian_charset);
2241 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2242 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2243 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2244 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2249 SetLastError(0xdeadbeef);
2250 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2251 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2252 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2253 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2254 ansi_charset, symbol_charset, russian_charset,
2255 *font_name ? font_name : "<empty>");
2257 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2259 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2260 for (i = 0; i < efd.total; i++)
2262 /* FIXME: remove completely once Wine is fixed */
2263 if (efd.lf[i].lfCharSet != font_charset)
2266 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2269 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2270 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2271 font_name, efd.lf[i].lfFaceName);
2274 memset(&lf, 0, sizeof(lf));
2275 lf.lfCharSet = ANSI_CHARSET;
2276 lstrcpy(lf.lfFaceName, font_name);
2278 SetLastError(0xdeadbeef);
2279 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2280 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2281 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2282 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2283 ansi_charset, symbol_charset, russian_charset,
2284 *font_name ? font_name : "<empty>");
2285 if (font_charset == SYMBOL_CHARSET)
2288 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2290 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2294 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2295 for (i = 0; i < efd.total; i++)
2297 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2299 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2300 font_name, efd.lf[i].lfFaceName);
2304 /* DEFAULT_CHARSET should enumerate all available charsets */
2305 memset(&lf, 0, sizeof(lf));
2306 lf.lfCharSet = DEFAULT_CHARSET;
2307 lstrcpy(lf.lfFaceName, font_name);
2309 SetLastError(0xdeadbeef);
2310 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2311 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2312 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2313 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2314 ansi_charset, symbol_charset, russian_charset,
2315 *font_name ? font_name : "<empty>");
2316 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2317 for (i = 0; i < efd.total; i++)
2320 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2321 font_name, efd.lf[i].lfFaceName);
2325 switch (font_charset)
2328 ok(ansi_charset > 0,
2329 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2331 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2332 ok(russian_charset > 0,
2333 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2335 case SYMBOL_CHARSET:
2337 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2339 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2340 ok(!russian_charset,
2341 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2343 case DEFAULT_CHARSET:
2344 ok(ansi_charset > 0,
2345 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2346 ok(symbol_charset > 0,
2347 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2348 ok(russian_charset > 0,
2349 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2355 ok(ansi_charset > 0,
2356 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2357 ok(symbol_charset > 0,
2358 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2359 ok(russian_charset > 0,
2360 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2363 memset(&lf, 0, sizeof(lf));
2364 lf.lfCharSet = SYMBOL_CHARSET;
2365 lstrcpy(lf.lfFaceName, font_name);
2367 SetLastError(0xdeadbeef);
2368 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2369 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2370 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2371 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2372 ansi_charset, symbol_charset, russian_charset,
2373 *font_name ? font_name : "<empty>");
2374 if (*font_name && font_charset == ANSI_CHARSET)
2375 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2378 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2379 for (i = 0; i < efd.total; i++)
2381 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2383 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2384 font_name, efd.lf[i].lfFaceName);
2388 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2389 ok(symbol_charset > 0,
2390 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2391 ok(!russian_charset,
2392 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2398 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2400 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2402 if (type != TRUETYPE_FONTTYPE) return 1;
2404 if (efd->total < MAX_ENUM_FONTS)
2405 efd->lf[efd->total++] = *lf;
2407 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2412 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2414 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2416 if (type != TRUETYPE_FONTTYPE) return 1;
2418 if (efnd->total < MAX_ENUM_FONTS)
2419 efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2421 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2426 static void test_EnumFontFamiliesEx_default_charset(void)
2428 struct enum_font_data efd;
2429 LOGFONT gui_font, enum_font;
2433 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2434 ok(ret, "GetObject failed.\n");
2441 memset(&enum_font, 0, sizeof(enum_font));
2442 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2443 enum_font.lfCharSet = DEFAULT_CHARSET;
2444 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2447 if (efd.total == 0) {
2448 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2451 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2453 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet || broken(system_lang_id == LANG_ARABIC),
2454 "(%s) got charset %d expected %d\n",
2455 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2460 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2462 HFONT hfont, hfont_prev;
2464 GLYPHMETRICS gm1, gm2;
2468 if(!pGetGlyphIndicesA)
2471 /* negative widths are handled just as positive ones */
2472 lf2.lfWidth = -lf->lfWidth;
2474 SetLastError(0xdeadbeef);
2475 hfont = CreateFontIndirectA(lf);
2476 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2477 check_font("original", lf, hfont);
2479 hfont_prev = SelectObject(hdc, hfont);
2481 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2482 if (ret == GDI_ERROR || idx == 0xffff)
2484 SelectObject(hdc, hfont_prev);
2485 DeleteObject(hfont);
2486 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2490 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2491 memset(&gm1, 0xab, sizeof(gm1));
2492 SetLastError(0xdeadbeef);
2493 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2494 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2496 SelectObject(hdc, hfont_prev);
2497 DeleteObject(hfont);
2499 SetLastError(0xdeadbeef);
2500 hfont = CreateFontIndirectA(&lf2);
2501 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2502 check_font("negative width", &lf2, hfont);
2504 hfont_prev = SelectObject(hdc, hfont);
2506 memset(&gm2, 0xbb, sizeof(gm2));
2507 SetLastError(0xdeadbeef);
2508 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2509 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2511 SelectObject(hdc, hfont_prev);
2512 DeleteObject(hfont);
2514 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2515 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2516 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2517 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2518 gm1.gmCellIncX == gm2.gmCellIncX &&
2519 gm1.gmCellIncY == gm2.gmCellIncY,
2520 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2521 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2522 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2523 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2524 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2527 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2528 #include "pshpack2.h"
2532 SHORT xAvgCharWidth;
2533 USHORT usWeightClass;
2534 USHORT usWidthClass;
2536 SHORT ySubscriptXSize;
2537 SHORT ySubscriptYSize;
2538 SHORT ySubscriptXOffset;
2539 SHORT ySubscriptYOffset;
2540 SHORT ySuperscriptXSize;
2541 SHORT ySuperscriptYSize;
2542 SHORT ySuperscriptXOffset;
2543 SHORT ySuperscriptYOffset;
2544 SHORT yStrikeoutSize;
2545 SHORT yStrikeoutPosition;
2548 ULONG ulUnicodeRange1;
2549 ULONG ulUnicodeRange2;
2550 ULONG ulUnicodeRange3;
2551 ULONG ulUnicodeRange4;
2554 USHORT usFirstCharIndex;
2555 USHORT usLastCharIndex;
2556 /* According to the Apple spec, original version didn't have the below fields,
2557 * version numbers were taken from the OpenType spec.
2559 /* version 0 (TrueType 1.5) */
2560 USHORT sTypoAscender;
2561 USHORT sTypoDescender;
2562 USHORT sTypoLineGap;
2564 USHORT usWinDescent;
2565 /* version 1 (TrueType 1.66) */
2566 ULONG ulCodePageRange1;
2567 ULONG ulCodePageRange2;
2568 /* version 2 (OpenType 1.2) */
2571 USHORT usDefaultChar;
2573 USHORT usMaxContext;
2575 #include "poppack.h"
2577 #ifdef WORDS_BIGENDIAN
2578 #define GET_BE_WORD(x) (x)
2579 #define GET_BE_DWORD(x) (x)
2581 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2582 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2585 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2586 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2587 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2588 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2589 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2590 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2603 } cmap_encoding_record;
2611 BYTE glyph_ids[256];
2621 USHORT search_range;
2622 USHORT entry_selector;
2625 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2628 USHORT start_count[seg_countx2 / 2];
2629 USHORT id_delta[seg_countx2 / 2];
2630 USHORT id_range_offset[seg_countx2 / 2];
2640 USHORT id_range_offset;
2641 } cmap_format_4_seg;
2643 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2645 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2646 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2647 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2648 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2649 os2->panose.bWeight, os2->panose.bProportion);
2652 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2655 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2659 for(i = 0; i < 256; i++)
2661 if(cmap->glyph_ids[i] == 0) continue;
2663 if(*first == 256) *first = i;
2665 if(*first == 256) return FALSE;
2669 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2671 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2672 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2673 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2674 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2675 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2678 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2681 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2682 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2683 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2687 for(i = 0; i < seg_count; i++)
2690 cmap_format_4_seg seg;
2692 get_seg4(cmap, i, &seg);
2693 for(code = seg.start_count; code <= seg.end_count; code++)
2695 if(seg.id_range_offset == 0)
2696 index = (seg.id_delta + code) & 0xffff;
2699 index = seg.id_range_offset / 2
2700 + code - seg.start_count
2703 /* some fonts have broken last segment */
2704 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2705 index = GET_BE_WORD(glyph_ids[index]);
2708 trace("segment %04x/%04x index %04x points to nowhere\n",
2709 seg.start_count, seg.end_count, index);
2712 if(index) index += seg.id_delta;
2714 if(*first == 0x10000)
2715 *last = *first = code;
2721 if(*first == 0x10000) return FALSE;
2725 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2728 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2730 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2732 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2733 return (BYTE *)header + GET_BE_DWORD(record->offset);
2746 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2749 cmap_header *header;
2754 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2755 ok(size != GDI_ERROR, "no cmap table found\n");
2756 if(size == GDI_ERROR) return FALSE;
2758 header = HeapAlloc(GetProcessHeap(), 0, size);
2759 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2760 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2761 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2763 cmap = get_cmap(header, 3, 1);
2765 *cmap_type = cmap_ms_unicode;
2768 cmap = get_cmap(header, 3, 0);
2769 if(cmap) *cmap_type = cmap_ms_symbol;
2773 *cmap_type = cmap_none;
2777 format = GET_BE_WORD(*(WORD *)cmap);
2781 r = get_first_last_from_cmap0(cmap, first, last);
2784 r = get_first_last_from_cmap4(cmap, first, last, size);
2787 trace("unhandled cmap format %d\n", format);
2792 HeapFree(GetProcessHeap(), 0, header);
2796 #define TT_PLATFORM_MICROSOFT 3
2797 #define TT_MS_ID_SYMBOL_CS 0
2798 #define TT_MS_ID_UNICODE_CS 1
2799 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2800 #define TT_NAME_ID_FONT_FAMILY 1
2801 #define TT_NAME_ID_FONT_SUBFAMILY 2
2802 #define TT_NAME_ID_UNIQUE_ID 3
2803 #define TT_NAME_ID_FULL_NAME 4
2805 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2807 struct sfnt_name_header
2810 USHORT number_of_record;
2811 USHORT storage_offset;
2823 LONG size, offset, length;
2829 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2830 ok(size != GDI_ERROR, "no name table found\n");
2831 if(size == GDI_ERROR) return FALSE;
2833 data = HeapAlloc(GetProcessHeap(), 0, size);
2834 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2835 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2837 header = (void *)data;
2838 header->format = GET_BE_WORD(header->format);
2839 header->number_of_record = GET_BE_WORD(header->number_of_record);
2840 header->storage_offset = GET_BE_WORD(header->storage_offset);
2841 if (header->format != 0)
2843 trace("got format %u\n", header->format);
2846 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2848 trace("number records out of range: %d\n", header->number_of_record);
2851 if (header->storage_offset >= size)
2853 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2857 entry = (void *)&header[1];
2858 for (i = 0; i < header->number_of_record; i++)
2860 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2861 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
2862 GET_BE_WORD(entry[i].language_id) != language_id ||
2863 GET_BE_WORD(entry[i].name_id) != name_id)
2868 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2869 length = GET_BE_WORD(entry[i].length);
2870 if (offset + length > size)
2872 trace("entry %d is out of range\n", i);
2875 if (length >= out_size)
2877 trace("buffer too small for entry %d\n", i);
2881 name = (WCHAR *)(data + offset);
2882 for (c = 0; c < length / 2; c++)
2883 out_buf[c] = GET_BE_WORD(name[c]);
2891 HeapFree(GetProcessHeap(), 0, data);
2895 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2898 HFONT hfont, hfont_old;
2902 const char *font_name = lf->lfFaceName;
2903 DWORD cmap_first = 0, cmap_last = 0;
2904 UINT ascent, descent, cell_height;
2905 cmap_type cmap_type;
2906 BOOL sys_lang_non_english;
2908 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2911 SetLastError(0xdeadbeef);
2912 hfont = CreateFontIndirectA(lf);
2913 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2915 hfont_old = SelectObject(hdc, hfont);
2917 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2918 if (size == GDI_ERROR)
2920 trace("OS/2 chunk was not found\n");
2923 if (size > sizeof(tt_os2))
2925 trace("got too large OS/2 chunk of size %u\n", size);
2926 size = sizeof(tt_os2);
2929 memset(&tt_os2, 0, sizeof(tt_os2));
2930 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2931 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2933 ascent = GET_BE_WORD(tt_os2.usWinAscent);
2934 descent = GET_BE_WORD(tt_os2.usWinDescent);
2935 cell_height = ascent + descent;
2936 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
2937 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
2939 SetLastError(0xdeadbeef);
2940 ret = GetTextMetricsA(hdc, &tmA);
2941 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2943 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2945 skip("Unable to retrieve first and last glyphs from cmap\n");
2949 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2950 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2951 UINT os2_first_char, os2_last_char, default_char, break_char;
2955 version = GET_BE_WORD(tt_os2.version);
2957 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2958 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2959 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2960 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2962 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2963 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2964 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2966 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2971 case 1257: /* Baltic */
2972 expect_last_W = 0xf8fd;
2975 expect_last_W = 0xf0ff;
2977 expect_break_W = 0x20;
2978 expect_default_W = expect_break_W - 1;
2979 expect_first_A = 0x1e;
2980 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2984 expect_first_W = cmap_first;
2985 expect_last_W = min(cmap_last, os2_last_char);
2986 if(os2_first_char <= 1)
2987 expect_break_W = os2_first_char + 2;
2988 else if(os2_first_char > 0xff)
2989 expect_break_W = 0x20;
2991 expect_break_W = os2_first_char;
2992 expect_default_W = expect_break_W - 1;
2993 expect_first_A = expect_default_W - 1;
2994 expect_last_A = min(expect_last_W, 0xff);
2996 expect_break_A = expect_break_W;
2997 expect_default_A = expect_default_W;
2999 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3000 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3001 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3002 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3003 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3005 ok(tmA.tmFirstChar == expect_first_A ||
3006 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3007 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3008 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3009 ok(tmA.tmLastChar == expect_last_A ||
3010 tmA.tmLastChar == 0xff /* win9x */,
3011 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3013 skip("tmLastChar is DBCS lead byte\n");
3014 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3015 font_name, tmA.tmBreakChar, expect_break_A);
3016 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3017 "A: tmDefaultChar for %s got %02x expected %02x\n",
3018 font_name, tmA.tmDefaultChar, expect_default_A);
3021 SetLastError(0xdeadbeef);
3022 ret = GetTextMetricsW(hdc, &tmW);
3023 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3024 "GetTextMetricsW error %u\n", GetLastError());
3027 /* Wine uses the os2 first char */
3028 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3029 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3030 font_name, tmW.tmFirstChar, expect_first_W);
3032 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3033 font_name, tmW.tmFirstChar, expect_first_W);
3035 /* Wine uses the os2 last char */
3036 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3037 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3038 font_name, tmW.tmLastChar, expect_last_W);
3040 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3041 font_name, tmW.tmLastChar, expect_last_W);
3042 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3043 font_name, tmW.tmBreakChar, expect_break_W);
3044 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3045 "W: tmDefaultChar for %s got %02x expected %02x\n",
3046 font_name, tmW.tmDefaultChar, expect_default_W);
3048 /* Test the aspect ratio while we have tmW */
3049 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3050 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3051 tmW.tmDigitizedAspectX, ret);
3052 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3053 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3054 tmW.tmDigitizedAspectX, ret);
3058 /* test FF_ values */
3059 switch(tt_os2.panose.bFamilyType)
3063 case PAN_FAMILY_TEXT_DISPLAY:
3064 case PAN_FAMILY_PICTORIAL:
3066 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3067 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3069 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3072 switch(tt_os2.panose.bSerifStyle)
3077 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3080 case PAN_SERIF_COVE:
3081 case PAN_SERIF_OBTUSE_COVE:
3082 case PAN_SERIF_SQUARE_COVE:
3083 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3084 case PAN_SERIF_SQUARE:
3085 case PAN_SERIF_THIN:
3086 case PAN_SERIF_BONE:
3087 case PAN_SERIF_EXAGGERATED:
3088 case PAN_SERIF_TRIANGLE:
3089 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3092 case PAN_SERIF_NORMAL_SANS:
3093 case PAN_SERIF_OBTUSE_SANS:
3094 case PAN_SERIF_PERP_SANS:
3095 case PAN_SERIF_FLARED:
3096 case PAN_SERIF_ROUNDED:
3097 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3102 case PAN_FAMILY_SCRIPT:
3103 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3106 case PAN_FAMILY_DECORATIVE:
3107 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3111 test_negative_width(hdc, lf);
3114 SelectObject(hdc, hfont_old);
3115 DeleteObject(hfont);
3120 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3122 INT *enumed = (INT *)lParam;
3124 if (type == TRUETYPE_FONTTYPE)
3127 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3132 static void test_GetTextMetrics(void)
3138 /* Report only once */
3139 if(!pGetGlyphIndicesA)
3140 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3144 memset(&lf, 0, sizeof(lf));
3145 lf.lfCharSet = DEFAULT_CHARSET;
3147 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3148 trace("Tested metrics of %d truetype fonts\n", enumed);
3153 static void test_nonexistent_font(void)
3161 { "Times New Roman Baltic", 186 },
3162 { "Times New Roman CE", 238 },
3163 { "Times New Roman CYR", 204 },
3164 { "Times New Roman Greek", 161 },
3165 { "Times New Roman TUR", 162 }
3171 INT cs, expected_cs, i;
3172 char buf[LF_FACESIZE];
3174 if (!is_truetype_font_installed("Arial") ||
3175 !is_truetype_font_installed("Times New Roman"))
3177 skip("Arial or Times New Roman not installed\n");
3181 expected_cs = GetACP();
3182 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3184 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3187 expected_cs = csi.ciCharset;
3188 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3192 memset(&lf, 0, sizeof(lf));
3194 lf.lfWeight = FW_REGULAR;
3195 lf.lfCharSet = ANSI_CHARSET;
3196 lf.lfPitchAndFamily = FF_SWISS;
3197 strcpy(lf.lfFaceName, "Nonexistent font");
3198 hfont = CreateFontIndirectA(&lf);
3199 hfont = SelectObject(hdc, hfont);
3200 GetTextFaceA(hdc, sizeof(buf), buf);
3201 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3202 cs = GetTextCharset(hdc);
3203 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3204 DeleteObject(SelectObject(hdc, hfont));
3206 memset(&lf, 0, sizeof(lf));
3208 lf.lfWeight = FW_DONTCARE;
3209 strcpy(lf.lfFaceName, "Nonexistent font");
3210 hfont = CreateFontIndirectA(&lf);
3211 hfont = SelectObject(hdc, hfont);
3212 GetTextFaceA(hdc, sizeof(buf), buf);
3213 todo_wine /* Wine uses Arial for all substitutions */
3214 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3215 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3216 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3218 cs = GetTextCharset(hdc);
3219 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3220 DeleteObject(SelectObject(hdc, hfont));
3222 memset(&lf, 0, sizeof(lf));
3224 lf.lfWeight = FW_REGULAR;
3225 strcpy(lf.lfFaceName, "Nonexistent font");
3226 hfont = CreateFontIndirectA(&lf);
3227 hfont = SelectObject(hdc, hfont);
3228 GetTextFaceA(hdc, sizeof(buf), buf);
3229 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3230 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3231 cs = GetTextCharset(hdc);
3232 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3233 DeleteObject(SelectObject(hdc, hfont));
3235 memset(&lf, 0, sizeof(lf));
3237 lf.lfWeight = FW_DONTCARE;
3238 strcpy(lf.lfFaceName, "Times New Roman");
3239 hfont = CreateFontIndirectA(&lf);
3240 hfont = SelectObject(hdc, hfont);
3241 GetTextFaceA(hdc, sizeof(buf), buf);
3242 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3243 cs = GetTextCharset(hdc);
3244 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3245 DeleteObject(SelectObject(hdc, hfont));
3247 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3249 memset(&lf, 0, sizeof(lf));
3251 lf.lfWeight = FW_REGULAR;
3252 strcpy(lf.lfFaceName, font_subst[i].name);
3253 hfont = CreateFontIndirectA(&lf);
3254 hfont = SelectObject(hdc, hfont);
3255 cs = GetTextCharset(hdc);
3256 if (font_subst[i].charset == expected_cs)
3258 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3259 GetTextFaceA(hdc, sizeof(buf), buf);
3260 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3264 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3265 GetTextFaceA(hdc, sizeof(buf), buf);
3266 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3267 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3269 DeleteObject(SelectObject(hdc, hfont));
3271 memset(&lf, 0, sizeof(lf));
3273 lf.lfWeight = FW_DONTCARE;
3274 strcpy(lf.lfFaceName, font_subst[i].name);
3275 hfont = CreateFontIndirectA(&lf);
3276 hfont = SelectObject(hdc, hfont);
3277 GetTextFaceA(hdc, sizeof(buf), buf);
3278 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3279 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3280 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3281 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3282 "got %s for font %s\n", buf, font_subst[i].name);
3283 cs = GetTextCharset(hdc);
3284 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3285 DeleteObject(SelectObject(hdc, hfont));
3291 static void test_GdiRealizationInfo(void)
3296 HFONT hfont, hfont_old;
3299 if(!pGdiRealizationInfo)
3301 win_skip("GdiRealizationInfo not available\n");
3307 memset(info, 0xcc, sizeof(info));
3308 r = pGdiRealizationInfo(hdc, info);
3309 ok(r != 0, "ret 0\n");
3310 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3311 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3313 if (!is_truetype_font_installed("Arial"))
3315 skip("skipping GdiRealizationInfo with truetype font\n");
3319 memset(&lf, 0, sizeof(lf));
3320 strcpy(lf.lfFaceName, "Arial");
3322 lf.lfWeight = FW_NORMAL;
3323 hfont = CreateFontIndirectA(&lf);
3324 hfont_old = SelectObject(hdc, hfont);
3326 memset(info, 0xcc, sizeof(info));
3327 r = pGdiRealizationInfo(hdc, info);
3328 ok(r != 0, "ret 0\n");
3329 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3330 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3332 DeleteObject(SelectObject(hdc, hfont_old));
3338 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3339 the nul in the count of characters copied when the face name buffer is not
3340 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3341 always includes it. */
3342 static void test_GetTextFace(void)
3344 static const char faceA[] = "Tahoma";
3345 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3348 char bufA[LF_FACESIZE];
3349 WCHAR bufW[LF_FACESIZE];
3354 if(!is_font_installed("Tahoma"))
3356 skip("Tahoma is not installed so skipping this test\n");
3361 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3362 f = CreateFontIndirectA(&fA);
3363 ok(f != NULL, "CreateFontIndirectA failed\n");
3366 g = SelectObject(dc, f);
3367 n = GetTextFaceA(dc, sizeof bufA, bufA);
3368 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3369 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3371 /* Play with the count arg. */
3373 n = GetTextFaceA(dc, 0, bufA);
3374 ok(n == 0, "GetTextFaceA returned %d\n", n);
3375 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3378 n = GetTextFaceA(dc, 1, bufA);
3379 ok(n == 0, "GetTextFaceA returned %d\n", n);
3380 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3382 bufA[0] = 'x'; bufA[1] = 'y';
3383 n = GetTextFaceA(dc, 2, bufA);
3384 ok(n == 1, "GetTextFaceA returned %d\n", n);
3385 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3387 n = GetTextFaceA(dc, 0, NULL);
3388 ok(n == sizeof faceA ||
3389 broken(n == 0), /* win98, winMe */
3390 "GetTextFaceA returned %d\n", n);
3392 DeleteObject(SelectObject(dc, g));
3393 ReleaseDC(NULL, dc);
3396 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3397 SetLastError(0xdeadbeef);
3398 f = CreateFontIndirectW(&fW);
3399 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3401 win_skip("CreateFontIndirectW is not implemented\n");
3404 ok(f != NULL, "CreateFontIndirectW failed\n");
3407 g = SelectObject(dc, f);
3408 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3409 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3410 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3412 /* Play with the count arg. */
3414 n = GetTextFaceW(dc, 0, bufW);
3415 ok(n == 0, "GetTextFaceW returned %d\n", n);
3416 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3419 n = GetTextFaceW(dc, 1, bufW);
3420 ok(n == 1, "GetTextFaceW returned %d\n", n);
3421 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3423 bufW[0] = 'x'; bufW[1] = 'y';
3424 n = GetTextFaceW(dc, 2, bufW);
3425 ok(n == 2, "GetTextFaceW returned %d\n", n);
3426 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3428 n = GetTextFaceW(dc, 0, NULL);
3429 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3431 DeleteObject(SelectObject(dc, g));
3432 ReleaseDC(NULL, dc);
3435 static void test_orientation(void)
3437 static const char test_str[11] = "Test String";
3440 HFONT hfont, old_hfont;
3443 if (!is_truetype_font_installed("Arial"))
3445 skip("Arial is not installed\n");
3449 hdc = CreateCompatibleDC(0);
3450 memset(&lf, 0, sizeof(lf));
3451 lstrcpyA(lf.lfFaceName, "Arial");
3453 lf.lfOrientation = lf.lfEscapement = 900;
3454 hfont = create_font("orientation", &lf);
3455 old_hfont = SelectObject(hdc, hfont);
3456 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3457 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3458 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3459 SelectObject(hdc, old_hfont);
3460 DeleteObject(hfont);
3464 static void test_oemcharset(void)
3468 HFONT hfont, old_hfont;
3471 hdc = CreateCompatibleDC(0);
3472 ZeroMemory(&lf, sizeof(lf));
3474 lf.lfCharSet = OEM_CHARSET;
3475 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3476 lstrcpyA(lf.lfFaceName, "Terminal");
3477 hfont = CreateFontIndirectA(&lf);
3478 old_hfont = SelectObject(hdc, hfont);
3479 charset = GetTextCharset(hdc);
3481 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3482 hfont = SelectObject(hdc, old_hfont);
3483 GetObjectA(hfont, sizeof(clf), &clf);
3484 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3485 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3486 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3487 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3488 DeleteObject(hfont);
3492 static void test_GetGlyphOutline(void)
3495 GLYPHMETRICS gm, gm2;
3497 HFONT hfont, old_hfont;
3506 {ANSI_CHARSET, 0x30, 0x30},
3507 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3508 {HANGEUL_CHARSET, 0x8141, 0xac02},
3509 {JOHAB_CHARSET, 0x8446, 0x3135},
3510 {GB2312_CHARSET, 0x8141, 0x4e04},
3511 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3515 if (!is_truetype_font_installed("Tahoma"))
3517 skip("Tahoma is not installed\n");
3521 hdc = CreateCompatibleDC(0);
3522 memset(&lf, 0, sizeof(lf));
3524 lstrcpyA(lf.lfFaceName, "Tahoma");
3525 SetLastError(0xdeadbeef);
3526 hfont = CreateFontIndirectA(&lf);
3527 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3528 old_hfont = SelectObject(hdc, hfont);
3530 memset(&gm, 0, sizeof(gm));
3531 SetLastError(0xdeadbeef);
3532 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3533 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3535 memset(&gm, 0, sizeof(gm));
3536 SetLastError(0xdeadbeef);
3537 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3538 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3539 ok(GetLastError() == 0xdeadbeef ||
3540 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3541 "expected 0xdeadbeef, got %u\n", GetLastError());
3543 memset(&gm, 0, sizeof(gm));
3544 SetLastError(0xdeadbeef);
3545 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3546 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3547 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3549 memset(&gm, 0, sizeof(gm));
3550 SetLastError(0xdeadbeef);
3551 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3552 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3554 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3555 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3558 /* test for needed buffer size request on space char */
3559 memset(&gm, 0, sizeof(gm));
3560 SetLastError(0xdeadbeef);
3561 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3562 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3563 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3565 /* requesting buffer size for space char + error */
3566 memset(&gm, 0, sizeof(gm));
3567 SetLastError(0xdeadbeef);
3568 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3569 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3571 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3572 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3575 SelectObject(hdc, old_hfont);
3576 DeleteObject(hfont);
3578 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3580 lf.lfFaceName[0] = '\0';
3581 lf.lfCharSet = c[i].cs;
3582 lf.lfPitchAndFamily = 0;
3583 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3585 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3589 old_hfont = SelectObject(hdc, hfont);
3591 /* expected to ignore superfluous bytes (sigle-byte character) */
3592 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3593 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3594 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3596 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3597 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3598 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3600 /* expected to ignore superfluous bytes (double-byte character) */
3601 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3602 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3603 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3604 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3606 /* expected to match wide-char version results */
3607 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3608 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3610 hfont = SelectObject(hdc, old_hfont);
3611 DeleteObject(hfont);
3617 /* bug #9995: there is a limit to the character width that can be specified */
3618 static void test_GetTextMetrics2(const char *fontname, int font_height)
3624 int ave_width, height, width, ratio, scale;
3626 if (!is_truetype_font_installed( fontname)) {
3627 skip("%s is not installed\n", fontname);
3630 hdc = CreateCompatibleDC(0);
3631 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3632 /* select width = 0 */
3633 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3634 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3635 DEFAULT_QUALITY, VARIABLE_PITCH,
3637 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3638 of = SelectObject( hdc, hf);
3639 ret = GetTextMetricsA( hdc, &tm);
3640 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3641 height = tm.tmHeight;
3642 ave_width = tm.tmAveCharWidth;
3643 SelectObject( hdc, of);
3646 trace("height %d, ave width %d\n", height, ave_width);
3648 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3650 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3651 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3652 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3653 ok(hf != 0, "CreateFont failed\n");
3654 of = SelectObject(hdc, hf);
3655 ret = GetTextMetrics(hdc, &tm);
3656 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3657 SelectObject(hdc, of);
3660 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3666 ratio = width / height;
3667 scale = width / ave_width;
3669 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3670 width, height, ratio, width, ave_width, scale);
3672 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3675 static void test_CreateFontIndirect(void)
3677 LOGFONTA lf, getobj_lf;
3680 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3682 memset(&lf, 0, sizeof(lf));
3683 lf.lfCharSet = ANSI_CHARSET;
3684 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3687 lf.lfQuality = DEFAULT_QUALITY;
3688 lf.lfItalic = FALSE;
3689 lf.lfWeight = FW_DONTCARE;
3691 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3693 lstrcpyA(lf.lfFaceName, TestName[i]);
3694 hfont = CreateFontIndirectA(&lf);
3695 ok(hfont != 0, "CreateFontIndirectA failed\n");
3696 SetLastError(0xdeadbeef);
3697 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3698 ok(ret, "GetObject failed: %d\n", GetLastError());
3699 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3700 ok(lf.lfWeight == getobj_lf.lfWeight ||
3701 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3702 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3703 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3704 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3705 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3706 DeleteObject(hfont);
3710 static void test_CreateFontIndirectEx(void)
3712 ENUMLOGFONTEXDVA lfex;
3715 if (!pCreateFontIndirectExA)
3717 win_skip("CreateFontIndirectExA is not available\n");
3721 if (!is_truetype_font_installed("Arial"))
3723 skip("Arial is not installed\n");
3727 SetLastError(0xdeadbeef);
3728 hfont = pCreateFontIndirectExA(NULL);
3729 ok(hfont == NULL, "got %p\n", hfont);
3730 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3732 memset(&lfex, 0, sizeof(lfex));
3733 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3734 hfont = pCreateFontIndirectExA(&lfex);
3735 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3737 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3738 DeleteObject(hfont);
3741 static void free_font(void *font)
3743 UnmapViewOfFile(font);
3746 static void *load_font(const char *font_name, DWORD *font_size)
3748 char file_name[MAX_PATH];
3749 HANDLE file, mapping;
3752 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3753 strcat(file_name, "\\fonts\\");
3754 strcat(file_name, font_name);
3756 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3757 if (file == INVALID_HANDLE_VALUE) return NULL;
3759 *font_size = GetFileSize(file, NULL);
3761 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3768 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3771 CloseHandle(mapping);
3775 static void test_AddFontMemResource(void)
3778 DWORD font_size, num_fonts;
3782 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3784 win_skip("AddFontMemResourceEx is not available on this platform\n");
3788 font = load_font("sserife.fon", &font_size);
3791 skip("Unable to locate and load font sserife.fon\n");
3795 SetLastError(0xdeadbeef);
3796 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3797 ok(!ret, "AddFontMemResourceEx should fail\n");
3798 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3799 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3802 SetLastError(0xdeadbeef);
3803 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3804 ok(!ret, "AddFontMemResourceEx should fail\n");
3805 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3806 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3809 SetLastError(0xdeadbeef);
3810 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3811 ok(!ret, "AddFontMemResourceEx should fail\n");
3812 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3813 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3816 SetLastError(0xdeadbeef);
3817 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3818 ok(!ret, "AddFontMemResourceEx should fail\n");
3819 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3820 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3823 SetLastError(0xdeadbeef);
3824 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3825 ok(!ret, "AddFontMemResourceEx should fail\n");
3826 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3827 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3830 SetLastError(0xdeadbeef);
3831 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3832 ok(!ret, "AddFontMemResourceEx should fail\n");
3833 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3834 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3837 num_fonts = 0xdeadbeef;
3838 SetLastError(0xdeadbeef);
3839 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3840 ok(!ret, "AddFontMemResourceEx should fail\n");
3841 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3842 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3844 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3846 if (0) /* hangs under windows 2000 */
3848 num_fonts = 0xdeadbeef;
3849 SetLastError(0xdeadbeef);
3850 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3851 ok(!ret, "AddFontMemResourceEx should fail\n");
3852 ok(GetLastError() == 0xdeadbeef,
3853 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3855 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3858 num_fonts = 0xdeadbeef;
3859 SetLastError(0xdeadbeef);
3860 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3861 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3862 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3863 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3867 SetLastError(0xdeadbeef);
3868 bRet = pRemoveFontMemResourceEx(ret);
3869 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3871 /* test invalid pointer to number of loaded fonts */
3872 font = load_font("sserife.fon", &font_size);
3873 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3875 SetLastError(0xdeadbeef);
3876 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3877 ok(!ret, "AddFontMemResourceEx should fail\n");
3878 ok(GetLastError() == 0xdeadbeef,
3879 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3882 SetLastError(0xdeadbeef);
3883 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3884 ok(!ret, "AddFontMemResourceEx should fail\n");
3885 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3886 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3892 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3896 if (type != TRUETYPE_FONTTYPE) return 1;
3898 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3900 lf = (LOGFONT *)lparam;
3905 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3910 if (type != TRUETYPE_FONTTYPE) return 1;
3912 lf = (LOGFONT *)lparam;
3913 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3916 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3923 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3928 static void test_EnumFonts(void)
3934 if (!is_truetype_font_installed("Arial"))
3936 skip("Arial is not installed\n");
3940 /* Windows uses localized font face names, so Arial Bold won't be found */
3941 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3943 skip("User locale is not English, skipping the test\n");
3947 hdc = CreateCompatibleDC(0);
3949 /* check that the enumproc's retval is returned */
3950 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
3951 ok(ret == 0xcafe, "got %08x\n", ret);
3953 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3954 ok(!ret, "font Arial is not enumerated\n");
3955 ret = strcmp(lf.lfFaceName, "Arial");
3956 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3957 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3959 lstrcpy(lf.lfFaceName, "Arial");
3960 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3961 ok(!ret, "font Arial is not enumerated\n");
3962 ret = strcmp(lf.lfFaceName, "Arial");
3963 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3964 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3966 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3967 ok(!ret, "font Arial Bold is not enumerated\n");
3968 ret = strcmp(lf.lfFaceName, "Arial");
3969 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3970 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3972 lstrcpy(lf.lfFaceName, "Arial Bold");
3973 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3974 ok(ret, "font Arial Bold should not be enumerated\n");
3976 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3977 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3978 ret = strcmp(lf.lfFaceName, "Arial");
3979 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3980 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3982 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3983 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3984 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3986 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3987 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3989 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3990 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3991 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3996 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3998 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3999 const char *fullname = (const char *)lParam;
4001 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4006 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4011 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4018 static void test_fullname(void)
4020 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4021 WCHAR bufW[LF_FULLFACESIZE];
4022 char bufA[LF_FULLFACESIZE];
4029 hdc = CreateCompatibleDC(0);
4030 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4032 memset(&lf, 0, sizeof(lf));
4033 lf.lfCharSet = ANSI_CHARSET;
4034 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4037 lf.lfQuality = DEFAULT_QUALITY;
4038 lf.lfItalic = FALSE;
4039 lf.lfWeight = FW_DONTCARE;
4041 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4043 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4045 skip("%s is not installed\n", TestName[i]);
4049 lstrcpyA(lf.lfFaceName, TestName[i]);
4050 hfont = CreateFontIndirectA(&lf);
4051 ok(hfont != 0, "CreateFontIndirectA failed\n");
4053 of = SelectObject(hdc, hfont);
4056 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4057 ok(ret, "face full name could not be read\n");
4058 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4059 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4060 SelectObject(hdc, of);
4061 DeleteObject(hfont);
4066 static WCHAR *prepend_at(WCHAR *family)
4071 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4076 static void test_fullname2_helper(const char *Family)
4078 char *FamilyName, *FaceName, *StyleName, *otmStr;
4079 struct enum_fullname_data efnd;
4086 DWORD otm_size, ret, buf_size;
4087 OUTLINETEXTMETRICA *otm;
4088 BOOL want_vertical, get_vertical;
4089 want_vertical = ( Family[0] == '@' );
4091 hdc = CreateCompatibleDC(0);
4092 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4094 memset(&lf, 0, sizeof(lf));
4095 lf.lfCharSet = DEFAULT_CHARSET;
4096 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4099 lf.lfQuality = DEFAULT_QUALITY;
4100 lf.lfItalic = FALSE;
4101 lf.lfWeight = FW_DONTCARE;
4102 lstrcpy(lf.lfFaceName, Family);
4104 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4105 if (efnd.total == 0)
4106 skip("%s is not installed\n", lf.lfFaceName);
4108 for (i = 0; i < efnd.total; i++)
4110 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4111 FaceName = (char *)efnd.elf[i].elfFullName;
4112 StyleName = (char *)efnd.elf[i].elfStyle;
4114 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4116 get_vertical = ( FamilyName[0] == '@' );
4117 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4119 lstrcpyA(lf.lfFaceName, FaceName);
4120 hfont = CreateFontIndirectA(&lf);
4121 ok(hfont != 0, "CreateFontIndirectA failed\n");
4123 of = SelectObject(hdc, hfont);
4124 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4125 ok(buf_size != GDI_ERROR, "no name table found\n");
4126 if (buf_size == GDI_ERROR) continue;
4128 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4129 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4131 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4132 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4133 memset(otm, 0, otm_size);
4134 ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4135 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4136 if (ret == 0) continue;
4140 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4143 trace("no localized FONT_FAMILY found.\n");
4144 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4146 ok(ret, "FAMILY (family name) could not be read\n");
4147 if (want_vertical) bufW = prepend_at(bufW);
4148 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4149 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4150 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4151 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4155 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4158 trace("no localized FULL_NAME found.\n");
4159 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4161 ok(ret, "FULL_NAME (face name) could not be read\n");
4162 if (want_vertical) bufW = prepend_at(bufW);
4163 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4164 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4165 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4166 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4170 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4173 trace("no localized FONT_SUBFAMILY found.\n");
4174 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4176 ok(ret, "SUBFAMILY (style name) could not be read\n");
4177 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4178 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4179 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4180 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4184 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4187 trace("no localized UNIQUE_ID found.\n");
4188 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4190 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4191 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4192 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4193 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4195 SelectObject(hdc, of);
4196 DeleteObject(hfont);
4198 HeapFree(GetProcessHeap(), 0, otm);
4199 HeapFree(GetProcessHeap(), 0, bufW);
4200 HeapFree(GetProcessHeap(), 0, bufA);
4205 static void test_fullname2(void)
4207 test_fullname2_helper("Arial");
4208 test_fullname2_helper("DejaVu Sans");
4209 test_fullname2_helper("Lucida Sans");
4210 test_fullname2_helper("Tahoma");
4211 test_fullname2_helper("Webdings");
4212 test_fullname2_helper("Wingdings");
4213 test_fullname2_helper("SimSun");
4214 test_fullname2_helper("NSimSun");
4215 test_fullname2_helper("MingLiu");
4216 test_fullname2_helper("PMingLiu");
4217 test_fullname2_helper("WenQuanYi Micro Hei");
4218 test_fullname2_helper("MS UI Gothic");
4219 test_fullname2_helper("Ume UI Gothic");
4220 test_fullname2_helper("MS Gothic");
4221 test_fullname2_helper("Ume Gothic");
4222 test_fullname2_helper("MS PGothic");
4223 test_fullname2_helper("Ume P Gothic");
4224 test_fullname2_helper("Gulim");
4225 test_fullname2_helper("Batang");
4226 test_fullname2_helper("UnBatang");
4227 test_fullname2_helper("UnDotum");
4228 test_fullname2_helper("@SimSun");
4229 test_fullname2_helper("@NSimSun");
4230 test_fullname2_helper("@MingLiu");
4231 test_fullname2_helper("@PMingLiu");
4232 test_fullname2_helper("@WenQuanYi Micro Hei");
4233 test_fullname2_helper("@MS UI Gothic");
4234 test_fullname2_helper("@Ume UI Gothic");
4235 test_fullname2_helper("@MS Gothic");
4236 test_fullname2_helper("@Ume Gothic");
4237 test_fullname2_helper("@MS PGothic");
4238 test_fullname2_helper("@Ume P Gothic");
4239 test_fullname2_helper("@Gulim");
4240 test_fullname2_helper("@Batang");
4241 test_fullname2_helper("@UnBatang");
4242 test_fullname2_helper("@UnDotum");
4246 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4248 char tmp_path[MAX_PATH];
4255 SetLastError(0xdeadbeef);
4256 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4257 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4258 if (!rsrc) return FALSE;
4259 SetLastError(0xdeadbeef);
4260 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4261 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4262 if (!rsrc_data) return FALSE;
4263 SetLastError(0xdeadbeef);
4264 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4265 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4266 if (!rsrc_size) return FALSE;
4268 SetLastError(0xdeadbeef);
4269 ret = GetTempPath(MAX_PATH, tmp_path);
4270 ok(ret, "GetTempPath() error %d\n", GetLastError());
4271 SetLastError(0xdeadbeef);
4272 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4273 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4275 SetLastError(0xdeadbeef);
4276 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4277 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4278 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4280 SetLastError(0xdeadbeef);
4281 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4282 ok(ret, "WriteFile() error %d\n", GetLastError());
4288 static void test_GetGlyphOutline_empty_contour(void)
4292 HFONT hfont, hfont_prev;
4293 TTPOLYGONHEADER *header;
4298 memset(&lf, 0, sizeof(lf));
4300 lstrcpyA(lf.lfFaceName, "wine_test");
4302 hfont = CreateFontIndirectA(&lf);
4303 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4307 hfont_prev = SelectObject(hdc, hfont);
4308 ok(hfont_prev != NULL, "SelectObject failed\n");
4310 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
4311 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4313 header = (TTPOLYGONHEADER*)buf;
4314 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
4315 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4316 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
4317 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
4318 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4319 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4320 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4321 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4323 SelectObject(hdc, hfont_prev);
4324 DeleteObject(hfont);
4325 ReleaseDC(NULL, hdc);
4328 static void test_CreateScalableFontResource(void)
4330 char ttf_name[MAX_PATH];
4331 char tmp_path[MAX_PATH];
4332 char fot_name[MAX_PATH];
4336 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4338 win_skip("AddFontResourceExA is not available on this platform\n");
4342 if (!write_ttf_file("wine_test.ttf", ttf_name))
4344 skip("Failed to create ttf file for testing\n");
4348 trace("created %s\n", ttf_name);
4350 ret = is_truetype_font_installed("wine_test");
4351 ok(!ret, "font wine_test should not be enumerated\n");
4353 ret = GetTempPath(MAX_PATH, tmp_path);
4354 ok(ret, "GetTempPath() error %d\n", GetLastError());
4355 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4356 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4358 ret = GetFileAttributes(fot_name);
4359 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4361 SetLastError(0xdeadbeef);
4362 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4363 ok(!ret, "CreateScalableFontResource() should fail\n");
4364 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4366 SetLastError(0xdeadbeef);
4367 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4368 ok(!ret, "CreateScalableFontResource() should fail\n");
4369 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4371 file_part = strrchr(ttf_name, '\\');
4372 SetLastError(0xdeadbeef);
4373 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4374 ok(!ret, "CreateScalableFontResource() should fail\n");
4375 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4377 SetLastError(0xdeadbeef);
4378 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4379 ok(!ret, "CreateScalableFontResource() should fail\n");
4380 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4382 SetLastError(0xdeadbeef);
4383 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4384 ok(!ret, "CreateScalableFontResource() should fail\n");
4385 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4387 ret = DeleteFile(fot_name);
4388 ok(ret, "DeleteFile() error %d\n", GetLastError());
4390 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4392 ok(!ret, "RemoveFontResourceEx() should fail\n");
4394 /* test public font resource */
4395 SetLastError(0xdeadbeef);
4396 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4397 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4399 ret = is_truetype_font_installed("wine_test");
4400 ok(!ret, "font wine_test should not be enumerated\n");
4402 SetLastError(0xdeadbeef);
4403 ret = pAddFontResourceExA(fot_name, 0, 0);
4404 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4406 ret = is_truetype_font_installed("wine_test");
4407 ok(ret, "font wine_test should be enumerated\n");
4409 test_GetGlyphOutline_empty_contour();
4411 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4413 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4415 SetLastError(0xdeadbeef);
4416 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4417 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4419 ret = is_truetype_font_installed("wine_test");
4421 ok(!ret, "font wine_test should not be enumerated\n");
4423 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4426 /* remove once RemoveFontResource is implemented */
4427 DeleteFile(fot_name);
4428 DeleteFile(ttf_name);
4432 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4433 ok(!ret, "RemoveFontResourceEx() should fail\n");
4435 DeleteFile(fot_name);
4437 /* test hidden font resource */
4438 SetLastError(0xdeadbeef);
4439 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4440 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4442 ret = is_truetype_font_installed("wine_test");
4443 ok(!ret, "font wine_test should not be enumerated\n");
4445 SetLastError(0xdeadbeef);
4446 ret = pAddFontResourceExA(fot_name, 0, 0);
4447 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4449 ret = is_truetype_font_installed("wine_test");
4450 ok(!ret, "font wine_test should not be enumerated\n");
4452 /* XP allows removing a private font added with 0 flags */
4453 SetLastError(0xdeadbeef);
4454 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4455 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4457 ret = is_truetype_font_installed("wine_test");
4458 ok(!ret, "font wine_test should not be enumerated\n");
4460 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4461 ok(!ret, "RemoveFontResourceEx() should fail\n");
4463 DeleteFile(fot_name);
4464 DeleteFile(ttf_name);
4467 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4470 HFONT hfont, hfont_prev;
4474 static const WCHAR str[] = { 0x2025 };
4476 *installed = is_truetype_font_installed(name);
4480 lf.lfEscapement = 0;
4481 lf.lfOrientation = 0;
4482 lf.lfWeight = FW_DONTCARE;
4486 lf.lfCharSet = DEFAULT_CHARSET;
4487 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4488 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4489 lf.lfQuality = DEFAULT_QUALITY;
4490 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4491 strcpy(lf.lfFaceName, name);
4493 hfont = CreateFontIndirectA(&lf);
4494 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4498 hfont_prev = SelectObject(hdc, hfont);
4499 ok(hfont_prev != NULL, "SelectObject failed\n");
4501 ret = GetTextFaceA(hdc, sizeof facename, facename);
4502 ok(ret, "GetTextFaceA failed\n");
4503 *selected = !strcmp(facename, name);
4505 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4506 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4508 memset(gm, 0, sizeof *gm);
4510 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4511 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4513 SelectObject(hdc, hfont_prev);
4514 DeleteObject(hfont);
4515 ReleaseDC(NULL, hdc);
4518 static void test_vertical_font(void)
4520 char ttf_name[MAX_PATH];
4522 BOOL ret, installed, selected;
4526 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4528 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4532 if (!write_ttf_file("vertical.ttf", ttf_name))
4534 skip("Failed to create ttf file for testing\n");
4538 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4539 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4541 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4542 ok(installed, "@WineTestVertical is not installed\n");
4543 ok(selected, "@WineTestVertical is not selected\n");
4544 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4545 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4546 gm.gmBlackBoxX, gm.gmBlackBoxY);
4548 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4549 ok(installed, "@@WineTestVertical is not installed\n");
4550 ok(selected, "@@WineTestVertical is not selected\n");
4551 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4552 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4553 gm.gmBlackBoxX, gm.gmBlackBoxY);
4555 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4557 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4558 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4560 DeleteFile(ttf_name);
4563 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4564 DWORD type, LPARAM lParam)
4566 if (lf->lfFaceName[0] == '@') {
4572 static void test_east_asian_font_selection(void)
4575 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4576 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4581 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4585 char face_name[LF_FACESIZE];
4588 memset(&lf, 0, sizeof lf);
4589 lf.lfFaceName[0] = '\0';
4590 lf.lfCharSet = charset[i];
4592 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4594 skip("Vertical font for charset %u is not installed\n", charset[i]);
4598 hfont = CreateFontIndirectA(&lf);
4599 hfont = SelectObject(hdc, hfont);
4600 memset(face_name, 0, sizeof face_name);
4601 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4602 ok(ret && face_name[0] != '@',
4603 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4604 DeleteObject(SelectObject(hdc, hfont));
4606 memset(&lf, 0, sizeof lf);
4607 strcpy(lf.lfFaceName, "@");
4608 lf.lfCharSet = charset[i];
4609 hfont = CreateFontIndirectA(&lf);
4610 hfont = SelectObject(hdc, hfont);
4611 memset(face_name, 0, sizeof face_name);
4612 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4613 ok(ret && face_name[0] == '@',
4614 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4615 DeleteObject(SelectObject(hdc, hfont));
4617 ReleaseDC(NULL, hdc);
4620 static int get_font_dpi(const LOGFONT *lf)
4622 HDC hdc = CreateCompatibleDC(0);
4627 hfont = CreateFontIndirect(lf);
4628 ok(hfont != 0, "CreateFontIndirect failed\n");
4630 SelectObject(hdc, hfont);
4631 ret = GetTextMetrics(hdc, &tm);
4632 ok(ret, "GetTextMetrics failed\n");
4633 ret = tm.tmDigitizedAspectX;
4636 DeleteObject(hfont);
4641 static void test_stock_fonts(void)
4643 static const int font[] =
4645 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4646 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4648 static const struct test_data
4650 int charset, weight, height, dpi;
4651 const char face_name[LF_FACESIZE];
4654 { /* ANSI_FIXED_FONT */
4655 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4656 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4659 { /* ANSI_VAR_FONT */
4660 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4661 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4665 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4666 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4667 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4668 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4669 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4670 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4673 { /* DEVICE_DEFAULT_FONT */
4674 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4675 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4676 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4677 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4678 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4679 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4682 { /* DEFAULT_GUI_FONT */
4683 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4684 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4685 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4686 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4687 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4688 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4689 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4690 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4691 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4692 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4698 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4704 hfont = GetStockObject(font[i]);
4705 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4707 ret = GetObject(hfont, sizeof(lf), &lf);
4708 if (ret != sizeof(lf))
4711 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4715 for (j = 0; td[i][j].face_name[0] != 0; j++)
4717 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4722 ret = get_font_dpi(&lf);
4723 if (ret != td[i][j].dpi)
4725 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4726 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4730 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4731 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4732 if (td[i][j].face_name[0] == '?')
4734 /* Wine doesn't have this font, skip this case for now.
4735 Actually, the face name is localized on Windows and varies
4736 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4737 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4741 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);
4755 test_outline_font();
4756 test_bitmap_font_metrics();
4757 test_GdiGetCharDimensions();
4758 test_GetCharABCWidths();
4759 test_text_extents();
4760 test_GetGlyphIndices();
4761 test_GetKerningPairs();
4762 test_GetOutlineTextMetrics();
4763 test_SetTextJustification();
4764 test_font_charset();
4765 test_GetFontUnicodeRanges();
4766 test_nonexistent_font();
4768 test_height_selection();
4769 test_AddFontMemResource();
4772 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4773 * I'd like to avoid them in this test.
4775 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4776 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4777 if (is_truetype_font_installed("Arial Black") &&
4778 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4780 test_EnumFontFamilies("", ANSI_CHARSET);
4781 test_EnumFontFamilies("", SYMBOL_CHARSET);
4782 test_EnumFontFamilies("", DEFAULT_CHARSET);
4785 skip("Arial Black or Symbol/Wingdings is not installed\n");
4786 test_EnumFontFamiliesEx_default_charset();
4787 test_GetTextMetrics();
4788 test_GdiRealizationInfo();
4790 test_GetGlyphOutline();
4791 test_GetTextMetrics2("Tahoma", -11);
4792 test_GetTextMetrics2("Tahoma", -55);
4793 test_GetTextMetrics2("Tahoma", -110);
4794 test_GetTextMetrics2("Arial", -11);
4795 test_GetTextMetrics2("Arial", -55);
4796 test_GetTextMetrics2("Arial", -110);
4797 test_CreateFontIndirect();
4798 test_CreateFontIndirectEx();
4802 test_east_asian_font_selection();
4804 /* These tests should be last test until RemoveFontResource
4805 * is properly implemented.
4807 test_vertical_font();
4808 test_CreateScalableFontResource();