2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
45 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
46 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
48 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
49 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
50 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
51 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
52 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
54 static HMODULE hgdi32 = 0;
55 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
57 static void init(void)
59 hgdi32 = GetModuleHandleA("gdi32.dll");
61 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
62 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
63 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
64 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
65 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
66 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
67 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
68 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
69 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
70 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
71 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
72 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
73 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
74 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
77 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
79 if (type != TRUETYPE_FONTTYPE) return 1;
84 static BOOL is_truetype_font_installed(const char *name)
89 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
96 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
101 static BOOL is_font_installed(const char *name)
106 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
113 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
121 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
122 /* NT4 tries to be clever and only returns the minimum length */
123 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
125 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
126 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
127 ok(lf->lfHeight == getobj_lf.lfHeight ||
128 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
129 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
130 ok(lf->lfWidth == getobj_lf.lfWidth ||
131 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
132 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
133 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
134 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
135 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
136 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
137 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
138 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
139 ok(lf->lfWeight == getobj_lf.lfWeight ||
140 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
141 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
142 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
143 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
144 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
145 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
146 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
147 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
148 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
149 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
150 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
151 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
152 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
155 static HFONT create_font(const char* test, const LOGFONTA* lf)
157 HFONT hfont = CreateFontIndirectA(lf);
158 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
160 check_font(test, lf, hfont);
164 static void test_logfont(void)
169 memset(&lf, 0, sizeof lf);
171 lf.lfCharSet = ANSI_CHARSET;
172 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
173 lf.lfWeight = FW_DONTCARE;
176 lf.lfQuality = DEFAULT_QUALITY;
178 lstrcpyA(lf.lfFaceName, "Arial");
179 hfont = create_font("Arial", &lf);
182 memset(&lf, 'A', sizeof(lf));
183 hfont = CreateFontIndirectA(&lf);
184 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
186 lf.lfFaceName[LF_FACESIZE - 1] = 0;
187 check_font("AAA...", &lf, hfont);
191 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
193 if (type & RASTER_FONTTYPE)
195 LOGFONT *lf = (LOGFONT *)lParam;
197 return 0; /* stop enumeration */
200 return 1; /* continue enumeration */
203 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
205 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
206 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
207 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
208 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
209 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
210 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
211 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
212 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
213 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
214 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
215 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
216 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
217 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
218 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
219 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
220 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
221 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
222 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
223 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
224 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
227 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
228 LONG lfWidth, const char *test_str,
229 INT test_str_len, const TEXTMETRICA *tm_orig,
230 const SIZE *size_orig, INT width_of_A_orig,
231 INT scale_x, INT scale_y)
234 OUTLINETEXTMETRIC otm;
237 INT width_of_A, cx, cy;
243 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
245 GetObjectA(hfont, sizeof(lf), &lf);
247 if (GetOutlineTextMetricsA(hdc, 0, NULL))
249 otm.otmSize = sizeof(otm) / 2;
250 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
251 ok(ret == sizeof(otm)/2 /* XP */ ||
252 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
254 memset(&otm, 0x1, sizeof(otm));
255 otm.otmSize = sizeof(otm);
256 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
257 ok(ret == sizeof(otm) /* XP */ ||
258 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
260 memset(&tm, 0x2, sizeof(tm));
261 ret = GetTextMetricsA(hdc, &tm);
262 ok(ret, "GetTextMetricsA failed\n");
263 /* the structure size is aligned */
264 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
266 ok(0, "tm != otm\n");
267 compare_tm(&tm, &otm.otmTextMetrics);
270 tm = otm.otmTextMetrics;
271 if (0) /* these metrics are scaled too, but with rounding errors */
273 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
274 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
276 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
277 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
278 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
279 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
280 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
281 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
285 ret = GetTextMetricsA(hdc, &tm);
286 ok(ret, "GetTextMetricsA failed\n");
289 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
290 cy = tm.tmHeight / tm_orig->tmHeight;
291 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
292 lfHeight, scale_x, scale_y, cx, cy);
293 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
294 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
295 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
296 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
297 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
299 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
303 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
306 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
308 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
310 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
311 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
313 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
315 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);
318 /* Test how GDI scales bitmap font metrics */
319 static void test_bitmap_font(void)
321 static const char test_str[11] = "Test String";
324 HFONT hfont, old_hfont;
327 INT ret, i, width_orig, height_orig, scale, lfWidth;
331 /* "System" has only 1 pixel size defined, otherwise the test breaks */
332 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
336 trace("no bitmap fonts were found, skipping the test\n");
340 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
342 height_orig = bitmap_lf.lfHeight;
343 lfWidth = bitmap_lf.lfWidth;
345 hfont = create_font("bitmap", &bitmap_lf);
346 old_hfont = SelectObject(hdc, hfont);
347 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
348 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
349 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
350 SelectObject(hdc, old_hfont);
353 bitmap_lf.lfHeight = 0;
354 bitmap_lf.lfWidth = 4;
355 hfont = create_font("bitmap", &bitmap_lf);
356 old_hfont = SelectObject(hdc, hfont);
357 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
358 SelectObject(hdc, old_hfont);
361 bitmap_lf.lfHeight = height_orig;
362 bitmap_lf.lfWidth = lfWidth;
364 /* test fractional scaling */
365 for (i = 1; i <= height_orig * 6; i++)
369 bitmap_lf.lfHeight = i;
370 hfont = create_font("fractional", &bitmap_lf);
371 scale = (i + height_orig - 1) / height_orig;
372 nearest_height = scale * height_orig;
373 /* Only jump to the next height if the difference <= 25% original height */
374 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
375 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
376 so we'll not test this particular height. */
377 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
378 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
379 old_hfont = SelectObject(hdc, hfont);
380 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
381 SelectObject(hdc, old_hfont);
385 /* test integer scaling 3x2 */
386 bitmap_lf.lfHeight = height_orig * 2;
387 bitmap_lf.lfWidth *= 3;
388 hfont = create_font("3x2", &bitmap_lf);
389 old_hfont = SelectObject(hdc, hfont);
390 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
391 SelectObject(hdc, old_hfont);
394 /* test integer scaling 3x3 */
395 bitmap_lf.lfHeight = height_orig * 3;
396 bitmap_lf.lfWidth = 0;
397 hfont = create_font("3x3", &bitmap_lf);
398 old_hfont = SelectObject(hdc, hfont);
399 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
400 SelectObject(hdc, old_hfont);
406 /* Test how GDI scales outline font metrics */
407 static void test_outline_font(void)
409 static const char test_str[11] = "Test String";
412 HFONT hfont, old_hfont, old_hfont_2;
413 OUTLINETEXTMETRICA otm;
415 INT width_orig, height_orig, lfWidth;
418 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
422 if (!is_truetype_font_installed("Arial"))
424 skip("Arial is not installed\n");
428 hdc = CreateCompatibleDC(0);
430 memset(&lf, 0, sizeof(lf));
431 strcpy(lf.lfFaceName, "Arial");
433 hfont = create_font("outline", &lf);
434 old_hfont = SelectObject(hdc, hfont);
435 otm.otmSize = sizeof(otm);
436 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
437 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
438 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
440 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
441 SelectObject(hdc, old_hfont);
444 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
445 lf.lfHeight = otm.otmEMSquare;
446 lf.lfHeight = -lf.lfHeight;
447 hfont = create_font("outline", &lf);
448 old_hfont = SelectObject(hdc, hfont);
449 otm.otmSize = sizeof(otm);
450 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
451 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
452 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
453 SelectObject(hdc, old_hfont);
456 height_orig = otm.otmTextMetrics.tmHeight;
457 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
459 /* test integer scaling 3x2 */
460 lf.lfHeight = height_orig * 2;
461 lf.lfWidth = lfWidth * 3;
462 hfont = create_font("3x2", &lf);
463 old_hfont = SelectObject(hdc, hfont);
464 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
465 SelectObject(hdc, old_hfont);
468 /* test integer scaling 3x3 */
469 lf.lfHeight = height_orig * 3;
470 lf.lfWidth = lfWidth * 3;
471 hfont = create_font("3x3", &lf);
472 old_hfont = SelectObject(hdc, hfont);
473 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
474 SelectObject(hdc, old_hfont);
477 /* test integer scaling 1x1 */
478 lf.lfHeight = height_orig * 1;
479 lf.lfWidth = lfWidth * 1;
480 hfont = create_font("1x1", &lf);
481 old_hfont = SelectObject(hdc, hfont);
482 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
483 SelectObject(hdc, old_hfont);
486 /* test integer scaling 1x1 */
487 lf.lfHeight = height_orig;
489 hfont = create_font("1x1", &lf);
490 old_hfont = SelectObject(hdc, hfont);
491 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
493 /* with an identity matrix */
494 memset(&gm, 0, sizeof(gm));
495 SetLastError(0xdeadbeef);
496 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
497 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
498 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
499 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
500 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
501 /* with a custom matrix */
502 memset(&gm, 0, sizeof(gm));
503 SetLastError(0xdeadbeef);
504 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
505 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
506 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
507 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
508 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
510 /* Test that changing the DC transformation affects only the font
511 * selected on this DC and doesn't affect the same font selected on
514 hdc_2 = CreateCompatibleDC(0);
515 old_hfont_2 = SelectObject(hdc_2, hfont);
516 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
518 SetMapMode(hdc, MM_ANISOTROPIC);
520 /* font metrics on another DC should be unchanged */
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 /* test restrictions of compatibility mode GM_COMPATIBLE */
524 /* part 1: rescaling only X should not change font scaling on screen.
525 So compressing the X axis by 2 is not done, and this
526 appears as X scaling of 2 that no one requested. */
527 SetWindowExtEx(hdc, 100, 100, NULL);
528 SetViewportExtEx(hdc, 50, 100, NULL);
529 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
530 /* font metrics on another DC should be unchanged */
531 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
533 /* part 2: rescaling only Y should change font scaling.
534 As also X is scaled by a factor of 2, but this is not
535 requested by the DC transformation, we get a scaling factor
536 of 2 in the X coordinate. */
537 SetViewportExtEx(hdc, 100, 200, NULL);
538 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
539 /* font metrics on another DC should be unchanged */
540 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
542 /* restore scaling */
543 SetMapMode(hdc, MM_TEXT);
545 /* font metrics on another DC should be unchanged */
546 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
548 SelectObject(hdc_2, old_hfont_2);
551 if (!SetGraphicsMode(hdc, GM_ADVANCED))
553 SelectObject(hdc, old_hfont);
556 skip("GM_ADVANCED is not supported on this platform\n");
567 SetLastError(0xdeadbeef);
568 ret = SetWorldTransform(hdc, &xform);
569 ok(ret, "SetWorldTransform error %u\n", GetLastError());
571 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
573 /* with an identity matrix */
574 memset(&gm, 0, sizeof(gm));
575 SetLastError(0xdeadbeef);
576 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
577 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
578 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
579 pt.x = width_orig; pt.y = 0;
581 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
582 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
583 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
584 /* with a custom matrix */
585 memset(&gm, 0, sizeof(gm));
586 SetLastError(0xdeadbeef);
587 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
588 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
589 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
590 pt.x = width_orig; pt.y = 0;
592 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
593 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
594 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
596 SetLastError(0xdeadbeef);
597 ret = SetMapMode(hdc, MM_LOMETRIC);
598 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
600 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
602 /* with an identity matrix */
603 memset(&gm, 0, sizeof(gm));
604 SetLastError(0xdeadbeef);
605 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
606 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
607 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
608 pt.x = width_orig; pt.y = 0;
610 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
611 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
612 /* with a custom matrix */
613 memset(&gm, 0, sizeof(gm));
614 SetLastError(0xdeadbeef);
615 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
616 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
617 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
618 pt.x = width_orig; pt.y = 0;
620 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
621 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
623 SetLastError(0xdeadbeef);
624 ret = SetMapMode(hdc, MM_TEXT);
625 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
627 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
629 /* with an identity matrix */
630 memset(&gm, 0, sizeof(gm));
631 SetLastError(0xdeadbeef);
632 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
633 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
634 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
635 pt.x = width_orig; pt.y = 0;
637 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
638 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
639 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
640 /* with a custom matrix */
641 memset(&gm, 0, sizeof(gm));
642 SetLastError(0xdeadbeef);
643 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
644 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
645 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
646 pt.x = width_orig; pt.y = 0;
648 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
649 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
650 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
652 SelectObject(hdc, old_hfont);
657 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
659 LOGFONT *lf = (LOGFONT *)lParam;
661 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
664 return 0; /* stop enumeration */
666 return 1; /* continue enumeration */
669 static void test_bitmap_font_metrics(void)
671 static const struct font_data
673 const char face_name[LF_FACESIZE];
674 int weight, height, ascent, descent, int_leading, ext_leading;
675 int ave_char_width, max_char_width, dpi;
680 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
681 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
682 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
684 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
685 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
686 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
687 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
688 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
689 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
690 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
693 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
694 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
695 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
696 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
697 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
698 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
699 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
701 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
702 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
703 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
705 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
706 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
707 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
708 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
709 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
710 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
711 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
712 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
713 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
714 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
715 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
717 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
719 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
721 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
722 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
723 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
724 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
725 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
726 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
727 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
728 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
729 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
731 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
732 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
733 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
735 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
736 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
737 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
739 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
740 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
741 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
743 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
744 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
746 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
747 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
748 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
749 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1, LANG_ARABIC },
750 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
751 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
752 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1, LANG_ARABIC },
753 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
754 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_ARABIC },
755 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1, LANG_ARABIC },
757 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_ARABIC },
759 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
761 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
762 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, FS_ARABIC },
763 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
765 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, FS_ARABIC },
766 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
768 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
769 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
770 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
771 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
772 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
773 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
774 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
775 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
776 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
777 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
778 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
779 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
781 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
782 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
783 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
785 /* The 120dpi version still has its dpi marked as 96 */
786 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
788 /* FIXME: add "Terminal" */
792 HFONT hfont, old_hfont;
797 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
799 hdc = CreateCompatibleDC(0);
802 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
806 memset(&lf, 0, sizeof(lf));
808 lf.lfHeight = fd[i].height;
809 strcpy(lf.lfFaceName, fd[i].face_name);
811 for(bit = 0; bit < 32; bit++)
819 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
820 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
822 lf.lfCharSet = csi.ciCharset;
823 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
826 hfont = create_font(lf.lfFaceName, &lf);
827 old_hfont = SelectObject(hdc, hfont);
828 bRet = GetTextMetrics(hdc, &tm);
829 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
830 if(fd[i].dpi == tm.tmDigitizedAspectX)
832 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
833 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
835 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
836 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);
837 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
838 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
839 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
840 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
841 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
843 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
844 that make the max width bigger */
845 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
846 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
849 skip("Skipping font metrics test for system langid 0x%x\n",
852 SelectObject(hdc, old_hfont);
860 static void test_GdiGetCharDimensions(void)
866 LONG avgwidth, height;
867 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
869 if (!pGdiGetCharDimensions)
871 win_skip("GdiGetCharDimensions not available on this platform\n");
875 hdc = CreateCompatibleDC(NULL);
877 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
878 avgwidth = ((size.cx / 26) + 1) / 2;
880 ret = pGdiGetCharDimensions(hdc, &tm, &height);
881 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
882 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
884 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
885 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
887 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
888 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
891 ret = pGdiGetCharDimensions(hdc, NULL, &height);
892 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
893 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
898 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
899 const TEXTMETRIC *lpntme,
900 DWORD FontType, LPARAM lParam)
902 if (FontType & TRUETYPE_FONTTYPE)
906 hfont = CreateFontIndirect(lpelfe);
909 *(HFONT *)lParam = hfont;
917 static void test_GetCharABCWidths(void)
919 static const WCHAR str[] = {'a',0};
940 {0xffffff, 0xffffff},
941 {0x1000000, 0x1000000},
942 {0xffffff, 0x1000000},
943 {0xffffffff, 0xffffffff}
950 BOOL r[sizeof range / sizeof range[0]];
953 {ANSI_CHARSET, 0x30, 0x30, {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
954 {SHIFTJIS_CHARSET, 0x82a0, 0x3042, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
955 {HANGEUL_CHARSET, 0x8141, 0xac02, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
956 {JOHAB_CHARSET, 0x8446, 0x3135, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
957 {GB2312_CHARSET, 0x8141, 0x4e04, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
958 {CHINESEBIG5_CHARSET, 0xa142, 0x3001, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}}
962 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsI)
964 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
968 memset(&lf, 0, sizeof(lf));
969 strcpy(lf.lfFaceName, "System");
972 hfont = CreateFontIndirectA(&lf);
974 hfont = SelectObject(hdc, hfont);
976 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
977 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
979 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
980 ok(!ret, "GetCharABCWidthsI should have failed\n");
982 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
983 ok(!ret, "GetCharABCWidthsI should have failed\n");
985 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
986 ok(ret, "GetCharABCWidthsI should have succeeded\n");
988 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
989 ok(!ret, "GetCharABCWidthsW should have failed\n");
991 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
992 ok(!ret, "GetCharABCWidthsW should have failed\n");
994 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
995 ok(!ret, "GetCharABCWidthsW should have failed\n");
997 hfont = SelectObject(hdc, hfont);
1000 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1004 UINT code = 0x41, j;
1006 lf.lfFaceName[0] = '\0';
1007 lf.lfCharSet = c[i].cs;
1008 lf.lfPitchAndFamily = 0;
1009 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1011 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1015 memset(a, 0, sizeof a);
1016 memset(w, 0, sizeof w);
1017 hfont = SelectObject(hdc, hfont);
1018 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1019 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1020 memcmp(a, w, sizeof a) == 0,
1021 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1023 memset(a, 0xbb, sizeof a);
1024 ret = pGetCharABCWidthsA(hdc, code, code, a);
1025 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1026 memset(full, 0xcc, sizeof full);
1027 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1028 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1029 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1030 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1032 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1034 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1035 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1036 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1039 hfont = SelectObject(hdc, hfont);
1040 DeleteObject(hfont);
1043 ReleaseDC(NULL, hdc);
1046 static void test_text_extents(void)
1048 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1050 INT i, len, fit1, fit2;
1059 memset(&lf, 0, sizeof(lf));
1060 strcpy(lf.lfFaceName, "Arial");
1063 hfont = CreateFontIndirectA(&lf);
1065 hfont = SelectObject(hdc, hfont);
1066 GetTextMetricsA(hdc, &tm);
1067 GetTextExtentPointA(hdc, "o", 1, &sz);
1068 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1070 SetLastError(0xdeadbeef);
1071 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1072 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1074 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1075 hfont = SelectObject(hdc, hfont);
1076 DeleteObject(hfont);
1082 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1083 extents[0] = 1; /* So that the increasing sequence test will fail
1084 if the extents array is untouched. */
1085 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1086 GetTextExtentPointW(hdc, wt, len, &sz2);
1087 ok(sz1.cy == sz2.cy,
1088 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1089 /* Because of the '\n' in the string GetTextExtentExPoint and
1090 GetTextExtentPoint return different widths under Win2k, but
1091 under WinXP they return the same width. So we don't test that
1094 for (i = 1; i < len; ++i)
1095 ok(extents[i-1] <= extents[i],
1096 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1098 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1099 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1100 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1101 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1102 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1103 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1104 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1105 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1106 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1107 ok(extents[0] == extents[2] && extents[1] == extents[3],
1108 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1109 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1110 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1111 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1112 HeapFree(GetProcessHeap(), 0, extents);
1114 /* extents functions fail with -ve counts (the interesting case being -1) */
1115 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1116 ok(ret == FALSE, "got %d\n", ret);
1117 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1118 ok(ret == FALSE, "got %d\n", ret);
1119 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1120 ok(ret == FALSE, "got %d\n", ret);
1122 hfont = SelectObject(hdc, hfont);
1123 DeleteObject(hfont);
1124 ReleaseDC(NULL, hdc);
1127 static void test_GetGlyphIndices(void)
1134 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1135 WORD glyphs[(sizeof(testtext)/2)-1];
1139 if (!pGetGlyphIndicesW) {
1140 win_skip("GetGlyphIndicesW not available on platform\n");
1146 memset(&lf, 0, sizeof(lf));
1147 strcpy(lf.lfFaceName, "System");
1149 lf.lfCharSet = ANSI_CHARSET;
1151 hfont = CreateFontIndirectA(&lf);
1152 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1153 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1154 if (textm.tmCharSet == ANSI_CHARSET)
1156 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1157 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1158 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1159 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1161 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1162 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1163 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1164 textm.tmDefaultChar, glyphs[4]);
1167 /* FIXME: Write tests for non-ANSI charsets. */
1168 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1170 if(!is_font_installed("Tahoma"))
1172 skip("Tahoma is not installed so skipping this test\n");
1175 memset(&lf, 0, sizeof(lf));
1176 strcpy(lf.lfFaceName, "Tahoma");
1179 hfont = CreateFontIndirectA(&lf);
1180 hOldFont = SelectObject(hdc, hfont);
1181 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1182 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1183 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1184 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1185 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1187 testtext[0] = textm.tmDefaultChar;
1188 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1189 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1190 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1191 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1192 DeleteObject(SelectObject(hdc, hOldFont));
1195 static void test_GetKerningPairs(void)
1197 static const struct kerning_data
1199 const char face_name[LF_FACESIZE];
1201 /* some interesting fields from OUTLINETEXTMETRIC */
1202 LONG tmHeight, tmAscent, tmDescent;
1207 UINT otmsCapEmHeight;
1212 UINT otmusMinimumPPEM;
1213 /* small subset of kerning pairs to test */
1214 DWORD total_kern_pairs;
1215 const KERNINGPAIR kern_pair[26];
1218 {"Arial", 12, 12, 9, 3,
1219 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1222 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1223 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1224 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1225 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1226 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1227 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1228 {933,970,+1},{933,972,-1}
1231 {"Arial", -34, 39, 32, 7,
1232 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1235 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1236 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1237 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1238 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1239 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1240 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1241 {933,970,+2},{933,972,-3}
1244 { "Arial", 120, 120, 97, 23,
1245 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1248 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1249 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1250 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1251 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1252 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1253 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1254 {933,970,+6},{933,972,-10}
1257 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1258 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1259 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1262 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1263 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1264 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1265 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1266 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1267 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1268 {933,970,+54},{933,972,-83}
1274 HFONT hfont, hfont_old;
1275 KERNINGPAIR *kern_pair;
1277 DWORD total_kern_pairs, ret, i, n, matches;
1281 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1282 * which may render this test unusable, so we're trying to avoid that.
1284 SetLastError(0xdeadbeef);
1285 GetKerningPairsW(hdc, 0, NULL);
1286 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1288 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1293 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1295 OUTLINETEXTMETRICW otm;
1298 if (!is_font_installed(kd[i].face_name))
1300 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1304 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1306 memset(&lf, 0, sizeof(lf));
1307 strcpy(lf.lfFaceName, kd[i].face_name);
1308 lf.lfHeight = kd[i].height;
1309 hfont = CreateFontIndirect(&lf);
1312 hfont_old = SelectObject(hdc, hfont);
1314 SetLastError(0xdeadbeef);
1315 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1316 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1317 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1319 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1320 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1321 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1322 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1323 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1324 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1326 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1327 kd[i].otmEMSquare, otm.otmEMSquare);
1328 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1329 kd[i].otmAscent, otm.otmAscent);
1330 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1331 kd[i].otmDescent, otm.otmDescent);
1332 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1333 kd[i].otmLineGap, otm.otmLineGap);
1334 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1335 kd[i].otmMacDescent, otm.otmMacDescent);
1336 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1337 kd[i].otmMacAscent, otm.otmMacAscent);
1339 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1340 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1341 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1342 kd[i].otmsXHeight, otm.otmsXHeight);
1343 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1344 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1345 kd[i].otmMacLineGap, otm.otmMacLineGap);
1346 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1347 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1350 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1351 trace("total_kern_pairs %u\n", total_kern_pairs);
1352 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1354 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1357 SetLastError(0xdeadbeef);
1358 ret = GetKerningPairsW(hdc, 0, kern_pair);
1359 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1360 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1361 ok(ret == 0, "got %u, expected 0\n", ret);
1363 ret = GetKerningPairsW(hdc, 100, NULL);
1364 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1366 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1367 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1369 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1370 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1374 for (n = 0; n < ret; n++)
1377 /* Disabled to limit console spam */
1378 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1379 trace("{'%c','%c',%d},\n",
1380 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1381 for (j = 0; j < kd[i].total_kern_pairs; j++)
1383 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1384 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1386 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1387 "pair %d:%d got %d, expected %d\n",
1388 kern_pair[n].wFirst, kern_pair[n].wSecond,
1389 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1395 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1396 matches, kd[i].total_kern_pairs);
1398 HeapFree(GetProcessHeap(), 0, kern_pair);
1400 SelectObject(hdc, hfont_old);
1401 DeleteObject(hfont);
1407 static void test_height_selection(void)
1409 static const struct font_data
1411 const char face_name[LF_FACESIZE];
1412 int requested_height;
1413 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1416 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1417 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1418 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1419 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1420 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1421 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1422 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1423 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1424 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1425 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1429 HFONT hfont, old_hfont;
1433 hdc = CreateCompatibleDC(0);
1436 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1438 if (!is_truetype_font_installed(fd[i].face_name))
1440 skip("%s is not installed\n", fd[i].face_name);
1444 memset(&lf, 0, sizeof(lf));
1445 lf.lfHeight = fd[i].requested_height;
1446 lf.lfWeight = fd[i].weight;
1447 strcpy(lf.lfFaceName, fd[i].face_name);
1449 hfont = CreateFontIndirect(&lf);
1452 old_hfont = SelectObject(hdc, hfont);
1453 ret = GetTextMetrics(hdc, &tm);
1454 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1455 if(fd[i].dpi == tm.tmDigitizedAspectX)
1457 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1458 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);
1459 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);
1460 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);
1461 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);
1462 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1463 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);
1465 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);
1468 SelectObject(hdc, old_hfont);
1469 DeleteObject(hfont);
1475 static void test_GetOutlineTextMetrics(void)
1477 OUTLINETEXTMETRIC *otm;
1479 HFONT hfont, hfont_old;
1481 DWORD ret, otm_size;
1484 if (!is_font_installed("Arial"))
1486 skip("Arial is not installed\n");
1492 memset(&lf, 0, sizeof(lf));
1493 strcpy(lf.lfFaceName, "Arial");
1495 lf.lfWeight = FW_NORMAL;
1496 lf.lfPitchAndFamily = DEFAULT_PITCH;
1497 lf.lfQuality = PROOF_QUALITY;
1498 hfont = CreateFontIndirect(&lf);
1501 hfont_old = SelectObject(hdc, hfont);
1502 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1503 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1505 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1507 memset(otm, 0xAA, otm_size);
1508 SetLastError(0xdeadbeef);
1509 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1510 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1511 ok(ret == 1 /* Win9x */ ||
1512 ret == otm->otmSize /* XP*/,
1513 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1514 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1516 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1517 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1518 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1519 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1522 memset(otm, 0xAA, otm_size);
1523 SetLastError(0xdeadbeef);
1524 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1525 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1526 ok(ret == 1 /* Win9x */ ||
1527 ret == otm->otmSize /* XP*/,
1528 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1529 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1531 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1532 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1533 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1534 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1537 /* ask about truncated data */
1538 memset(otm, 0xAA, otm_size);
1539 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1540 SetLastError(0xdeadbeef);
1541 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1542 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1543 ok(ret == 1 /* Win9x */ ||
1544 ret == otm->otmSize /* XP*/,
1545 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1546 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1548 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1549 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1550 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1552 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1554 HeapFree(GetProcessHeap(), 0, otm);
1556 SelectObject(hdc, hfont_old);
1557 DeleteObject(hfont);
1562 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1566 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1567 areaWidth = clientArea->right - clientArea->left,
1569 BOOL lastExtent = FALSE;
1570 PSTR pFirstChar, pLastChar;
1576 int GetTextExtentExPointWWidth;
1579 GetTextMetricsA(hdc, &tm);
1580 y = clientArea->top;
1583 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1589 /* if not at the end of the string, ... */
1590 if (*str == '\0') break;
1591 /* ... add the next word to the current extent */
1592 while (*str != '\0' && *str++ != tm.tmBreakChar);
1594 SetTextJustification(hdc, 0, 0);
1595 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1596 } while ((int) size.cx < areaWidth);
1598 /* ignore trailing break chars */
1600 while (*(pLastChar - 1) == tm.tmBreakChar)
1606 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1608 SetTextJustification(hdc, 0, 0);
1609 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1611 /* do not justify the last extent */
1612 if (*str != '\0' && breakCount > 0)
1614 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1615 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1616 justifiedWidth = size.cx;
1618 else lastExtent = TRUE;
1620 /* catch errors and report them */
1621 if (!lastExtent && (justifiedWidth != areaWidth))
1623 memset(error[nErrors].extent, 0, 100);
1624 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1625 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1631 } while (*str && y < clientArea->bottom);
1633 for (e = 0; e < nErrors; e++)
1635 /* The width returned by GetTextExtentPoint32() is exactly the same
1636 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1637 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1638 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1639 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1643 static void test_SetTextJustification(void)
1650 static char testText[] =
1651 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1652 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1653 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1654 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1655 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1656 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1657 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1659 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1660 GetClientRect( hwnd, &clientArea );
1661 hdc = GetDC( hwnd );
1663 memset(&lf, 0, sizeof lf);
1664 lf.lfCharSet = ANSI_CHARSET;
1665 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1666 lf.lfWeight = FW_DONTCARE;
1668 lf.lfQuality = DEFAULT_QUALITY;
1669 lstrcpyA(lf.lfFaceName, "Times New Roman");
1670 hfont = create_font("Times New Roman", &lf);
1671 SelectObject(hdc, hfont);
1673 testJustification(hdc, testText, &clientArea);
1675 DeleteObject(hfont);
1676 ReleaseDC(hwnd, hdc);
1677 DestroyWindow(hwnd);
1680 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1684 HFONT hfont, hfont_old;
1691 assert(count <= 128);
1693 memset(&lf, 0, sizeof(lf));
1695 lf.lfCharSet = charset;
1697 lstrcpyA(lf.lfFaceName, "Arial");
1698 SetLastError(0xdeadbeef);
1699 hfont = CreateFontIndirectA(&lf);
1700 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1703 hfont_old = SelectObject(hdc, hfont);
1705 cs = GetTextCharsetInfo(hdc, &fs, 0);
1706 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1708 SetLastError(0xdeadbeef);
1709 ret = GetTextFaceA(hdc, sizeof(name), name);
1710 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1712 if (charset == SYMBOL_CHARSET)
1714 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1715 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1719 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1720 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1723 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1725 trace("Can't find codepage for charset %d\n", cs);
1729 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1731 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1733 skip("Font code page %d, looking for code page %d\n",
1734 pGdiGetCodePage(hdc), code_page);
1742 WCHAR unicode_buf[128];
1744 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1746 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1748 SetLastError(0xdeadbeef);
1749 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1750 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1751 count, ret, GetLastError());
1757 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1759 SetLastError(0xdeadbeef);
1760 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1761 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1762 count, ret, GetLastError());
1765 SelectObject(hdc, hfont_old);
1766 DeleteObject(hfont);
1773 static void test_font_charset(void)
1775 static struct charset_data
1779 WORD font_idxA[128], font_idxW[128];
1782 { ANSI_CHARSET, 1252 },
1783 { RUSSIAN_CHARSET, 1251 },
1784 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1788 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1790 win_skip("Skipping the font charset test on a Win9x platform\n");
1794 if (!is_font_installed("Arial"))
1796 skip("Arial is not installed\n");
1800 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1802 if (cd[i].charset == SYMBOL_CHARSET)
1804 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1806 skip("Symbol or Wingdings is not installed\n");
1810 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1811 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1812 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1815 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1818 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1819 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1822 skip("Symbol or Wingdings is not installed\n");
1825 static void test_GetFontUnicodeRanges(void)
1829 HFONT hfont, hfont_old;
1834 if (!pGetFontUnicodeRanges)
1836 win_skip("GetFontUnicodeRanges not available before W2K\n");
1840 memset(&lf, 0, sizeof(lf));
1841 lstrcpyA(lf.lfFaceName, "Arial");
1842 hfont = create_font("Arial", &lf);
1845 hfont_old = SelectObject(hdc, hfont);
1847 size = pGetFontUnicodeRanges(NULL, NULL);
1848 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1850 size = pGetFontUnicodeRanges(hdc, NULL);
1851 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1853 gs = HeapAlloc(GetProcessHeap(), 0, size);
1855 size = pGetFontUnicodeRanges(hdc, gs);
1856 ok(size, "GetFontUnicodeRanges failed\n");
1858 if (0) /* Disabled to limit console spam */
1859 for (i = 0; i < gs->cRanges; i++)
1860 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1861 trace("found %u ranges\n", gs->cRanges);
1863 HeapFree(GetProcessHeap(), 0, gs);
1865 SelectObject(hdc, hfont_old);
1866 DeleteObject(hfont);
1867 ReleaseDC(NULL, hdc);
1870 #define MAX_ENUM_FONTS 4096
1872 struct enum_font_data
1875 LOGFONT lf[MAX_ENUM_FONTS];
1878 struct enum_font_dataW
1881 LOGFONTW lf[MAX_ENUM_FONTS];
1884 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1886 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1888 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1890 if (type != TRUETYPE_FONTTYPE) return 1;
1891 if (0) /* Disabled to limit console spam */
1892 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1893 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1894 if (efd->total < MAX_ENUM_FONTS)
1895 efd->lf[efd->total++] = *lf;
1897 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1902 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1904 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1906 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1908 if (type != TRUETYPE_FONTTYPE) return 1;
1909 if (0) /* Disabled to limit console spam */
1910 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1911 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1912 if (efd->total < MAX_ENUM_FONTS)
1913 efd->lf[efd->total++] = *lf;
1915 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1920 static void get_charset_stats(struct enum_font_data *efd,
1921 int *ansi_charset, int *symbol_charset,
1922 int *russian_charset)
1927 *symbol_charset = 0;
1928 *russian_charset = 0;
1930 for (i = 0; i < efd->total; i++)
1932 switch (efd->lf[i].lfCharSet)
1937 case SYMBOL_CHARSET:
1938 (*symbol_charset)++;
1940 case RUSSIAN_CHARSET:
1941 (*russian_charset)++;
1947 static void get_charset_statsW(struct enum_font_dataW *efd,
1948 int *ansi_charset, int *symbol_charset,
1949 int *russian_charset)
1954 *symbol_charset = 0;
1955 *russian_charset = 0;
1957 for (i = 0; i < efd->total; i++)
1959 switch (efd->lf[i].lfCharSet)
1964 case SYMBOL_CHARSET:
1965 (*symbol_charset)++;
1967 case RUSSIAN_CHARSET:
1968 (*russian_charset)++;
1974 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1976 struct enum_font_data efd;
1977 struct enum_font_dataW efdw;
1980 int i, ret, ansi_charset, symbol_charset, russian_charset;
1982 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1984 if (*font_name && !is_truetype_font_installed(font_name))
1986 skip("%s is not installed\n", font_name);
1992 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1993 * while EnumFontFamiliesEx doesn't.
1995 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1998 * Use EnumFontFamiliesW since win98 crashes when the
1999 * second parameter is NULL using EnumFontFamilies
2002 SetLastError(0xdeadbeef);
2003 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2004 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2007 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2008 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2009 ansi_charset, symbol_charset, russian_charset);
2010 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2011 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2012 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2013 ok(russian_charset > 0 ||
2014 broken(russian_charset == 0), /* NT4 */
2015 "NULL family should enumerate RUSSIAN_CHARSET\n");
2019 SetLastError(0xdeadbeef);
2020 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2021 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2024 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2025 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2026 ansi_charset, symbol_charset, russian_charset);
2027 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2028 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2029 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2030 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2035 SetLastError(0xdeadbeef);
2036 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2037 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2038 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2039 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2040 ansi_charset, symbol_charset, russian_charset,
2041 *font_name ? font_name : "<empty>");
2043 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2045 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2046 for (i = 0; i < efd.total; i++)
2048 /* FIXME: remove completely once Wine is fixed */
2049 if (efd.lf[i].lfCharSet != font_charset)
2052 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2055 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2056 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2057 font_name, efd.lf[i].lfFaceName);
2060 memset(&lf, 0, sizeof(lf));
2061 lf.lfCharSet = ANSI_CHARSET;
2062 lstrcpy(lf.lfFaceName, font_name);
2064 SetLastError(0xdeadbeef);
2065 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2066 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2067 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2068 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2069 ansi_charset, symbol_charset, russian_charset,
2070 *font_name ? font_name : "<empty>");
2071 if (font_charset == SYMBOL_CHARSET)
2074 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2076 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2080 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2081 for (i = 0; i < efd.total; i++)
2083 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2085 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2086 font_name, efd.lf[i].lfFaceName);
2090 /* DEFAULT_CHARSET should enumerate all available charsets */
2091 memset(&lf, 0, sizeof(lf));
2092 lf.lfCharSet = DEFAULT_CHARSET;
2093 lstrcpy(lf.lfFaceName, font_name);
2095 SetLastError(0xdeadbeef);
2096 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2097 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2098 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2099 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2100 ansi_charset, symbol_charset, russian_charset,
2101 *font_name ? font_name : "<empty>");
2102 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2103 for (i = 0; i < efd.total; i++)
2106 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2107 font_name, efd.lf[i].lfFaceName);
2111 switch (font_charset)
2114 ok(ansi_charset > 0,
2115 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2117 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2118 ok(russian_charset > 0,
2119 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2121 case SYMBOL_CHARSET:
2123 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2125 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2126 ok(!russian_charset,
2127 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2129 case DEFAULT_CHARSET:
2130 ok(ansi_charset > 0,
2131 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2132 ok(symbol_charset > 0,
2133 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2134 ok(russian_charset > 0,
2135 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2141 ok(ansi_charset > 0,
2142 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2143 ok(symbol_charset > 0,
2144 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2145 ok(russian_charset > 0,
2146 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2149 memset(&lf, 0, sizeof(lf));
2150 lf.lfCharSet = SYMBOL_CHARSET;
2151 lstrcpy(lf.lfFaceName, font_name);
2153 SetLastError(0xdeadbeef);
2154 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2155 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2156 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2157 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2158 ansi_charset, symbol_charset, russian_charset,
2159 *font_name ? font_name : "<empty>");
2160 if (*font_name && font_charset == ANSI_CHARSET)
2161 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2164 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2165 for (i = 0; i < efd.total; i++)
2167 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2169 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2170 font_name, efd.lf[i].lfFaceName);
2174 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2175 ok(symbol_charset > 0,
2176 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2177 ok(!russian_charset,
2178 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2184 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2186 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2188 if (type != TRUETYPE_FONTTYPE) return 1;
2190 if (efd->total < MAX_ENUM_FONTS)
2191 efd->lf[efd->total++] = *lf;
2193 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2198 static void test_EnumFontFamiliesEx_default_charset(void)
2200 struct enum_font_data efd;
2201 LOGFONT gui_font, enum_font;
2205 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2206 ok(ret, "GetObject failed.\n");
2213 memset(&enum_font, 0, sizeof(enum_font));
2214 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2215 enum_font.lfCharSet = DEFAULT_CHARSET;
2216 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2219 if (efd.total == 0) {
2220 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2223 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2225 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2226 "(%s) got charset %d expected %d\n",
2227 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2232 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2234 HFONT hfont, hfont_prev;
2236 GLYPHMETRICS gm1, gm2;
2240 if(!pGetGlyphIndicesA)
2243 /* negative widths are handled just as positive ones */
2244 lf2.lfWidth = -lf->lfWidth;
2246 SetLastError(0xdeadbeef);
2247 hfont = CreateFontIndirectA(lf);
2248 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2249 check_font("original", lf, hfont);
2251 hfont_prev = SelectObject(hdc, hfont);
2253 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2254 if (ret == GDI_ERROR || idx == 0xffff)
2256 SelectObject(hdc, hfont_prev);
2257 DeleteObject(hfont);
2258 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2262 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2263 memset(&gm1, 0xab, sizeof(gm1));
2264 SetLastError(0xdeadbeef);
2265 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2266 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2268 SelectObject(hdc, hfont_prev);
2269 DeleteObject(hfont);
2271 SetLastError(0xdeadbeef);
2272 hfont = CreateFontIndirectA(&lf2);
2273 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2274 check_font("negative width", &lf2, hfont);
2276 hfont_prev = SelectObject(hdc, hfont);
2278 memset(&gm2, 0xbb, sizeof(gm2));
2279 SetLastError(0xdeadbeef);
2280 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2281 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2283 SelectObject(hdc, hfont_prev);
2284 DeleteObject(hfont);
2286 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2287 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2288 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2289 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2290 gm1.gmCellIncX == gm2.gmCellIncX &&
2291 gm1.gmCellIncY == gm2.gmCellIncY,
2292 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2293 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2294 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2295 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2296 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2299 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2300 #include "pshpack2.h"
2304 SHORT xAvgCharWidth;
2305 USHORT usWeightClass;
2306 USHORT usWidthClass;
2308 SHORT ySubscriptXSize;
2309 SHORT ySubscriptYSize;
2310 SHORT ySubscriptXOffset;
2311 SHORT ySubscriptYOffset;
2312 SHORT ySuperscriptXSize;
2313 SHORT ySuperscriptYSize;
2314 SHORT ySuperscriptXOffset;
2315 SHORT ySuperscriptYOffset;
2316 SHORT yStrikeoutSize;
2317 SHORT yStrikeoutPosition;
2320 ULONG ulUnicodeRange1;
2321 ULONG ulUnicodeRange2;
2322 ULONG ulUnicodeRange3;
2323 ULONG ulUnicodeRange4;
2326 USHORT usFirstCharIndex;
2327 USHORT usLastCharIndex;
2328 /* According to the Apple spec, original version didn't have the below fields,
2329 * version numbers were taken from the OpenType spec.
2331 /* version 0 (TrueType 1.5) */
2332 USHORT sTypoAscender;
2333 USHORT sTypoDescender;
2334 USHORT sTypoLineGap;
2336 USHORT usWinDescent;
2337 /* version 1 (TrueType 1.66) */
2338 ULONG ulCodePageRange1;
2339 ULONG ulCodePageRange2;
2340 /* version 2 (OpenType 1.2) */
2343 USHORT usDefaultChar;
2345 USHORT usMaxContext;
2347 #include "poppack.h"
2349 #ifdef WORDS_BIGENDIAN
2350 #define GET_BE_WORD(x) (x)
2351 #define GET_BE_DWORD(x) (x)
2353 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2354 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2357 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2358 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2359 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2360 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2361 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2362 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2375 } cmap_encoding_record;
2383 BYTE glyph_ids[256];
2393 USHORT search_range;
2394 USHORT entry_selector;
2397 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2400 USHORT start_count[seg_countx2 / 2];
2401 USHORT id_delta[seg_countx2 / 2];
2402 USHORT id_range_offset[seg_countx2 / 2];
2412 USHORT id_range_offset;
2413 } cmap_format_4_seg;
2415 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2417 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2418 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2419 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2420 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2421 os2->panose.bWeight, os2->panose.bProportion);
2424 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2427 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2431 for(i = 0; i < 256; i++)
2433 if(cmap->glyph_ids[i] == 0) continue;
2435 if(*first == 256) *first = i;
2437 if(*first == 256) return FALSE;
2441 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2443 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2444 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2445 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2446 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2447 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2450 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2453 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2454 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2455 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2459 for(i = 0; i < seg_count; i++)
2462 cmap_format_4_seg seg;
2464 get_seg4(cmap, i, &seg);
2465 for(code = seg.start_count; code <= seg.end_count; code++)
2467 if(seg.id_range_offset == 0)
2468 index = (seg.id_delta + code) & 0xffff;
2471 index = seg.id_range_offset / 2
2472 + code - seg.start_count
2475 /* some fonts have broken last segment */
2476 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2477 index = GET_BE_WORD(glyph_ids[index]);
2480 trace("segment %04x/%04x index %04x points to nowhere\n",
2481 seg.start_count, seg.end_count, index);
2484 if(index) index += seg.id_delta;
2486 if(*first == 0x10000)
2487 *last = *first = code;
2493 if(*first == 0x10000) return FALSE;
2497 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2500 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2502 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2504 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2505 return (BYTE *)header + GET_BE_DWORD(record->offset);
2518 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2521 cmap_header *header;
2526 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2527 ok(size != GDI_ERROR, "no cmap table found\n");
2528 if(size == GDI_ERROR) return FALSE;
2530 header = HeapAlloc(GetProcessHeap(), 0, size);
2531 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2532 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2533 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2535 cmap = get_cmap(header, 3, 1);
2537 *cmap_type = cmap_ms_unicode;
2540 cmap = get_cmap(header, 3, 0);
2541 if(cmap) *cmap_type = cmap_ms_symbol;
2545 *cmap_type = cmap_none;
2549 format = GET_BE_WORD(*(WORD *)cmap);
2553 r = get_first_last_from_cmap0(cmap, first, last);
2556 r = get_first_last_from_cmap4(cmap, first, last, size);
2559 trace("unhandled cmap format %d\n", format);
2564 HeapFree(GetProcessHeap(), 0, header);
2568 #define TT_PLATFORM_MICROSOFT 3
2569 #define TT_MS_ID_UNICODE_CS 1
2570 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2571 #define TT_NAME_ID_FULL_NAME 4
2573 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2575 struct sfnt_name_header
2578 USHORT number_of_record;
2579 USHORT storage_offset;
2591 LONG size, offset, length;
2597 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2598 ok(size != GDI_ERROR, "no name table found\n");
2599 if(size == GDI_ERROR) return FALSE;
2601 data = HeapAlloc(GetProcessHeap(), 0, size);
2602 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2603 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2605 header = (void *)data;
2606 header->format = GET_BE_WORD(header->format);
2607 header->number_of_record = GET_BE_WORD(header->number_of_record);
2608 header->storage_offset = GET_BE_WORD(header->storage_offset);
2609 if (header->format != 0)
2611 trace("got format %u\n", header->format);
2614 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2616 trace("number records out of range: %d\n", header->number_of_record);
2619 if (header->storage_offset >= size)
2621 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2625 entry = (void *)&header[1];
2626 for (i = 0; i < header->number_of_record; i++)
2628 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2629 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2630 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2631 GET_BE_WORD(entry[i].name_id) != name_id)
2636 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2637 length = GET_BE_WORD(entry[i].length);
2638 if (offset + length > size)
2640 trace("entry %d is out of range\n", i);
2643 if (length >= out_size)
2645 trace("buffer too small for entry %d\n", i);
2649 name = (WCHAR *)(data + offset);
2650 for (c = 0; c < length / 2; c++)
2651 out_buf[c] = GET_BE_WORD(name[c]);
2659 HeapFree(GetProcessHeap(), 0, data);
2663 static void test_text_metrics(const LOGFONTA *lf)
2666 HFONT hfont, hfont_old;
2670 const char *font_name = lf->lfFaceName;
2671 DWORD cmap_first = 0, cmap_last = 0;
2672 cmap_type cmap_type;
2673 BOOL sys_lang_non_english;
2675 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2678 SetLastError(0xdeadbeef);
2679 hfont = CreateFontIndirectA(lf);
2680 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2682 hfont_old = SelectObject(hdc, hfont);
2684 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2685 if (size == GDI_ERROR)
2687 trace("OS/2 chunk was not found\n");
2690 if (size > sizeof(tt_os2))
2692 trace("got too large OS/2 chunk of size %u\n", size);
2693 size = sizeof(tt_os2);
2696 memset(&tt_os2, 0, sizeof(tt_os2));
2697 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2698 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2700 SetLastError(0xdeadbeef);
2701 ret = GetTextMetricsA(hdc, &tmA);
2702 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2704 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2706 skip("Unable to retrieve first and last glyphs from cmap\n");
2710 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2711 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2712 UINT os2_first_char, os2_last_char, default_char, break_char;
2716 version = GET_BE_WORD(tt_os2.version);
2718 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2719 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2720 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2721 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2723 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2724 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2725 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2727 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2732 case 1257: /* Baltic */
2733 expect_last_W = 0xf8fd;
2736 expect_last_W = 0xf0ff;
2738 expect_break_W = 0x20;
2739 expect_default_W = expect_break_W - 1;
2740 expect_first_A = 0x1e;
2741 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2745 expect_first_W = cmap_first;
2746 expect_last_W = min(cmap_last, os2_last_char);
2747 if(os2_first_char <= 1)
2748 expect_break_W = os2_first_char + 2;
2749 else if(os2_first_char > 0xff)
2750 expect_break_W = 0x20;
2752 expect_break_W = os2_first_char;
2753 expect_default_W = expect_break_W - 1;
2754 expect_first_A = expect_default_W - 1;
2755 expect_last_A = min(expect_last_W, 0xff);
2757 expect_break_A = expect_break_W;
2758 expect_default_A = expect_default_W;
2760 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2761 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2762 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2763 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2764 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2766 ok(tmA.tmFirstChar == expect_first_A ||
2767 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2768 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2769 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2770 ok(tmA.tmLastChar == expect_last_A ||
2771 tmA.tmLastChar == 0xff /* win9x */,
2772 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2774 skip("tmLastChar is DBCS lead byte\n");
2775 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2776 font_name, tmA.tmBreakChar, expect_break_A);
2777 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2778 "A: tmDefaultChar for %s got %02x expected %02x\n",
2779 font_name, tmA.tmDefaultChar, expect_default_A);
2782 SetLastError(0xdeadbeef);
2783 ret = GetTextMetricsW(hdc, &tmW);
2784 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2785 "GetTextMetricsW error %u\n", GetLastError());
2788 /* Wine uses the os2 first char */
2789 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2790 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2791 font_name, tmW.tmFirstChar, expect_first_W);
2793 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2794 font_name, tmW.tmFirstChar, expect_first_W);
2796 /* Wine uses the os2 last char */
2797 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2798 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2799 font_name, tmW.tmLastChar, expect_last_W);
2801 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2802 font_name, tmW.tmLastChar, expect_last_W);
2803 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2804 font_name, tmW.tmBreakChar, expect_break_W);
2805 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2806 "W: tmDefaultChar for %s got %02x expected %02x\n",
2807 font_name, tmW.tmDefaultChar, expect_default_W);
2809 /* Test the aspect ratio while we have tmW */
2810 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2811 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2812 tmW.tmDigitizedAspectX, ret);
2813 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2814 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2815 tmW.tmDigitizedAspectX, ret);
2819 /* test FF_ values */
2820 switch(tt_os2.panose.bFamilyType)
2824 case PAN_FAMILY_TEXT_DISPLAY:
2825 case PAN_FAMILY_PICTORIAL:
2827 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2828 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2830 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2833 switch(tt_os2.panose.bSerifStyle)
2838 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2841 case PAN_SERIF_COVE:
2842 case PAN_SERIF_OBTUSE_COVE:
2843 case PAN_SERIF_SQUARE_COVE:
2844 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2845 case PAN_SERIF_SQUARE:
2846 case PAN_SERIF_THIN:
2847 case PAN_SERIF_BONE:
2848 case PAN_SERIF_EXAGGERATED:
2849 case PAN_SERIF_TRIANGLE:
2850 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2853 case PAN_SERIF_NORMAL_SANS:
2854 case PAN_SERIF_OBTUSE_SANS:
2855 case PAN_SERIF_PERP_SANS:
2856 case PAN_SERIF_FLARED:
2857 case PAN_SERIF_ROUNDED:
2858 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2863 case PAN_FAMILY_SCRIPT:
2864 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2867 case PAN_FAMILY_DECORATIVE:
2868 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2872 test_negative_width(hdc, lf);
2875 SelectObject(hdc, hfont_old);
2876 DeleteObject(hfont);
2881 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2883 INT *enumed = (INT *)lParam;
2885 if (type == TRUETYPE_FONTTYPE)
2888 test_text_metrics(lf);
2893 static void test_GetTextMetrics(void)
2899 /* Report only once */
2900 if(!pGetGlyphIndicesA)
2901 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2905 memset(&lf, 0, sizeof(lf));
2906 lf.lfCharSet = DEFAULT_CHARSET;
2908 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2909 trace("Tested metrics of %d truetype fonts\n", enumed);
2914 static void test_nonexistent_font(void)
2922 { "Times New Roman Baltic", 186 },
2923 { "Times New Roman CE", 238 },
2924 { "Times New Roman CYR", 204 },
2925 { "Times New Roman Greek", 161 },
2926 { "Times New Roman TUR", 162 }
2932 INT cs, expected_cs, i;
2933 char buf[LF_FACESIZE];
2935 if (!is_truetype_font_installed("Arial") ||
2936 !is_truetype_font_installed("Times New Roman"))
2938 skip("Arial or Times New Roman not installed\n");
2942 expected_cs = GetACP();
2943 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2945 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2948 expected_cs = csi.ciCharset;
2949 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2953 memset(&lf, 0, sizeof(lf));
2955 lf.lfWeight = FW_REGULAR;
2956 lf.lfCharSet = ANSI_CHARSET;
2957 lf.lfPitchAndFamily = FF_SWISS;
2958 strcpy(lf.lfFaceName, "Nonexistent font");
2959 hfont = CreateFontIndirectA(&lf);
2960 hfont = SelectObject(hdc, hfont);
2961 GetTextFaceA(hdc, sizeof(buf), buf);
2962 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2963 cs = GetTextCharset(hdc);
2964 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2965 DeleteObject(SelectObject(hdc, hfont));
2967 memset(&lf, 0, sizeof(lf));
2969 lf.lfWeight = FW_DONTCARE;
2970 strcpy(lf.lfFaceName, "Nonexistent font");
2971 hfont = CreateFontIndirectA(&lf);
2972 hfont = SelectObject(hdc, hfont);
2973 GetTextFaceA(hdc, sizeof(buf), buf);
2974 todo_wine /* Wine uses Arial for all substitutions */
2975 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2976 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2977 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2979 cs = GetTextCharset(hdc);
2980 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2981 DeleteObject(SelectObject(hdc, hfont));
2983 memset(&lf, 0, sizeof(lf));
2985 lf.lfWeight = FW_REGULAR;
2986 strcpy(lf.lfFaceName, "Nonexistent font");
2987 hfont = CreateFontIndirectA(&lf);
2988 hfont = SelectObject(hdc, hfont);
2989 GetTextFaceA(hdc, sizeof(buf), buf);
2990 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2991 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2992 cs = GetTextCharset(hdc);
2993 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2994 DeleteObject(SelectObject(hdc, hfont));
2996 memset(&lf, 0, sizeof(lf));
2998 lf.lfWeight = FW_DONTCARE;
2999 strcpy(lf.lfFaceName, "Times New Roman");
3000 hfont = CreateFontIndirectA(&lf);
3001 hfont = SelectObject(hdc, hfont);
3002 GetTextFaceA(hdc, sizeof(buf), buf);
3003 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3004 cs = GetTextCharset(hdc);
3005 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3006 DeleteObject(SelectObject(hdc, hfont));
3008 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3010 memset(&lf, 0, sizeof(lf));
3012 lf.lfWeight = FW_REGULAR;
3013 strcpy(lf.lfFaceName, font_subst[i].name);
3014 hfont = CreateFontIndirectA(&lf);
3015 hfont = SelectObject(hdc, hfont);
3016 cs = GetTextCharset(hdc);
3017 if (font_subst[i].charset == expected_cs)
3019 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3020 GetTextFaceA(hdc, sizeof(buf), buf);
3021 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3025 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3026 GetTextFaceA(hdc, sizeof(buf), buf);
3027 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3028 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3030 DeleteObject(SelectObject(hdc, hfont));
3032 memset(&lf, 0, sizeof(lf));
3034 lf.lfWeight = FW_DONTCARE;
3035 strcpy(lf.lfFaceName, font_subst[i].name);
3036 hfont = CreateFontIndirectA(&lf);
3037 hfont = SelectObject(hdc, hfont);
3038 GetTextFaceA(hdc, sizeof(buf), buf);
3039 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3040 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3041 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3042 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3043 "got %s for font %s\n", buf, font_subst[i].name);
3044 cs = GetTextCharset(hdc);
3045 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3046 DeleteObject(SelectObject(hdc, hfont));
3052 static void test_GdiRealizationInfo(void)
3057 HFONT hfont, hfont_old;
3060 if(!pGdiRealizationInfo)
3062 win_skip("GdiRealizationInfo not available\n");
3068 memset(info, 0xcc, sizeof(info));
3069 r = pGdiRealizationInfo(hdc, info);
3070 ok(r != 0, "ret 0\n");
3071 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3072 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3074 if (!is_truetype_font_installed("Arial"))
3076 skip("skipping GdiRealizationInfo with truetype font\n");
3080 memset(&lf, 0, sizeof(lf));
3081 strcpy(lf.lfFaceName, "Arial");
3083 lf.lfWeight = FW_NORMAL;
3084 hfont = CreateFontIndirectA(&lf);
3085 hfont_old = SelectObject(hdc, hfont);
3087 memset(info, 0xcc, sizeof(info));
3088 r = pGdiRealizationInfo(hdc, info);
3089 ok(r != 0, "ret 0\n");
3090 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3091 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3093 DeleteObject(SelectObject(hdc, hfont_old));
3099 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3100 the nul in the count of characters copied when the face name buffer is not
3101 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3102 always includes it. */
3103 static void test_GetTextFace(void)
3105 static const char faceA[] = "Tahoma";
3106 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3109 char bufA[LF_FACESIZE];
3110 WCHAR bufW[LF_FACESIZE];
3115 if(!is_font_installed("Tahoma"))
3117 skip("Tahoma is not installed so skipping this test\n");
3122 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3123 f = CreateFontIndirectA(&fA);
3124 ok(f != NULL, "CreateFontIndirectA failed\n");
3127 g = SelectObject(dc, f);
3128 n = GetTextFaceA(dc, sizeof bufA, bufA);
3129 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3130 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3132 /* Play with the count arg. */
3134 n = GetTextFaceA(dc, 0, bufA);
3135 ok(n == 0, "GetTextFaceA returned %d\n", n);
3136 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3139 n = GetTextFaceA(dc, 1, bufA);
3140 ok(n == 0, "GetTextFaceA returned %d\n", n);
3141 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3143 bufA[0] = 'x'; bufA[1] = 'y';
3144 n = GetTextFaceA(dc, 2, bufA);
3145 ok(n == 1, "GetTextFaceA returned %d\n", n);
3146 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3148 n = GetTextFaceA(dc, 0, NULL);
3149 ok(n == sizeof faceA ||
3150 broken(n == 0), /* win98, winMe */
3151 "GetTextFaceA returned %d\n", n);
3153 DeleteObject(SelectObject(dc, g));
3154 ReleaseDC(NULL, dc);
3157 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3158 SetLastError(0xdeadbeef);
3159 f = CreateFontIndirectW(&fW);
3160 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3162 win_skip("CreateFontIndirectW is not implemented\n");
3165 ok(f != NULL, "CreateFontIndirectW failed\n");
3168 g = SelectObject(dc, f);
3169 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3170 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3171 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3173 /* Play with the count arg. */
3175 n = GetTextFaceW(dc, 0, bufW);
3176 ok(n == 0, "GetTextFaceW returned %d\n", n);
3177 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3180 n = GetTextFaceW(dc, 1, bufW);
3181 ok(n == 1, "GetTextFaceW returned %d\n", n);
3182 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3184 bufW[0] = 'x'; bufW[1] = 'y';
3185 n = GetTextFaceW(dc, 2, bufW);
3186 ok(n == 2, "GetTextFaceW returned %d\n", n);
3187 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3189 n = GetTextFaceW(dc, 0, NULL);
3190 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3192 DeleteObject(SelectObject(dc, g));
3193 ReleaseDC(NULL, dc);
3196 static void test_orientation(void)
3198 static const char test_str[11] = "Test String";
3201 HFONT hfont, old_hfont;
3204 if (!is_truetype_font_installed("Arial"))
3206 skip("Arial is not installed\n");
3210 hdc = CreateCompatibleDC(0);
3211 memset(&lf, 0, sizeof(lf));
3212 lstrcpyA(lf.lfFaceName, "Arial");
3214 lf.lfOrientation = lf.lfEscapement = 900;
3215 hfont = create_font("orientation", &lf);
3216 old_hfont = SelectObject(hdc, hfont);
3217 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3218 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3219 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3220 SelectObject(hdc, old_hfont);
3221 DeleteObject(hfont);
3225 static void test_oemcharset(void)
3229 HFONT hfont, old_hfont;
3232 hdc = CreateCompatibleDC(0);
3233 ZeroMemory(&lf, sizeof(lf));
3235 lf.lfCharSet = OEM_CHARSET;
3236 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3237 lstrcpyA(lf.lfFaceName, "Terminal");
3238 hfont = CreateFontIndirectA(&lf);
3239 old_hfont = SelectObject(hdc, hfont);
3240 charset = GetTextCharset(hdc);
3242 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3243 hfont = SelectObject(hdc, old_hfont);
3244 GetObjectA(hfont, sizeof(clf), &clf);
3245 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3246 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3247 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3248 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3249 DeleteObject(hfont);
3253 static void test_GetGlyphOutline(void)
3256 GLYPHMETRICS gm, gm2;
3258 HFONT hfont, old_hfont;
3267 {ANSI_CHARSET, 0x30, 0x30},
3268 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3269 {HANGEUL_CHARSET, 0x8141, 0xac02},
3270 {JOHAB_CHARSET, 0x8446, 0x3135},
3271 {GB2312_CHARSET, 0x8141, 0x4e04},
3272 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3276 if (!is_truetype_font_installed("Tahoma"))
3278 skip("Tahoma is not installed\n");
3282 hdc = CreateCompatibleDC(0);
3283 memset(&lf, 0, sizeof(lf));
3285 lstrcpyA(lf.lfFaceName, "Tahoma");
3286 SetLastError(0xdeadbeef);
3287 hfont = CreateFontIndirectA(&lf);
3288 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3289 old_hfont = SelectObject(hdc, hfont);
3291 memset(&gm, 0, sizeof(gm));
3292 SetLastError(0xdeadbeef);
3293 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3294 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3296 memset(&gm, 0, sizeof(gm));
3297 SetLastError(0xdeadbeef);
3298 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3299 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3300 ok(GetLastError() == 0xdeadbeef ||
3301 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3302 "expected 0xdeadbeef, got %u\n", GetLastError());
3304 memset(&gm, 0, sizeof(gm));
3305 SetLastError(0xdeadbeef);
3306 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3307 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3308 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3310 memset(&gm, 0, sizeof(gm));
3311 SetLastError(0xdeadbeef);
3312 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3313 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3315 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3316 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3319 /* test for needed buffer size request on space char */
3320 memset(&gm, 0, sizeof(gm));
3321 SetLastError(0xdeadbeef);
3322 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3323 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3324 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3326 /* requesting buffer size for space char + error */
3327 memset(&gm, 0, sizeof(gm));
3328 SetLastError(0xdeadbeef);
3329 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3330 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3332 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3333 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3336 SelectObject(hdc, old_hfont);
3337 DeleteObject(hfont);
3339 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3341 lf.lfFaceName[0] = '\0';
3342 lf.lfCharSet = c[i].cs;
3343 lf.lfPitchAndFamily = 0;
3344 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3346 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3350 old_hfont = SelectObject(hdc, hfont);
3352 /* expected to ignore superfluous bytes (sigle-byte character) */
3353 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3354 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3355 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3357 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3358 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3359 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3361 /* expected to ignore superfluous bytes (double-byte character) */
3362 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3363 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3364 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3365 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3367 /* expected to match wide-char version results */
3368 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3369 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3371 hfont = SelectObject(hdc, old_hfont);
3372 DeleteObject(hfont);
3378 /* bug #9995: there is a limit to the character width that can be specified */
3379 static void test_GetTextMetrics2(const char *fontname, int font_height)
3385 int ave_width, height, width, ratio, scale;
3387 if (!is_truetype_font_installed( fontname)) {
3388 skip("%s is not installed\n", fontname);
3391 hdc = CreateCompatibleDC(0);
3392 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3393 /* select width = 0 */
3394 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3395 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3396 DEFAULT_QUALITY, VARIABLE_PITCH,
3398 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3399 of = SelectObject( hdc, hf);
3400 ret = GetTextMetricsA( hdc, &tm);
3401 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3402 height = tm.tmHeight;
3403 ave_width = tm.tmAveCharWidth;
3404 SelectObject( hdc, of);
3407 trace("height %d, ave width %d\n", height, ave_width);
3409 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3411 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3412 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3413 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3414 ok(hf != 0, "CreateFont failed\n");
3415 of = SelectObject(hdc, hf);
3416 ret = GetTextMetrics(hdc, &tm);
3417 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3418 SelectObject(hdc, of);
3421 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3427 ratio = width / height;
3428 scale = width / ave_width;
3430 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3431 width, height, ratio, width, ave_width, scale);
3433 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3436 static void test_CreateFontIndirect(void)
3438 LOGFONTA lf, getobj_lf;
3441 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3443 memset(&lf, 0, sizeof(lf));
3444 lf.lfCharSet = ANSI_CHARSET;
3445 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3448 lf.lfQuality = DEFAULT_QUALITY;
3449 lf.lfItalic = FALSE;
3450 lf.lfWeight = FW_DONTCARE;
3452 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3454 lstrcpyA(lf.lfFaceName, TestName[i]);
3455 hfont = CreateFontIndirectA(&lf);
3456 ok(hfont != 0, "CreateFontIndirectA failed\n");
3457 SetLastError(0xdeadbeef);
3458 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3459 ok(ret, "GetObject failed: %d\n", GetLastError());
3460 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3461 ok(lf.lfWeight == getobj_lf.lfWeight ||
3462 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3463 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3464 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3465 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3466 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3467 DeleteObject(hfont);
3471 static void test_CreateFontIndirectEx(void)
3473 ENUMLOGFONTEXDVA lfex;
3476 if (!pCreateFontIndirectExA)
3478 win_skip("CreateFontIndirectExA is not available\n");
3482 if (!is_truetype_font_installed("Arial"))
3484 skip("Arial is not installed\n");
3488 SetLastError(0xdeadbeef);
3489 hfont = pCreateFontIndirectExA(NULL);
3490 ok(hfont == NULL, "got %p\n", hfont);
3491 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3493 memset(&lfex, 0, sizeof(lfex));
3494 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3495 hfont = pCreateFontIndirectExA(&lfex);
3496 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3498 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3499 DeleteObject(hfont);
3502 static void free_font(void *font)
3504 UnmapViewOfFile(font);
3507 static void *load_font(const char *font_name, DWORD *font_size)
3509 char file_name[MAX_PATH];
3510 HANDLE file, mapping;
3513 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3514 strcat(file_name, "\\fonts\\");
3515 strcat(file_name, font_name);
3517 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3518 if (file == INVALID_HANDLE_VALUE) return NULL;
3520 *font_size = GetFileSize(file, NULL);
3522 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3529 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3532 CloseHandle(mapping);
3536 static void test_AddFontMemResource(void)
3539 DWORD font_size, num_fonts;
3543 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3545 win_skip("AddFontMemResourceEx is not available on this platform\n");
3549 font = load_font("sserife.fon", &font_size);
3552 skip("Unable to locate and load font sserife.fon\n");
3556 SetLastError(0xdeadbeef);
3557 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3558 ok(!ret, "AddFontMemResourceEx should fail\n");
3559 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3560 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3563 SetLastError(0xdeadbeef);
3564 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3565 ok(!ret, "AddFontMemResourceEx should fail\n");
3566 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3567 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3570 SetLastError(0xdeadbeef);
3571 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3572 ok(!ret, "AddFontMemResourceEx should fail\n");
3573 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3574 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3577 SetLastError(0xdeadbeef);
3578 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3579 ok(!ret, "AddFontMemResourceEx should fail\n");
3580 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3581 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3584 SetLastError(0xdeadbeef);
3585 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3586 ok(!ret, "AddFontMemResourceEx should fail\n");
3587 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3588 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3591 SetLastError(0xdeadbeef);
3592 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3593 ok(!ret, "AddFontMemResourceEx should fail\n");
3594 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3595 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3598 num_fonts = 0xdeadbeef;
3599 SetLastError(0xdeadbeef);
3600 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3601 ok(!ret, "AddFontMemResourceEx should fail\n");
3602 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3603 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3605 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3607 if (0) /* hangs under windows 2000 */
3609 num_fonts = 0xdeadbeef;
3610 SetLastError(0xdeadbeef);
3611 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3612 ok(!ret, "AddFontMemResourceEx should fail\n");
3613 ok(GetLastError() == 0xdeadbeef,
3614 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3616 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3619 num_fonts = 0xdeadbeef;
3620 SetLastError(0xdeadbeef);
3621 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3622 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3623 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3624 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3628 SetLastError(0xdeadbeef);
3629 bRet = pRemoveFontMemResourceEx(ret);
3630 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3632 /* test invalid pointer to number of loaded fonts */
3633 font = load_font("sserife.fon", &font_size);
3634 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3636 SetLastError(0xdeadbeef);
3637 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3638 ok(!ret, "AddFontMemResourceEx should fail\n");
3639 ok(GetLastError() == 0xdeadbeef,
3640 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3643 SetLastError(0xdeadbeef);
3644 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3645 ok(!ret, "AddFontMemResourceEx should fail\n");
3646 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3647 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3653 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3657 if (type != TRUETYPE_FONTTYPE) return 1;
3659 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3661 lf = (LOGFONT *)lparam;
3666 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3671 if (type != TRUETYPE_FONTTYPE) return 1;
3673 lf = (LOGFONT *)lparam;
3674 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3677 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3684 static void test_EnumFonts(void)
3690 if (!is_truetype_font_installed("Arial"))
3692 skip("Arial is not installed\n");
3696 /* Windows uses localized font face names, so Arial Bold won't be found */
3697 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3699 skip("User locale is not English, skipping the test\n");
3703 hdc = CreateCompatibleDC(0);
3705 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3706 ok(!ret, "font Arial is not enumerated\n");
3707 ret = strcmp(lf.lfFaceName, "Arial");
3708 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3709 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3711 lstrcpy(lf.lfFaceName, "Arial");
3712 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3713 ok(!ret, "font Arial is not enumerated\n");
3714 ret = strcmp(lf.lfFaceName, "Arial");
3715 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3716 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3718 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3719 ok(!ret, "font Arial Bold is not enumerated\n");
3720 ret = strcmp(lf.lfFaceName, "Arial");
3721 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3722 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3724 lstrcpy(lf.lfFaceName, "Arial Bold");
3725 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3726 ok(ret, "font Arial Bold should not be enumerated\n");
3728 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3729 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3730 ret = strcmp(lf.lfFaceName, "Arial");
3731 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3732 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3734 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3735 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3736 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3738 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3739 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3741 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3742 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3743 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3748 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3750 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3751 const char *fullname = (const char *)lParam;
3753 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3758 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3763 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3770 static void test_fullname(void)
3772 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3773 char buf[LF_FULLFACESIZE];
3779 hdc = CreateCompatibleDC(0);
3780 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3782 memset(&lf, 0, sizeof(lf));
3783 lf.lfCharSet = ANSI_CHARSET;
3784 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3787 lf.lfQuality = DEFAULT_QUALITY;
3788 lf.lfItalic = FALSE;
3789 lf.lfWeight = FW_DONTCARE;
3791 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3793 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3795 skip("%s is not installed\n", TestName[i]);
3799 lstrcpyA(lf.lfFaceName, TestName[i]);
3800 hfont = CreateFontIndirectA(&lf);
3801 ok(hfont != 0, "CreateFontIndirectA failed\n");
3803 of = SelectObject(hdc, hfont);
3805 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3806 "face full name could not be read\n");
3807 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3808 SelectObject(hdc, of);
3809 DeleteObject(hfont);
3814 static BOOL write_ttf_file(char *tmp_name)
3816 char tmp_path[MAX_PATH];
3823 SetLastError(0xdeadbeef);
3824 rsrc = FindResource(GetModuleHandle(0), "wine_test.ttf", RT_RCDATA);
3825 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
3826 if (!rsrc) return FALSE;
3827 SetLastError(0xdeadbeef);
3828 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
3829 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
3830 if (!rsrc_data) return FALSE;
3831 SetLastError(0xdeadbeef);
3832 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
3833 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
3834 if (!rsrc_size) return FALSE;
3836 SetLastError(0xdeadbeef);
3837 ret = GetTempPath(MAX_PATH, tmp_path);
3838 ok(ret, "GetTempPath() error %d\n", GetLastError());
3839 SetLastError(0xdeadbeef);
3840 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
3841 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3843 SetLastError(0xdeadbeef);
3844 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
3845 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
3846 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
3848 SetLastError(0xdeadbeef);
3849 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
3850 ok(ret, "WriteFile() error %d\n", GetLastError());
3856 static void test_CreateScalableFontResource(void)
3858 char ttf_name[MAX_PATH];
3859 char tmp_path[MAX_PATH];
3860 char fot_name[MAX_PATH];
3864 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
3866 win_skip("AddFontResourceExA is not available on this platform\n");
3870 if (!write_ttf_file(ttf_name))
3872 skip("Failed to create ttf file for testing\n");
3876 trace("created %s\n", ttf_name);
3878 ret = is_truetype_font_installed("wine_test");
3879 ok(!ret, "font wine_test should not be enumerated\n");
3881 ret = GetTempPath(MAX_PATH, tmp_path);
3882 ok(ret, "GetTempPath() error %d\n", GetLastError());
3883 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
3884 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3886 ret = GetFileAttributes(fot_name);
3887 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
3889 SetLastError(0xdeadbeef);
3890 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3891 ok(!ret, "CreateScalableFontResource() should fail\n");
3892 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3894 SetLastError(0xdeadbeef);
3895 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
3896 ok(!ret, "CreateScalableFontResource() should fail\n");
3897 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3899 file_part = strrchr(ttf_name, '\\');
3900 SetLastError(0xdeadbeef);
3901 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
3902 ok(!ret, "CreateScalableFontResource() should fail\n");
3903 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3905 SetLastError(0xdeadbeef);
3906 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
3907 ok(!ret, "CreateScalableFontResource() should fail\n");
3909 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3911 SetLastError(0xdeadbeef);
3912 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
3913 ok(!ret, "CreateScalableFontResource() should fail\n");
3915 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3917 ret = DeleteFile(fot_name);
3918 ok(ret, "DeleteFile() error %d\n", GetLastError());
3920 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3922 ok(!ret, "RemoveFontResourceEx() should fail\n");
3924 /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3927 /* test public font resource */
3928 SetLastError(0xdeadbeef);
3929 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3930 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3932 ret = is_truetype_font_installed("wine_test");
3933 ok(!ret, "font wine_test should not be enumerated\n");
3935 SetLastError(0xdeadbeef);
3936 ret = pAddFontResourceExA(fot_name, 0, 0);
3937 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3939 ret = is_truetype_font_installed("wine_test");
3940 ok(ret, "font wine_test should be enumerated\n");
3942 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3943 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
3945 SetLastError(0xdeadbeef);
3946 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3948 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3950 ret = is_truetype_font_installed("wine_test");
3952 ok(!ret, "font wine_test should not be enumerated\n");
3954 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
3957 /* remove once RemoveFontResource is implemented */
3958 DeleteFile(fot_name);
3959 DeleteFile(ttf_name);
3963 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3964 ok(!ret, "RemoveFontResourceEx() should fail\n");
3966 DeleteFile(fot_name);
3968 /* test hidden font resource */
3969 SetLastError(0xdeadbeef);
3970 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
3971 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3973 ret = is_truetype_font_installed("wine_test");
3974 ok(!ret, "font wine_test should not be enumerated\n");
3976 SetLastError(0xdeadbeef);
3977 ret = pAddFontResourceExA(fot_name, 0, 0);
3978 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3980 ret = is_truetype_font_installed("wine_test");
3981 ok(!ret, "font wine_test should not be enumerated\n");
3983 /* XP allows removing a private font added with 0 flags */
3984 SetLastError(0xdeadbeef);
3985 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3986 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3988 ret = is_truetype_font_installed("wine_test");
3989 ok(!ret, "font wine_test should not be enumerated\n");
3991 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3992 ok(!ret, "RemoveFontResourceEx() should fail\n");
3994 DeleteFile(fot_name);
3995 DeleteFile(ttf_name);
4004 test_outline_font();
4005 test_bitmap_font_metrics();
4006 test_GdiGetCharDimensions();
4007 test_GetCharABCWidths();
4008 test_text_extents();
4009 test_GetGlyphIndices();
4010 test_GetKerningPairs();
4011 test_GetOutlineTextMetrics();
4012 test_SetTextJustification();
4013 test_font_charset();
4014 test_GetFontUnicodeRanges();
4015 test_nonexistent_font();
4017 test_height_selection();
4018 test_AddFontMemResource();
4021 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4022 * I'd like to avoid them in this test.
4024 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4025 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4026 if (is_truetype_font_installed("Arial Black") &&
4027 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4029 test_EnumFontFamilies("", ANSI_CHARSET);
4030 test_EnumFontFamilies("", SYMBOL_CHARSET);
4031 test_EnumFontFamilies("", DEFAULT_CHARSET);
4034 skip("Arial Black or Symbol/Wingdings is not installed\n");
4035 test_EnumFontFamiliesEx_default_charset();
4036 test_GetTextMetrics();
4037 test_GdiRealizationInfo();
4039 test_GetGlyphOutline();
4040 test_GetTextMetrics2("Tahoma", -11);
4041 test_GetTextMetrics2("Tahoma", -55);
4042 test_GetTextMetrics2("Tahoma", -110);
4043 test_GetTextMetrics2("Arial", -11);
4044 test_GetTextMetrics2("Arial", -55);
4045 test_GetTextMetrics2("Arial", -110);
4046 test_CreateFontIndirect();
4047 test_CreateFontIndirectEx();
4051 /* CreateScalableFontResource should be last test until RemoveFontResource
4052 * is properly implemented.
4054 test_CreateScalableFontResource();