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;
1058 memset(&lf, 0, sizeof(lf));
1059 strcpy(lf.lfFaceName, "Arial");
1062 hfont = CreateFontIndirectA(&lf);
1064 hfont = SelectObject(hdc, hfont);
1065 GetTextMetricsA(hdc, &tm);
1066 GetTextExtentPointA(hdc, "o", 1, &sz);
1067 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1069 SetLastError(0xdeadbeef);
1070 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1071 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1073 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1074 hfont = SelectObject(hdc, hfont);
1075 DeleteObject(hfont);
1081 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1082 extents[0] = 1; /* So that the increasing sequence test will fail
1083 if the extents array is untouched. */
1084 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1085 GetTextExtentPointW(hdc, wt, len, &sz2);
1086 ok(sz1.cy == sz2.cy,
1087 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1088 /* Because of the '\n' in the string GetTextExtentExPoint and
1089 GetTextExtentPoint return different widths under Win2k, but
1090 under WinXP they return the same width. So we don't test that
1093 for (i = 1; i < len; ++i)
1094 ok(extents[i-1] <= extents[i],
1095 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1097 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1098 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1099 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1100 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1101 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1102 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1103 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1104 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1105 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1106 ok(extents[0] == extents[2] && extents[1] == extents[3],
1107 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1108 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1109 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1110 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1111 HeapFree(GetProcessHeap(), 0, extents);
1113 hfont = SelectObject(hdc, hfont);
1114 DeleteObject(hfont);
1115 ReleaseDC(NULL, hdc);
1118 static void test_GetGlyphIndices(void)
1125 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1126 WORD glyphs[(sizeof(testtext)/2)-1];
1130 if (!pGetGlyphIndicesW) {
1131 win_skip("GetGlyphIndicesW not available on platform\n");
1137 memset(&lf, 0, sizeof(lf));
1138 strcpy(lf.lfFaceName, "System");
1140 lf.lfCharSet = ANSI_CHARSET;
1142 hfont = CreateFontIndirectA(&lf);
1143 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1144 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1145 if (textm.tmCharSet == ANSI_CHARSET)
1147 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1148 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1149 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1150 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1152 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1153 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1154 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1155 textm.tmDefaultChar, glyphs[4]);
1158 /* FIXME: Write tests for non-ANSI charsets. */
1159 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1161 if(!is_font_installed("Tahoma"))
1163 skip("Tahoma is not installed so skipping this test\n");
1166 memset(&lf, 0, sizeof(lf));
1167 strcpy(lf.lfFaceName, "Tahoma");
1170 hfont = CreateFontIndirectA(&lf);
1171 hOldFont = SelectObject(hdc, hfont);
1172 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1173 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1174 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1175 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1176 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1178 testtext[0] = textm.tmDefaultChar;
1179 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1180 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1181 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1182 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1183 DeleteObject(SelectObject(hdc, hOldFont));
1186 static void test_GetKerningPairs(void)
1188 static const struct kerning_data
1190 const char face_name[LF_FACESIZE];
1192 /* some interesting fields from OUTLINETEXTMETRIC */
1193 LONG tmHeight, tmAscent, tmDescent;
1198 UINT otmsCapEmHeight;
1203 UINT otmusMinimumPPEM;
1204 /* small subset of kerning pairs to test */
1205 DWORD total_kern_pairs;
1206 const KERNINGPAIR kern_pair[26];
1209 {"Arial", 12, 12, 9, 3,
1210 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1213 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1214 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1215 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1216 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1217 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1218 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1219 {933,970,+1},{933,972,-1}
1222 {"Arial", -34, 39, 32, 7,
1223 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1226 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1227 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1228 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1229 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1230 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1231 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1232 {933,970,+2},{933,972,-3}
1235 { "Arial", 120, 120, 97, 23,
1236 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1239 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1240 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1241 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1242 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1243 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1244 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1245 {933,970,+6},{933,972,-10}
1248 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1249 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1250 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1253 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1254 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1255 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1256 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1257 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1258 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1259 {933,970,+54},{933,972,-83}
1265 HFONT hfont, hfont_old;
1266 KERNINGPAIR *kern_pair;
1268 DWORD total_kern_pairs, ret, i, n, matches;
1272 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1273 * which may render this test unusable, so we're trying to avoid that.
1275 SetLastError(0xdeadbeef);
1276 GetKerningPairsW(hdc, 0, NULL);
1277 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1279 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1284 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1286 OUTLINETEXTMETRICW otm;
1289 if (!is_font_installed(kd[i].face_name))
1291 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1295 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1297 memset(&lf, 0, sizeof(lf));
1298 strcpy(lf.lfFaceName, kd[i].face_name);
1299 lf.lfHeight = kd[i].height;
1300 hfont = CreateFontIndirect(&lf);
1303 hfont_old = SelectObject(hdc, hfont);
1305 SetLastError(0xdeadbeef);
1306 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1307 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1308 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1310 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1311 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1312 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1313 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1314 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1315 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1317 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1318 kd[i].otmEMSquare, otm.otmEMSquare);
1319 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1320 kd[i].otmAscent, otm.otmAscent);
1321 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1322 kd[i].otmDescent, otm.otmDescent);
1323 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1324 kd[i].otmLineGap, otm.otmLineGap);
1325 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1326 kd[i].otmMacDescent, otm.otmMacDescent);
1327 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1328 kd[i].otmMacAscent, otm.otmMacAscent);
1330 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1331 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1332 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1333 kd[i].otmsXHeight, otm.otmsXHeight);
1334 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1335 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1336 kd[i].otmMacLineGap, otm.otmMacLineGap);
1337 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1338 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1341 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1342 trace("total_kern_pairs %u\n", total_kern_pairs);
1343 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1345 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1346 SetLastError(0xdeadbeef);
1347 ret = GetKerningPairsW(hdc, 0, kern_pair);
1348 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1349 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1350 ok(ret == 0, "got %lu, expected 0\n", ret);
1353 ret = GetKerningPairsW(hdc, 100, NULL);
1354 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1356 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1357 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1359 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1360 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1364 for (n = 0; n < ret; n++)
1368 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1369 trace("{'%c','%c',%d},\n",
1370 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1372 for (j = 0; j < kd[i].total_kern_pairs; j++)
1374 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1375 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1377 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1378 "pair %d:%d got %d, expected %d\n",
1379 kern_pair[n].wFirst, kern_pair[n].wSecond,
1380 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1386 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1387 matches, kd[i].total_kern_pairs);
1389 HeapFree(GetProcessHeap(), 0, kern_pair);
1391 SelectObject(hdc, hfont_old);
1392 DeleteObject(hfont);
1398 static void test_height_selection(void)
1400 static const struct font_data
1402 const char face_name[LF_FACESIZE];
1403 int requested_height;
1404 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1407 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1408 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1409 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1410 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1411 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1412 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1413 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1414 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1415 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1416 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1420 HFONT hfont, old_hfont;
1424 hdc = CreateCompatibleDC(0);
1427 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1429 if (!is_truetype_font_installed(fd[i].face_name))
1431 skip("%s is not installed\n", fd[i].face_name);
1435 memset(&lf, 0, sizeof(lf));
1436 lf.lfHeight = fd[i].requested_height;
1437 lf.lfWeight = fd[i].weight;
1438 strcpy(lf.lfFaceName, fd[i].face_name);
1440 hfont = CreateFontIndirect(&lf);
1443 old_hfont = SelectObject(hdc, hfont);
1444 ret = GetTextMetrics(hdc, &tm);
1445 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1446 if(fd[i].dpi == tm.tmDigitizedAspectX)
1448 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1449 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);
1450 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);
1451 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);
1452 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);
1453 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1454 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);
1456 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);
1459 SelectObject(hdc, old_hfont);
1460 DeleteObject(hfont);
1466 static void test_GetOutlineTextMetrics(void)
1468 OUTLINETEXTMETRIC *otm;
1470 HFONT hfont, hfont_old;
1472 DWORD ret, otm_size;
1475 if (!is_font_installed("Arial"))
1477 skip("Arial is not installed\n");
1483 memset(&lf, 0, sizeof(lf));
1484 strcpy(lf.lfFaceName, "Arial");
1486 lf.lfWeight = FW_NORMAL;
1487 lf.lfPitchAndFamily = DEFAULT_PITCH;
1488 lf.lfQuality = PROOF_QUALITY;
1489 hfont = CreateFontIndirect(&lf);
1492 hfont_old = SelectObject(hdc, hfont);
1493 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1494 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1496 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1498 memset(otm, 0xAA, otm_size);
1499 SetLastError(0xdeadbeef);
1500 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1501 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1502 ok(ret == 1 /* Win9x */ ||
1503 ret == otm->otmSize /* XP*/,
1504 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1505 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1507 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1508 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1509 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1510 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1513 memset(otm, 0xAA, otm_size);
1514 SetLastError(0xdeadbeef);
1515 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1516 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1517 ok(ret == 1 /* Win9x */ ||
1518 ret == otm->otmSize /* XP*/,
1519 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1520 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1522 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1523 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1524 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1525 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1528 /* ask about truncated data */
1529 memset(otm, 0xAA, otm_size);
1530 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1531 SetLastError(0xdeadbeef);
1532 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1533 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1534 ok(ret == 1 /* Win9x */ ||
1535 ret == otm->otmSize /* XP*/,
1536 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1537 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1539 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1540 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1541 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1543 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1545 HeapFree(GetProcessHeap(), 0, otm);
1547 SelectObject(hdc, hfont_old);
1548 DeleteObject(hfont);
1553 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1557 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1558 areaWidth = clientArea->right - clientArea->left,
1560 BOOL lastExtent = FALSE;
1561 PSTR pFirstChar, pLastChar;
1567 int GetTextExtentExPointWWidth;
1570 GetTextMetricsA(hdc, &tm);
1571 y = clientArea->top;
1574 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1580 /* if not at the end of the string, ... */
1581 if (*str == '\0') break;
1582 /* ... add the next word to the current extent */
1583 while (*str != '\0' && *str++ != tm.tmBreakChar);
1585 SetTextJustification(hdc, 0, 0);
1586 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1587 } while ((int) size.cx < areaWidth);
1589 /* ignore trailing break chars */
1591 while (*(pLastChar - 1) == tm.tmBreakChar)
1597 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1599 SetTextJustification(hdc, 0, 0);
1600 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1602 /* do not justify the last extent */
1603 if (*str != '\0' && breakCount > 0)
1605 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1606 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1607 justifiedWidth = size.cx;
1609 else lastExtent = TRUE;
1611 /* catch errors and report them */
1612 if (!lastExtent && (justifiedWidth != areaWidth))
1614 memset(error[nErrors].extent, 0, 100);
1615 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1616 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1622 } while (*str && y < clientArea->bottom);
1624 for (e = 0; e < nErrors; e++)
1626 /* The width returned by GetTextExtentPoint32() is exactly the same
1627 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1628 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1629 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1630 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1634 static void test_SetTextJustification(void)
1641 static char testText[] =
1642 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1643 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1644 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1645 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1646 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1647 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1648 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1650 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1651 GetClientRect( hwnd, &clientArea );
1652 hdc = GetDC( hwnd );
1654 memset(&lf, 0, sizeof lf);
1655 lf.lfCharSet = ANSI_CHARSET;
1656 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1657 lf.lfWeight = FW_DONTCARE;
1659 lf.lfQuality = DEFAULT_QUALITY;
1660 lstrcpyA(lf.lfFaceName, "Times New Roman");
1661 hfont = create_font("Times New Roman", &lf);
1662 SelectObject(hdc, hfont);
1664 testJustification(hdc, testText, &clientArea);
1666 DeleteObject(hfont);
1667 ReleaseDC(hwnd, hdc);
1668 DestroyWindow(hwnd);
1671 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1675 HFONT hfont, hfont_old;
1682 assert(count <= 128);
1684 memset(&lf, 0, sizeof(lf));
1686 lf.lfCharSet = charset;
1688 lstrcpyA(lf.lfFaceName, "Arial");
1689 SetLastError(0xdeadbeef);
1690 hfont = CreateFontIndirectA(&lf);
1691 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1694 hfont_old = SelectObject(hdc, hfont);
1696 cs = GetTextCharsetInfo(hdc, &fs, 0);
1697 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1699 SetLastError(0xdeadbeef);
1700 ret = GetTextFaceA(hdc, sizeof(name), name);
1701 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1703 if (charset == SYMBOL_CHARSET)
1705 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1706 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1710 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1711 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1714 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1716 trace("Can't find codepage for charset %d\n", cs);
1720 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1722 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1724 skip("Font code page %d, looking for code page %d\n",
1725 pGdiGetCodePage(hdc), code_page);
1733 WCHAR unicode_buf[128];
1735 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1737 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1739 SetLastError(0xdeadbeef);
1740 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1741 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1742 count, ret, GetLastError());
1748 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1750 SetLastError(0xdeadbeef);
1751 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1752 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1753 count, ret, GetLastError());
1756 SelectObject(hdc, hfont_old);
1757 DeleteObject(hfont);
1764 static void test_font_charset(void)
1766 static struct charset_data
1770 WORD font_idxA[128], font_idxW[128];
1773 { ANSI_CHARSET, 1252 },
1774 { RUSSIAN_CHARSET, 1251 },
1775 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1779 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1781 win_skip("Skipping the font charset test on a Win9x platform\n");
1785 if (!is_font_installed("Arial"))
1787 skip("Arial is not installed\n");
1791 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1793 if (cd[i].charset == SYMBOL_CHARSET)
1795 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1797 skip("Symbol or Wingdings is not installed\n");
1801 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1802 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1803 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1806 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1809 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1810 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1813 skip("Symbol or Wingdings is not installed\n");
1816 static void test_GetFontUnicodeRanges(void)
1820 HFONT hfont, hfont_old;
1824 if (!pGetFontUnicodeRanges)
1826 win_skip("GetFontUnicodeRanges not available before W2K\n");
1830 memset(&lf, 0, sizeof(lf));
1831 lstrcpyA(lf.lfFaceName, "Arial");
1832 hfont = create_font("Arial", &lf);
1835 hfont_old = SelectObject(hdc, hfont);
1837 size = pGetFontUnicodeRanges(NULL, NULL);
1838 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1840 size = pGetFontUnicodeRanges(hdc, NULL);
1841 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1843 gs = HeapAlloc(GetProcessHeap(), 0, size);
1845 size = pGetFontUnicodeRanges(hdc, gs);
1846 ok(size, "GetFontUnicodeRanges failed\n");
1848 for (i = 0; i < gs->cRanges; i++)
1849 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1851 trace("found %u ranges\n", gs->cRanges);
1853 HeapFree(GetProcessHeap(), 0, gs);
1855 SelectObject(hdc, hfont_old);
1856 DeleteObject(hfont);
1857 ReleaseDC(NULL, hdc);
1860 #define MAX_ENUM_FONTS 4096
1862 struct enum_font_data
1865 LOGFONT lf[MAX_ENUM_FONTS];
1868 struct enum_font_dataW
1871 LOGFONTW lf[MAX_ENUM_FONTS];
1874 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1876 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1878 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1880 if (type != TRUETYPE_FONTTYPE) return 1;
1882 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1883 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1885 if (efd->total < MAX_ENUM_FONTS)
1886 efd->lf[efd->total++] = *lf;
1888 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1893 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1895 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1897 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1899 if (type != TRUETYPE_FONTTYPE) return 1;
1901 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1902 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1904 if (efd->total < MAX_ENUM_FONTS)
1905 efd->lf[efd->total++] = *lf;
1907 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1912 static void get_charset_stats(struct enum_font_data *efd,
1913 int *ansi_charset, int *symbol_charset,
1914 int *russian_charset)
1919 *symbol_charset = 0;
1920 *russian_charset = 0;
1922 for (i = 0; i < efd->total; i++)
1924 switch (efd->lf[i].lfCharSet)
1929 case SYMBOL_CHARSET:
1930 (*symbol_charset)++;
1932 case RUSSIAN_CHARSET:
1933 (*russian_charset)++;
1939 static void get_charset_statsW(struct enum_font_dataW *efd,
1940 int *ansi_charset, int *symbol_charset,
1941 int *russian_charset)
1946 *symbol_charset = 0;
1947 *russian_charset = 0;
1949 for (i = 0; i < efd->total; i++)
1951 switch (efd->lf[i].lfCharSet)
1956 case SYMBOL_CHARSET:
1957 (*symbol_charset)++;
1959 case RUSSIAN_CHARSET:
1960 (*russian_charset)++;
1966 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1968 struct enum_font_data efd;
1969 struct enum_font_dataW efdw;
1972 int i, ret, ansi_charset, symbol_charset, russian_charset;
1974 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1976 if (*font_name && !is_truetype_font_installed(font_name))
1978 skip("%s is not installed\n", font_name);
1984 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1985 * while EnumFontFamiliesEx doesn't.
1987 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1990 * Use EnumFontFamiliesW since win98 crashes when the
1991 * second parameter is NULL using EnumFontFamilies
1994 SetLastError(0xdeadbeef);
1995 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1996 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1999 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2000 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2001 ansi_charset, symbol_charset, russian_charset);
2002 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2003 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2004 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2005 ok(russian_charset > 0 ||
2006 broken(russian_charset == 0), /* NT4 */
2007 "NULL family should enumerate RUSSIAN_CHARSET\n");
2011 SetLastError(0xdeadbeef);
2012 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2013 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2016 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2017 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2018 ansi_charset, symbol_charset, russian_charset);
2019 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2020 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2021 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2022 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2027 SetLastError(0xdeadbeef);
2028 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2029 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2030 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2031 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2032 ansi_charset, symbol_charset, russian_charset,
2033 *font_name ? font_name : "<empty>");
2035 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2037 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2038 for (i = 0; i < efd.total; i++)
2040 /* FIXME: remove completely once Wine is fixed */
2041 if (efd.lf[i].lfCharSet != font_charset)
2044 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2047 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2048 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2049 font_name, efd.lf[i].lfFaceName);
2052 memset(&lf, 0, sizeof(lf));
2053 lf.lfCharSet = ANSI_CHARSET;
2054 lstrcpy(lf.lfFaceName, font_name);
2056 SetLastError(0xdeadbeef);
2057 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2058 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2059 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2060 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2061 ansi_charset, symbol_charset, russian_charset,
2062 *font_name ? font_name : "<empty>");
2063 if (font_charset == SYMBOL_CHARSET)
2066 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2068 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2072 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2073 for (i = 0; i < efd.total; i++)
2075 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2077 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2078 font_name, efd.lf[i].lfFaceName);
2082 /* DEFAULT_CHARSET should enumerate all available charsets */
2083 memset(&lf, 0, sizeof(lf));
2084 lf.lfCharSet = DEFAULT_CHARSET;
2085 lstrcpy(lf.lfFaceName, font_name);
2087 SetLastError(0xdeadbeef);
2088 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2089 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2090 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2091 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2092 ansi_charset, symbol_charset, russian_charset,
2093 *font_name ? font_name : "<empty>");
2094 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2095 for (i = 0; i < efd.total; i++)
2098 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2099 font_name, efd.lf[i].lfFaceName);
2103 switch (font_charset)
2106 ok(ansi_charset > 0,
2107 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2109 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2110 ok(russian_charset > 0,
2111 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2113 case SYMBOL_CHARSET:
2115 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2117 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2118 ok(!russian_charset,
2119 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2121 case DEFAULT_CHARSET:
2122 ok(ansi_charset > 0,
2123 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2124 ok(symbol_charset > 0,
2125 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2126 ok(russian_charset > 0,
2127 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2133 ok(ansi_charset > 0,
2134 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2135 ok(symbol_charset > 0,
2136 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2137 ok(russian_charset > 0,
2138 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2141 memset(&lf, 0, sizeof(lf));
2142 lf.lfCharSet = SYMBOL_CHARSET;
2143 lstrcpy(lf.lfFaceName, font_name);
2145 SetLastError(0xdeadbeef);
2146 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2147 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2148 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2149 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2150 ansi_charset, symbol_charset, russian_charset,
2151 *font_name ? font_name : "<empty>");
2152 if (*font_name && font_charset == ANSI_CHARSET)
2153 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2156 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2157 for (i = 0; i < efd.total; i++)
2159 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2161 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2162 font_name, efd.lf[i].lfFaceName);
2166 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2167 ok(symbol_charset > 0,
2168 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2169 ok(!russian_charset,
2170 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2176 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2178 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2180 if (type != TRUETYPE_FONTTYPE) return 1;
2182 if (efd->total < MAX_ENUM_FONTS)
2183 efd->lf[efd->total++] = *lf;
2185 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2190 static void test_EnumFontFamiliesEx_default_charset(void)
2192 struct enum_font_data efd;
2193 LOGFONT gui_font, enum_font;
2197 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2198 ok(ret, "GetObject failed.\n");
2205 memset(&enum_font, 0, sizeof(enum_font));
2206 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2207 enum_font.lfCharSet = DEFAULT_CHARSET;
2208 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2211 if (efd.total == 0) {
2212 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2215 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2217 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2218 "(%s) got charset %d expected %d\n",
2219 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2224 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2226 HFONT hfont, hfont_prev;
2228 GLYPHMETRICS gm1, gm2;
2232 if(!pGetGlyphIndicesA)
2235 /* negative widths are handled just as positive ones */
2236 lf2.lfWidth = -lf->lfWidth;
2238 SetLastError(0xdeadbeef);
2239 hfont = CreateFontIndirectA(lf);
2240 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2241 check_font("original", lf, hfont);
2243 hfont_prev = SelectObject(hdc, hfont);
2245 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2246 if (ret == GDI_ERROR || idx == 0xffff)
2248 SelectObject(hdc, hfont_prev);
2249 DeleteObject(hfont);
2250 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2254 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2255 memset(&gm1, 0xab, sizeof(gm1));
2256 SetLastError(0xdeadbeef);
2257 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2258 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2260 SelectObject(hdc, hfont_prev);
2261 DeleteObject(hfont);
2263 SetLastError(0xdeadbeef);
2264 hfont = CreateFontIndirectA(&lf2);
2265 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2266 check_font("negative width", &lf2, hfont);
2268 hfont_prev = SelectObject(hdc, hfont);
2270 memset(&gm2, 0xbb, sizeof(gm2));
2271 SetLastError(0xdeadbeef);
2272 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2273 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2275 SelectObject(hdc, hfont_prev);
2276 DeleteObject(hfont);
2278 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2279 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2280 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2281 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2282 gm1.gmCellIncX == gm2.gmCellIncX &&
2283 gm1.gmCellIncY == gm2.gmCellIncY,
2284 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2285 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2286 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2287 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2288 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2291 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2292 #include "pshpack2.h"
2296 SHORT xAvgCharWidth;
2297 USHORT usWeightClass;
2298 USHORT usWidthClass;
2300 SHORT ySubscriptXSize;
2301 SHORT ySubscriptYSize;
2302 SHORT ySubscriptXOffset;
2303 SHORT ySubscriptYOffset;
2304 SHORT ySuperscriptXSize;
2305 SHORT ySuperscriptYSize;
2306 SHORT ySuperscriptXOffset;
2307 SHORT ySuperscriptYOffset;
2308 SHORT yStrikeoutSize;
2309 SHORT yStrikeoutPosition;
2312 ULONG ulUnicodeRange1;
2313 ULONG ulUnicodeRange2;
2314 ULONG ulUnicodeRange3;
2315 ULONG ulUnicodeRange4;
2318 USHORT usFirstCharIndex;
2319 USHORT usLastCharIndex;
2320 /* According to the Apple spec, original version didn't have the below fields,
2321 * version numbers were taken from the OpenType spec.
2323 /* version 0 (TrueType 1.5) */
2324 USHORT sTypoAscender;
2325 USHORT sTypoDescender;
2326 USHORT sTypoLineGap;
2328 USHORT usWinDescent;
2329 /* version 1 (TrueType 1.66) */
2330 ULONG ulCodePageRange1;
2331 ULONG ulCodePageRange2;
2332 /* version 2 (OpenType 1.2) */
2335 USHORT usDefaultChar;
2337 USHORT usMaxContext;
2339 #include "poppack.h"
2341 #ifdef WORDS_BIGENDIAN
2342 #define GET_BE_WORD(x) (x)
2343 #define GET_BE_DWORD(x) (x)
2345 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2346 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2349 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2350 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2351 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2352 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2353 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2354 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2367 } cmap_encoding_record;
2375 BYTE glyph_ids[256];
2385 USHORT search_range;
2386 USHORT entry_selector;
2389 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2392 USHORT start_count[seg_countx2 / 2];
2393 USHORT id_delta[seg_countx2 / 2];
2394 USHORT id_range_offset[seg_countx2 / 2];
2404 USHORT id_range_offset;
2405 } cmap_format_4_seg;
2407 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2409 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2410 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2411 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2412 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2413 os2->panose.bWeight, os2->panose.bProportion);
2416 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2419 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2423 for(i = 0; i < 256; i++)
2425 if(cmap->glyph_ids[i] == 0) continue;
2427 if(*first == 256) *first = i;
2429 if(*first == 256) return FALSE;
2433 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2435 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2436 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2437 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2438 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2439 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2442 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2445 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2446 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2447 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2451 for(i = 0; i < seg_count; i++)
2454 cmap_format_4_seg seg;
2456 get_seg4(cmap, i, &seg);
2457 for(code = seg.start_count; code <= seg.end_count; code++)
2459 if(seg.id_range_offset == 0)
2460 index = (seg.id_delta + code) & 0xffff;
2463 index = seg.id_range_offset / 2
2464 + code - seg.start_count
2467 /* some fonts have broken last segment */
2468 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2469 index = GET_BE_WORD(glyph_ids[index]);
2472 trace("segment %04x/%04x index %04x points to nowhere\n",
2473 seg.start_count, seg.end_count, index);
2476 if(index) index += seg.id_delta;
2478 if(*first == 0x10000)
2479 *last = *first = code;
2485 if(*first == 0x10000) return FALSE;
2489 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2492 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2494 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2496 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2497 return (BYTE *)header + GET_BE_DWORD(record->offset);
2510 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2513 cmap_header *header;
2518 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2519 ok(size != GDI_ERROR, "no cmap table found\n");
2520 if(size == GDI_ERROR) return FALSE;
2522 header = HeapAlloc(GetProcessHeap(), 0, size);
2523 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2524 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2525 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2527 cmap = get_cmap(header, 3, 1);
2529 *cmap_type = cmap_ms_unicode;
2532 cmap = get_cmap(header, 3, 0);
2533 if(cmap) *cmap_type = cmap_ms_symbol;
2537 *cmap_type = cmap_none;
2541 format = GET_BE_WORD(*(WORD *)cmap);
2545 r = get_first_last_from_cmap0(cmap, first, last);
2548 r = get_first_last_from_cmap4(cmap, first, last, size);
2551 trace("unhandled cmap format %d\n", format);
2556 HeapFree(GetProcessHeap(), 0, header);
2560 #define TT_PLATFORM_MICROSOFT 3
2561 #define TT_MS_ID_UNICODE_CS 1
2562 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2563 #define TT_NAME_ID_FULL_NAME 4
2565 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2567 struct sfnt_name_header
2570 USHORT number_of_record;
2571 USHORT storage_offset;
2583 LONG size, offset, length;
2589 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2590 ok(size != GDI_ERROR, "no name table found\n");
2591 if(size == GDI_ERROR) return FALSE;
2593 data = HeapAlloc(GetProcessHeap(), 0, size);
2594 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2595 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2597 header = (void *)data;
2598 header->format = GET_BE_WORD(header->format);
2599 header->number_of_record = GET_BE_WORD(header->number_of_record);
2600 header->storage_offset = GET_BE_WORD(header->storage_offset);
2601 if (header->format != 0)
2603 trace("got format %u\n", header->format);
2606 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2608 trace("number records out of range: %d\n", header->number_of_record);
2611 if (header->storage_offset >= size)
2613 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2617 entry = (void *)&header[1];
2618 for (i = 0; i < header->number_of_record; i++)
2620 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2621 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2622 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2623 GET_BE_WORD(entry[i].name_id) != name_id)
2628 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2629 length = GET_BE_WORD(entry[i].length);
2630 if (offset + length > size)
2632 trace("entry %d is out of range\n", i);
2635 if (length >= out_size)
2637 trace("buffer too small for entry %d\n", i);
2641 name = (WCHAR *)(data + offset);
2642 for (c = 0; c < length / 2; c++)
2643 out_buf[c] = GET_BE_WORD(name[c]);
2651 HeapFree(GetProcessHeap(), 0, data);
2655 static void test_text_metrics(const LOGFONTA *lf)
2658 HFONT hfont, hfont_old;
2662 const char *font_name = lf->lfFaceName;
2663 DWORD cmap_first = 0, cmap_last = 0;
2664 cmap_type cmap_type;
2665 BOOL sys_lang_non_english;
2667 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2670 SetLastError(0xdeadbeef);
2671 hfont = CreateFontIndirectA(lf);
2672 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2674 hfont_old = SelectObject(hdc, hfont);
2676 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2677 if (size == GDI_ERROR)
2679 trace("OS/2 chunk was not found\n");
2682 if (size > sizeof(tt_os2))
2684 trace("got too large OS/2 chunk of size %u\n", size);
2685 size = sizeof(tt_os2);
2688 memset(&tt_os2, 0, sizeof(tt_os2));
2689 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2690 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2692 SetLastError(0xdeadbeef);
2693 ret = GetTextMetricsA(hdc, &tmA);
2694 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2696 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2698 skip("Unable to retrieve first and last glyphs from cmap\n");
2702 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2703 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2704 UINT os2_first_char, os2_last_char, default_char, break_char;
2708 version = GET_BE_WORD(tt_os2.version);
2710 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2711 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2712 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2713 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2715 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2716 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2717 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2719 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2724 case 1257: /* Baltic */
2725 expect_last_W = 0xf8fd;
2728 expect_last_W = 0xf0ff;
2730 expect_break_W = 0x20;
2731 expect_default_W = expect_break_W - 1;
2732 expect_first_A = 0x1e;
2733 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2737 expect_first_W = cmap_first;
2738 expect_last_W = min(cmap_last, os2_last_char);
2739 if(os2_first_char <= 1)
2740 expect_break_W = os2_first_char + 2;
2741 else if(os2_first_char > 0xff)
2742 expect_break_W = 0x20;
2744 expect_break_W = os2_first_char;
2745 expect_default_W = expect_break_W - 1;
2746 expect_first_A = expect_default_W - 1;
2747 expect_last_A = min(expect_last_W, 0xff);
2749 expect_break_A = expect_break_W;
2750 expect_default_A = expect_default_W;
2752 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2753 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2754 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2755 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2756 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2758 ok(tmA.tmFirstChar == expect_first_A ||
2759 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2760 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2761 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2762 ok(tmA.tmLastChar == expect_last_A ||
2763 tmA.tmLastChar == 0xff /* win9x */,
2764 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2766 skip("tmLastChar is DBCS lead byte\n");
2767 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2768 font_name, tmA.tmBreakChar, expect_break_A);
2769 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2770 "A: tmDefaultChar for %s got %02x expected %02x\n",
2771 font_name, tmA.tmDefaultChar, expect_default_A);
2774 SetLastError(0xdeadbeef);
2775 ret = GetTextMetricsW(hdc, &tmW);
2776 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2777 "GetTextMetricsW error %u\n", GetLastError());
2780 /* Wine uses the os2 first char */
2781 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2782 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2783 font_name, tmW.tmFirstChar, expect_first_W);
2785 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2786 font_name, tmW.tmFirstChar, expect_first_W);
2788 /* Wine uses the os2 last char */
2789 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2790 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2791 font_name, tmW.tmLastChar, expect_last_W);
2793 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2794 font_name, tmW.tmLastChar, expect_last_W);
2795 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2796 font_name, tmW.tmBreakChar, expect_break_W);
2797 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2798 "W: tmDefaultChar for %s got %02x expected %02x\n",
2799 font_name, tmW.tmDefaultChar, expect_default_W);
2801 /* Test the aspect ratio while we have tmW */
2802 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2803 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2804 tmW.tmDigitizedAspectX, ret);
2805 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2806 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2807 tmW.tmDigitizedAspectX, ret);
2811 /* test FF_ values */
2812 switch(tt_os2.panose.bFamilyType)
2816 case PAN_FAMILY_TEXT_DISPLAY:
2817 case PAN_FAMILY_PICTORIAL:
2819 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2820 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2822 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2825 switch(tt_os2.panose.bSerifStyle)
2830 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2833 case PAN_SERIF_COVE:
2834 case PAN_SERIF_OBTUSE_COVE:
2835 case PAN_SERIF_SQUARE_COVE:
2836 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2837 case PAN_SERIF_SQUARE:
2838 case PAN_SERIF_THIN:
2839 case PAN_SERIF_BONE:
2840 case PAN_SERIF_EXAGGERATED:
2841 case PAN_SERIF_TRIANGLE:
2842 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2845 case PAN_SERIF_NORMAL_SANS:
2846 case PAN_SERIF_OBTUSE_SANS:
2847 case PAN_SERIF_PERP_SANS:
2848 case PAN_SERIF_FLARED:
2849 case PAN_SERIF_ROUNDED:
2850 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2855 case PAN_FAMILY_SCRIPT:
2856 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2859 case PAN_FAMILY_DECORATIVE:
2860 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2864 test_negative_width(hdc, lf);
2867 SelectObject(hdc, hfont_old);
2868 DeleteObject(hfont);
2873 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2875 INT *enumed = (INT *)lParam;
2877 if (type == TRUETYPE_FONTTYPE)
2880 test_text_metrics(lf);
2885 static void test_GetTextMetrics(void)
2891 /* Report only once */
2892 if(!pGetGlyphIndicesA)
2893 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2897 memset(&lf, 0, sizeof(lf));
2898 lf.lfCharSet = DEFAULT_CHARSET;
2900 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2901 trace("Tested metrics of %d truetype fonts\n", enumed);
2906 static void test_nonexistent_font(void)
2914 { "Times New Roman Baltic", 186 },
2915 { "Times New Roman CE", 238 },
2916 { "Times New Roman CYR", 204 },
2917 { "Times New Roman Greek", 161 },
2918 { "Times New Roman TUR", 162 }
2924 INT cs, expected_cs, i;
2925 char buf[LF_FACESIZE];
2927 if (!is_truetype_font_installed("Arial") ||
2928 !is_truetype_font_installed("Times New Roman"))
2930 skip("Arial or Times New Roman not installed\n");
2934 expected_cs = GetACP();
2935 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2937 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2940 expected_cs = csi.ciCharset;
2941 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2945 memset(&lf, 0, sizeof(lf));
2947 lf.lfWeight = FW_REGULAR;
2948 lf.lfCharSet = ANSI_CHARSET;
2949 lf.lfPitchAndFamily = FF_SWISS;
2950 strcpy(lf.lfFaceName, "Nonexistent font");
2951 hfont = CreateFontIndirectA(&lf);
2952 hfont = SelectObject(hdc, hfont);
2953 GetTextFaceA(hdc, sizeof(buf), buf);
2954 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2955 cs = GetTextCharset(hdc);
2956 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2957 DeleteObject(SelectObject(hdc, hfont));
2959 memset(&lf, 0, sizeof(lf));
2961 lf.lfWeight = FW_DONTCARE;
2962 strcpy(lf.lfFaceName, "Nonexistent font");
2963 hfont = CreateFontIndirectA(&lf);
2964 hfont = SelectObject(hdc, hfont);
2965 GetTextFaceA(hdc, sizeof(buf), buf);
2966 todo_wine /* Wine uses Arial for all substitutions */
2967 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2968 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2969 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2971 cs = GetTextCharset(hdc);
2972 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2973 DeleteObject(SelectObject(hdc, hfont));
2975 memset(&lf, 0, sizeof(lf));
2977 lf.lfWeight = FW_REGULAR;
2978 strcpy(lf.lfFaceName, "Nonexistent font");
2979 hfont = CreateFontIndirectA(&lf);
2980 hfont = SelectObject(hdc, hfont);
2981 GetTextFaceA(hdc, sizeof(buf), buf);
2982 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2983 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2984 cs = GetTextCharset(hdc);
2985 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2986 DeleteObject(SelectObject(hdc, hfont));
2988 memset(&lf, 0, sizeof(lf));
2990 lf.lfWeight = FW_DONTCARE;
2991 strcpy(lf.lfFaceName, "Times New Roman");
2992 hfont = CreateFontIndirectA(&lf);
2993 hfont = SelectObject(hdc, hfont);
2994 GetTextFaceA(hdc, sizeof(buf), buf);
2995 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2996 cs = GetTextCharset(hdc);
2997 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2998 DeleteObject(SelectObject(hdc, hfont));
3000 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3002 memset(&lf, 0, sizeof(lf));
3004 lf.lfWeight = FW_REGULAR;
3005 strcpy(lf.lfFaceName, font_subst[i].name);
3006 hfont = CreateFontIndirectA(&lf);
3007 hfont = SelectObject(hdc, hfont);
3008 cs = GetTextCharset(hdc);
3009 if (font_subst[i].charset == expected_cs)
3011 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3012 GetTextFaceA(hdc, sizeof(buf), buf);
3013 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3017 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3018 GetTextFaceA(hdc, sizeof(buf), buf);
3019 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3020 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3022 DeleteObject(SelectObject(hdc, hfont));
3024 memset(&lf, 0, sizeof(lf));
3026 lf.lfWeight = FW_DONTCARE;
3027 strcpy(lf.lfFaceName, font_subst[i].name);
3028 hfont = CreateFontIndirectA(&lf);
3029 hfont = SelectObject(hdc, hfont);
3030 GetTextFaceA(hdc, sizeof(buf), buf);
3031 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3032 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3033 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3034 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3035 "got %s for font %s\n", buf, font_subst[i].name);
3036 cs = GetTextCharset(hdc);
3037 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3038 DeleteObject(SelectObject(hdc, hfont));
3044 static void test_GdiRealizationInfo(void)
3049 HFONT hfont, hfont_old;
3052 if(!pGdiRealizationInfo)
3054 win_skip("GdiRealizationInfo not available\n");
3060 memset(info, 0xcc, sizeof(info));
3061 r = pGdiRealizationInfo(hdc, info);
3062 ok(r != 0, "ret 0\n");
3063 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3064 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3066 if (!is_truetype_font_installed("Arial"))
3068 skip("skipping GdiRealizationInfo with truetype font\n");
3072 memset(&lf, 0, sizeof(lf));
3073 strcpy(lf.lfFaceName, "Arial");
3075 lf.lfWeight = FW_NORMAL;
3076 hfont = CreateFontIndirectA(&lf);
3077 hfont_old = SelectObject(hdc, hfont);
3079 memset(info, 0xcc, sizeof(info));
3080 r = pGdiRealizationInfo(hdc, info);
3081 ok(r != 0, "ret 0\n");
3082 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3083 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3085 DeleteObject(SelectObject(hdc, hfont_old));
3091 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3092 the nul in the count of characters copied when the face name buffer is not
3093 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3094 always includes it. */
3095 static void test_GetTextFace(void)
3097 static const char faceA[] = "Tahoma";
3098 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3101 char bufA[LF_FACESIZE];
3102 WCHAR bufW[LF_FACESIZE];
3107 if(!is_font_installed("Tahoma"))
3109 skip("Tahoma is not installed so skipping this test\n");
3114 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3115 f = CreateFontIndirectA(&fA);
3116 ok(f != NULL, "CreateFontIndirectA failed\n");
3119 g = SelectObject(dc, f);
3120 n = GetTextFaceA(dc, sizeof bufA, bufA);
3121 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3122 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3124 /* Play with the count arg. */
3126 n = GetTextFaceA(dc, 0, bufA);
3127 ok(n == 0, "GetTextFaceA returned %d\n", n);
3128 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3131 n = GetTextFaceA(dc, 1, bufA);
3132 ok(n == 0, "GetTextFaceA returned %d\n", n);
3133 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3135 bufA[0] = 'x'; bufA[1] = 'y';
3136 n = GetTextFaceA(dc, 2, bufA);
3137 ok(n == 1, "GetTextFaceA returned %d\n", n);
3138 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3140 n = GetTextFaceA(dc, 0, NULL);
3141 ok(n == sizeof faceA ||
3142 broken(n == 0), /* win98, winMe */
3143 "GetTextFaceA returned %d\n", n);
3145 DeleteObject(SelectObject(dc, g));
3146 ReleaseDC(NULL, dc);
3149 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3150 SetLastError(0xdeadbeef);
3151 f = CreateFontIndirectW(&fW);
3152 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3154 win_skip("CreateFontIndirectW is not implemented\n");
3157 ok(f != NULL, "CreateFontIndirectW failed\n");
3160 g = SelectObject(dc, f);
3161 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3162 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3163 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3165 /* Play with the count arg. */
3167 n = GetTextFaceW(dc, 0, bufW);
3168 ok(n == 0, "GetTextFaceW returned %d\n", n);
3169 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3172 n = GetTextFaceW(dc, 1, bufW);
3173 ok(n == 1, "GetTextFaceW returned %d\n", n);
3174 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3176 bufW[0] = 'x'; bufW[1] = 'y';
3177 n = GetTextFaceW(dc, 2, bufW);
3178 ok(n == 2, "GetTextFaceW returned %d\n", n);
3179 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3181 n = GetTextFaceW(dc, 0, NULL);
3182 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3184 DeleteObject(SelectObject(dc, g));
3185 ReleaseDC(NULL, dc);
3188 static void test_orientation(void)
3190 static const char test_str[11] = "Test String";
3193 HFONT hfont, old_hfont;
3196 if (!is_truetype_font_installed("Arial"))
3198 skip("Arial is not installed\n");
3202 hdc = CreateCompatibleDC(0);
3203 memset(&lf, 0, sizeof(lf));
3204 lstrcpyA(lf.lfFaceName, "Arial");
3206 lf.lfOrientation = lf.lfEscapement = 900;
3207 hfont = create_font("orientation", &lf);
3208 old_hfont = SelectObject(hdc, hfont);
3209 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3210 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3211 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3212 SelectObject(hdc, old_hfont);
3213 DeleteObject(hfont);
3217 static void test_oemcharset(void)
3221 HFONT hfont, old_hfont;
3224 hdc = CreateCompatibleDC(0);
3225 ZeroMemory(&lf, sizeof(lf));
3227 lf.lfCharSet = OEM_CHARSET;
3228 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3229 lstrcpyA(lf.lfFaceName, "Terminal");
3230 hfont = CreateFontIndirectA(&lf);
3231 old_hfont = SelectObject(hdc, hfont);
3232 charset = GetTextCharset(hdc);
3234 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3235 hfont = SelectObject(hdc, old_hfont);
3236 GetObjectA(hfont, sizeof(clf), &clf);
3237 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3238 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3239 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3240 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3241 DeleteObject(hfont);
3245 static void test_GetGlyphOutline(void)
3248 GLYPHMETRICS gm, gm2;
3250 HFONT hfont, old_hfont;
3259 {ANSI_CHARSET, 0x30, 0x30},
3260 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3261 {HANGEUL_CHARSET, 0x8141, 0xac02},
3262 {JOHAB_CHARSET, 0x8446, 0x3135},
3263 {GB2312_CHARSET, 0x8141, 0x4e04},
3264 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3268 if (!is_truetype_font_installed("Tahoma"))
3270 skip("Tahoma is not installed\n");
3274 hdc = CreateCompatibleDC(0);
3275 memset(&lf, 0, sizeof(lf));
3277 lstrcpyA(lf.lfFaceName, "Tahoma");
3278 SetLastError(0xdeadbeef);
3279 hfont = CreateFontIndirectA(&lf);
3280 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3281 old_hfont = SelectObject(hdc, hfont);
3283 memset(&gm, 0, sizeof(gm));
3284 SetLastError(0xdeadbeef);
3285 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3286 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3288 memset(&gm, 0, sizeof(gm));
3289 SetLastError(0xdeadbeef);
3290 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3291 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3292 ok(GetLastError() == 0xdeadbeef ||
3293 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3294 "expected 0xdeadbeef, got %u\n", GetLastError());
3296 memset(&gm, 0, sizeof(gm));
3297 SetLastError(0xdeadbeef);
3298 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3299 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3300 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3302 memset(&gm, 0, sizeof(gm));
3303 SetLastError(0xdeadbeef);
3304 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3305 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3307 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3308 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3311 /* test for needed buffer size request on space char */
3312 memset(&gm, 0, sizeof(gm));
3313 SetLastError(0xdeadbeef);
3314 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3315 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3316 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3318 /* requesting buffer size for space char + error */
3319 memset(&gm, 0, sizeof(gm));
3320 SetLastError(0xdeadbeef);
3321 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3322 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3324 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3325 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3328 SelectObject(hdc, old_hfont);
3329 DeleteObject(hfont);
3331 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3333 lf.lfFaceName[0] = '\0';
3334 lf.lfCharSet = c[i].cs;
3335 lf.lfPitchAndFamily = 0;
3336 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3338 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3342 old_hfont = SelectObject(hdc, hfont);
3344 /* expected to ignore superfluous bytes (sigle-byte character) */
3345 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3346 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3347 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3349 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3350 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3351 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3353 /* expected to ignore superfluous bytes (double-byte character) */
3354 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3355 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3356 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3357 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3359 /* expected to match wide-char version results */
3360 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3361 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3363 hfont = SelectObject(hdc, old_hfont);
3364 DeleteObject(hfont);
3370 /* bug #9995: there is a limit to the character width that can be specified */
3371 static void test_GetTextMetrics2(const char *fontname, int font_height)
3377 int ave_width, height, width, ratio, scale;
3379 if (!is_truetype_font_installed( fontname)) {
3380 skip("%s is not installed\n", fontname);
3383 hdc = CreateCompatibleDC(0);
3384 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3385 /* select width = 0 */
3386 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3387 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3388 DEFAULT_QUALITY, VARIABLE_PITCH,
3390 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3391 of = SelectObject( hdc, hf);
3392 ret = GetTextMetricsA( hdc, &tm);
3393 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3394 height = tm.tmHeight;
3395 ave_width = tm.tmAveCharWidth;
3396 SelectObject( hdc, of);
3399 trace("height %d, ave width %d\n", height, ave_width);
3401 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3403 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3404 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3405 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3406 ok(hf != 0, "CreateFont failed\n");
3407 of = SelectObject(hdc, hf);
3408 ret = GetTextMetrics(hdc, &tm);
3409 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3410 SelectObject(hdc, of);
3413 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3419 ratio = width / height;
3420 scale = width / ave_width;
3422 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3423 width, height, ratio, width, ave_width, scale);
3425 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3428 static void test_CreateFontIndirect(void)
3430 LOGFONTA lf, getobj_lf;
3433 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3435 memset(&lf, 0, sizeof(lf));
3436 lf.lfCharSet = ANSI_CHARSET;
3437 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3440 lf.lfQuality = DEFAULT_QUALITY;
3441 lf.lfItalic = FALSE;
3442 lf.lfWeight = FW_DONTCARE;
3444 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3446 lstrcpyA(lf.lfFaceName, TestName[i]);
3447 hfont = CreateFontIndirectA(&lf);
3448 ok(hfont != 0, "CreateFontIndirectA failed\n");
3449 SetLastError(0xdeadbeef);
3450 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3451 ok(ret, "GetObject failed: %d\n", GetLastError());
3452 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3453 ok(lf.lfWeight == getobj_lf.lfWeight ||
3454 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3455 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3456 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3457 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3458 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3459 DeleteObject(hfont);
3463 static void test_CreateFontIndirectEx(void)
3465 ENUMLOGFONTEXDVA lfex;
3468 if (!pCreateFontIndirectExA)
3470 win_skip("CreateFontIndirectExA is not available\n");
3474 if (!is_truetype_font_installed("Arial"))
3476 skip("Arial is not installed\n");
3480 SetLastError(0xdeadbeef);
3481 hfont = pCreateFontIndirectExA(NULL);
3482 ok(hfont == NULL, "got %p\n", hfont);
3483 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3485 memset(&lfex, 0, sizeof(lfex));
3486 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3487 hfont = pCreateFontIndirectExA(&lfex);
3488 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3490 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3491 DeleteObject(hfont);
3494 static void free_font(void *font)
3496 UnmapViewOfFile(font);
3499 static void *load_font(const char *font_name, DWORD *font_size)
3501 char file_name[MAX_PATH];
3502 HANDLE file, mapping;
3505 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3506 strcat(file_name, "\\fonts\\");
3507 strcat(file_name, font_name);
3509 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3510 if (file == INVALID_HANDLE_VALUE) return NULL;
3512 *font_size = GetFileSize(file, NULL);
3514 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3521 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3524 CloseHandle(mapping);
3528 static void test_AddFontMemResource(void)
3531 DWORD font_size, num_fonts;
3535 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3537 win_skip("AddFontMemResourceEx is not available on this platform\n");
3541 font = load_font("sserife.fon", &font_size);
3544 skip("Unable to locate and load font sserife.fon\n");
3548 SetLastError(0xdeadbeef);
3549 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3550 ok(!ret, "AddFontMemResourceEx should fail\n");
3551 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3552 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3555 SetLastError(0xdeadbeef);
3556 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3557 ok(!ret, "AddFontMemResourceEx should fail\n");
3558 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3559 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3562 SetLastError(0xdeadbeef);
3563 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3564 ok(!ret, "AddFontMemResourceEx should fail\n");
3565 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3566 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3569 SetLastError(0xdeadbeef);
3570 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3571 ok(!ret, "AddFontMemResourceEx should fail\n");
3572 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3573 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3576 SetLastError(0xdeadbeef);
3577 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3578 ok(!ret, "AddFontMemResourceEx should fail\n");
3579 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3580 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3583 SetLastError(0xdeadbeef);
3584 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3585 ok(!ret, "AddFontMemResourceEx should fail\n");
3586 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3587 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3590 num_fonts = 0xdeadbeef;
3591 SetLastError(0xdeadbeef);
3592 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3593 ok(!ret, "AddFontMemResourceEx should fail\n");
3594 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3595 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3597 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3599 if (0) /* hangs under windows 2000 */
3601 num_fonts = 0xdeadbeef;
3602 SetLastError(0xdeadbeef);
3603 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3604 ok(!ret, "AddFontMemResourceEx should fail\n");
3605 ok(GetLastError() == 0xdeadbeef,
3606 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3608 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3611 num_fonts = 0xdeadbeef;
3612 SetLastError(0xdeadbeef);
3613 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3614 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3615 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3616 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3620 SetLastError(0xdeadbeef);
3621 bRet = pRemoveFontMemResourceEx(ret);
3622 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3624 /* test invalid pointer to number of loaded fonts */
3625 font = load_font("sserife.fon", &font_size);
3626 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3628 SetLastError(0xdeadbeef);
3629 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3630 ok(!ret, "AddFontMemResourceEx should fail\n");
3631 ok(GetLastError() == 0xdeadbeef,
3632 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3635 SetLastError(0xdeadbeef);
3636 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3637 ok(!ret, "AddFontMemResourceEx should fail\n");
3638 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3639 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3645 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3649 if (type != TRUETYPE_FONTTYPE) return 1;
3651 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3653 lf = (LOGFONT *)lparam;
3658 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3663 if (type != TRUETYPE_FONTTYPE) return 1;
3665 lf = (LOGFONT *)lparam;
3666 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3669 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3676 static void test_EnumFonts(void)
3682 if (!is_truetype_font_installed("Arial"))
3684 skip("Arial is not installed\n");
3688 /* Windows uses localized font face names, so Arial Bold won't be found */
3689 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3691 skip("User locale is not English, skipping the test\n");
3695 hdc = CreateCompatibleDC(0);
3697 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3698 ok(!ret, "font Arial is not enumerated\n");
3699 ret = strcmp(lf.lfFaceName, "Arial");
3700 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3701 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3703 lstrcpy(lf.lfFaceName, "Arial");
3704 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3705 ok(!ret, "font Arial is not enumerated\n");
3706 ret = strcmp(lf.lfFaceName, "Arial");
3707 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3708 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3710 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3711 ok(!ret, "font Arial Bold is not enumerated\n");
3712 ret = strcmp(lf.lfFaceName, "Arial");
3713 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3714 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3716 lstrcpy(lf.lfFaceName, "Arial Bold");
3717 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3718 ok(ret, "font Arial Bold should not be enumerated\n");
3720 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3721 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3722 ret = strcmp(lf.lfFaceName, "Arial");
3723 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3724 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3726 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3727 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3728 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3730 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3731 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3733 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3734 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3735 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3740 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3742 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3743 const char *fullname = (const char *)lParam;
3745 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3750 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3755 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3762 static void test_fullname(void)
3764 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3765 char buf[LF_FULLFACESIZE];
3771 hdc = CreateCompatibleDC(0);
3772 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3774 memset(&lf, 0, sizeof(lf));
3775 lf.lfCharSet = ANSI_CHARSET;
3776 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3779 lf.lfQuality = DEFAULT_QUALITY;
3780 lf.lfItalic = FALSE;
3781 lf.lfWeight = FW_DONTCARE;
3783 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3785 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3787 skip("%s is not installed\n", TestName[i]);
3791 lstrcpyA(lf.lfFaceName, TestName[i]);
3792 hfont = CreateFontIndirectA(&lf);
3793 ok(hfont != 0, "CreateFontIndirectA failed\n");
3795 of = SelectObject(hdc, hfont);
3797 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3798 "face full name could not be read\n");
3799 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3800 SelectObject(hdc, of);
3801 DeleteObject(hfont);
3806 static BOOL write_ttf_file(char *tmp_name)
3808 char tmp_path[MAX_PATH];
3815 SetLastError(0xdeadbeef);
3816 rsrc = FindResource(GetModuleHandle(0), "wine_test.ttf", RT_RCDATA);
3817 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
3818 if (!rsrc) return FALSE;
3819 SetLastError(0xdeadbeef);
3820 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
3821 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
3822 if (!rsrc_data) return FALSE;
3823 SetLastError(0xdeadbeef);
3824 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
3825 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
3826 if (!rsrc_size) return FALSE;
3828 SetLastError(0xdeadbeef);
3829 ret = GetTempPath(MAX_PATH, tmp_path);
3830 ok(ret, "GetTempPath() error %d\n", GetLastError());
3831 SetLastError(0xdeadbeef);
3832 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
3833 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3835 SetLastError(0xdeadbeef);
3836 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
3837 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
3838 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
3840 SetLastError(0xdeadbeef);
3841 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
3842 ok(ret, "WriteFile() error %d\n", GetLastError());
3848 static void test_CreateScalableFontResource(void)
3850 char ttf_name[MAX_PATH];
3851 char tmp_path[MAX_PATH];
3852 char fot_name[MAX_PATH];
3856 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
3858 win_skip("AddFontResourceExA is not available on this platform\n");
3862 if (!write_ttf_file(ttf_name))
3864 skip("Failed to create ttf file for testing\n");
3868 trace("created %s\n", ttf_name);
3870 ret = is_truetype_font_installed("wine_test");
3871 ok(!ret, "font wine_test should not be enumerated\n");
3873 ret = GetTempPath(MAX_PATH, tmp_path);
3874 ok(ret, "GetTempPath() error %d\n", GetLastError());
3875 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
3876 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3878 ret = GetFileAttributes(fot_name);
3879 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
3881 SetLastError(0xdeadbeef);
3882 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3883 ok(!ret, "CreateScalableFontResource() should fail\n");
3884 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3886 SetLastError(0xdeadbeef);
3887 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
3888 ok(!ret, "CreateScalableFontResource() should fail\n");
3889 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3891 file_part = strrchr(ttf_name, '\\');
3892 SetLastError(0xdeadbeef);
3893 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
3894 ok(!ret, "CreateScalableFontResource() should fail\n");
3895 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3897 SetLastError(0xdeadbeef);
3898 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
3899 ok(!ret, "CreateScalableFontResource() should fail\n");
3901 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3903 SetLastError(0xdeadbeef);
3904 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
3905 ok(!ret, "CreateScalableFontResource() should fail\n");
3907 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3909 ret = DeleteFile(fot_name);
3910 ok(ret, "DeleteFile() error %d\n", GetLastError());
3912 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3914 ok(!ret, "RemoveFontResourceEx() should fail\n");
3916 /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3919 /* test public font resource */
3920 SetLastError(0xdeadbeef);
3921 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3922 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3924 ret = is_truetype_font_installed("wine_test");
3925 ok(!ret, "font wine_test should not be enumerated\n");
3927 SetLastError(0xdeadbeef);
3928 ret = pAddFontResourceExA(fot_name, 0, 0);
3929 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3931 ret = is_truetype_font_installed("wine_test");
3932 ok(ret, "font wine_test should be enumerated\n");
3934 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3935 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
3937 SetLastError(0xdeadbeef);
3938 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3940 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3942 ret = is_truetype_font_installed("wine_test");
3944 ok(!ret, "font wine_test should not be enumerated\n");
3946 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
3949 /* remove once RemoveFontResource is implemented */
3950 DeleteFile(fot_name);
3951 DeleteFile(ttf_name);
3955 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3956 ok(!ret, "RemoveFontResourceEx() should fail\n");
3958 DeleteFile(fot_name);
3960 /* test hidden font resource */
3961 SetLastError(0xdeadbeef);
3962 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
3963 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3965 ret = is_truetype_font_installed("wine_test");
3966 ok(!ret, "font wine_test should not be enumerated\n");
3968 SetLastError(0xdeadbeef);
3969 ret = pAddFontResourceExA(fot_name, 0, 0);
3970 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3972 ret = is_truetype_font_installed("wine_test");
3973 ok(!ret, "font wine_test should not be enumerated\n");
3975 /* XP allows removing a private font added with 0 flags */
3976 SetLastError(0xdeadbeef);
3977 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3978 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3980 ret = is_truetype_font_installed("wine_test");
3981 ok(!ret, "font wine_test should not be enumerated\n");
3983 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3984 ok(!ret, "RemoveFontResourceEx() should fail\n");
3986 DeleteFile(fot_name);
3987 DeleteFile(ttf_name);
3996 test_outline_font();
3997 test_bitmap_font_metrics();
3998 test_GdiGetCharDimensions();
3999 test_GetCharABCWidths();
4000 test_text_extents();
4001 test_GetGlyphIndices();
4002 test_GetKerningPairs();
4003 test_GetOutlineTextMetrics();
4004 test_SetTextJustification();
4005 test_font_charset();
4006 test_GetFontUnicodeRanges();
4007 test_nonexistent_font();
4009 test_height_selection();
4010 test_AddFontMemResource();
4013 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4014 * I'd like to avoid them in this test.
4016 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4017 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4018 if (is_truetype_font_installed("Arial Black") &&
4019 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4021 test_EnumFontFamilies("", ANSI_CHARSET);
4022 test_EnumFontFamilies("", SYMBOL_CHARSET);
4023 test_EnumFontFamilies("", DEFAULT_CHARSET);
4026 skip("Arial Black or Symbol/Wingdings is not installed\n");
4027 test_EnumFontFamiliesEx_default_charset();
4028 test_GetTextMetrics();
4029 test_GdiRealizationInfo();
4031 test_GetGlyphOutline();
4032 test_GetTextMetrics2("Tahoma", -11);
4033 test_GetTextMetrics2("Tahoma", -55);
4034 test_GetTextMetrics2("Tahoma", -110);
4035 test_GetTextMetrics2("Arial", -11);
4036 test_GetTextMetrics2("Arial", -55);
4037 test_GetTextMetrics2("Arial", -110);
4038 test_CreateFontIndirect();
4039 test_CreateFontIndirectEx();
4043 /* CreateScalableFontResource should be last test until RemoveFontResource
4044 * is properly implemented.
4046 test_CreateScalableFontResource();