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;
676 BYTE first_char, last_char, def_char, break_char;
681 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
682 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
684 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
685 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
686 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
687 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
688 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
689 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
690 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
691 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
692 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
693 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
694 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
695 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
696 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
698 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
699 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
700 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
701 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
702 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
703 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
704 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
705 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
706 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
707 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
708 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
709 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
711 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
712 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
713 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
714 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
715 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
717 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
719 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
721 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
722 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
723 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
724 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
725 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
726 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
727 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
729 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
730 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
731 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
732 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
733 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
734 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
735 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
736 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
737 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
739 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
741 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
742 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
743 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
745 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
746 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
747 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
749 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
750 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
751 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
753 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
754 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
756 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
757 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN },
759 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
760 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
761 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN },
762 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
763 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
764 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC },
765 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN },
766 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
767 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
768 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC },
769 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN },
770 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
771 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
772 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC },
773 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN },
774 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
775 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC },
776 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN },
778 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
779 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
780 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
781 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
782 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
783 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
784 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
785 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
786 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
787 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
788 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
789 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
791 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
792 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
793 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
795 /* The 120dpi version still has its dpi marked as 96 */
796 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
798 /* FIXME: add "Terminal" */
802 HFONT hfont, old_hfont;
807 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
809 hdc = CreateCompatibleDC(0);
812 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
816 memset(&lf, 0, sizeof(lf));
818 lf.lfHeight = fd[i].height;
819 strcpy(lf.lfFaceName, fd[i].face_name);
821 for(bit = 0; bit < 32; bit++)
829 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
830 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
832 lf.lfCharSet = csi.ciCharset;
833 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
836 hfont = create_font(lf.lfFaceName, &lf);
837 old_hfont = SelectObject(hdc, hfont);
838 bRet = GetTextMetrics(hdc, &tm);
839 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
840 if(fd[i].dpi == tm.tmDigitizedAspectX)
842 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
843 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
845 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);
846 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);
847 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);
848 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);
849 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);
850 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);
851 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);
852 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmFirstChar);
853 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmLastChar);
854 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmDefaultChar);
855 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmBreakChar);
857 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
858 that make the max width bigger */
859 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
860 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);
863 skip("Skipping font metrics test for system langid 0x%x\n",
866 SelectObject(hdc, old_hfont);
874 static void test_GdiGetCharDimensions(void)
880 LONG avgwidth, height;
881 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
883 if (!pGdiGetCharDimensions)
885 win_skip("GdiGetCharDimensions not available on this platform\n");
889 hdc = CreateCompatibleDC(NULL);
891 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
892 avgwidth = ((size.cx / 26) + 1) / 2;
894 ret = pGdiGetCharDimensions(hdc, &tm, &height);
895 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
896 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
898 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
899 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
901 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
902 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
905 ret = pGdiGetCharDimensions(hdc, NULL, &height);
906 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
907 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
912 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
913 const TEXTMETRIC *lpntme,
914 DWORD FontType, LPARAM lParam)
916 if (FontType & TRUETYPE_FONTTYPE)
920 hfont = CreateFontIndirect(lpelfe);
923 *(HFONT *)lParam = hfont;
931 static void test_GetCharABCWidths(void)
933 static const WCHAR str[] = {'a',0};
954 {0xffffff, 0xffffff},
955 {0x1000000, 0x1000000},
956 {0xffffff, 0x1000000},
957 {0xffffffff, 0xffffffff}
964 BOOL r[sizeof range / sizeof range[0]];
967 {ANSI_CHARSET, 0x30, 0x30, {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
968 {SHIFTJIS_CHARSET, 0x82a0, 0x3042, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
969 {HANGEUL_CHARSET, 0x8141, 0xac02, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
970 {JOHAB_CHARSET, 0x8446, 0x3135, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
971 {GB2312_CHARSET, 0x8141, 0x4e04, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
972 {CHINESEBIG5_CHARSET, 0xa142, 0x3001, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}}
976 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsI)
978 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
982 memset(&lf, 0, sizeof(lf));
983 strcpy(lf.lfFaceName, "System");
986 hfont = CreateFontIndirectA(&lf);
988 hfont = SelectObject(hdc, hfont);
990 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
991 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
993 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
994 ok(!ret, "GetCharABCWidthsI should have failed\n");
996 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
997 ok(!ret, "GetCharABCWidthsI should have failed\n");
999 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1000 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1002 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1003 ok(!ret, "GetCharABCWidthsW should have failed\n");
1005 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1006 ok(!ret, "GetCharABCWidthsW should have failed\n");
1008 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1009 ok(!ret, "GetCharABCWidthsW should have failed\n");
1011 hfont = SelectObject(hdc, hfont);
1012 DeleteObject(hfont);
1014 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1018 UINT code = 0x41, j;
1020 lf.lfFaceName[0] = '\0';
1021 lf.lfCharSet = c[i].cs;
1022 lf.lfPitchAndFamily = 0;
1023 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1025 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1029 memset(a, 0, sizeof a);
1030 memset(w, 0, sizeof w);
1031 hfont = SelectObject(hdc, hfont);
1032 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1033 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1034 memcmp(a, w, sizeof a) == 0,
1035 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1037 memset(a, 0xbb, sizeof a);
1038 ret = pGetCharABCWidthsA(hdc, code, code, a);
1039 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1040 memset(full, 0xcc, sizeof full);
1041 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1042 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1043 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1044 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1046 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1048 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1049 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1050 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1053 hfont = SelectObject(hdc, hfont);
1054 DeleteObject(hfont);
1057 ReleaseDC(NULL, hdc);
1060 static void test_text_extents(void)
1062 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1064 INT i, len, fit1, fit2;
1073 memset(&lf, 0, sizeof(lf));
1074 strcpy(lf.lfFaceName, "Arial");
1077 hfont = CreateFontIndirectA(&lf);
1079 hfont = SelectObject(hdc, hfont);
1080 GetTextMetricsA(hdc, &tm);
1081 GetTextExtentPointA(hdc, "o", 1, &sz);
1082 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1084 SetLastError(0xdeadbeef);
1085 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1086 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1088 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1089 hfont = SelectObject(hdc, hfont);
1090 DeleteObject(hfont);
1096 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1097 extents[0] = 1; /* So that the increasing sequence test will fail
1098 if the extents array is untouched. */
1099 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1100 GetTextExtentPointW(hdc, wt, len, &sz2);
1101 ok(sz1.cy == sz2.cy,
1102 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1103 /* Because of the '\n' in the string GetTextExtentExPoint and
1104 GetTextExtentPoint return different widths under Win2k, but
1105 under WinXP they return the same width. So we don't test that
1108 for (i = 1; i < len; ++i)
1109 ok(extents[i-1] <= extents[i],
1110 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1112 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1113 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1114 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1115 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1116 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1117 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1118 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1119 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1120 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1121 ok(extents[0] == extents[2] && extents[1] == extents[3],
1122 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1123 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1124 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1125 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1126 HeapFree(GetProcessHeap(), 0, extents);
1128 /* extents functions fail with -ve counts (the interesting case being -1) */
1129 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1130 ok(ret == FALSE, "got %d\n", ret);
1131 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1132 ok(ret == FALSE, "got %d\n", ret);
1133 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1134 ok(ret == FALSE, "got %d\n", ret);
1136 /* max_extent = 0 succeeds and returns zero */
1138 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1140 broken(ret == FALSE), /* NT4, 2k */
1143 broken(fit1 == -215), /* NT4, 2k */
1144 "fit = %d\n", fit1);
1145 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1146 ok(ret == TRUE, "got %d\n", ret);
1147 ok(fit2 == 0, "fit = %d\n", fit2);
1149 /* max_extent = -1 is interpreted as a very large width that will
1150 * definitely fit our three characters */
1152 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1153 ok(ret == TRUE, "got %d\n", ret);
1154 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1155 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1156 ok(ret == TRUE, "got %d\n", ret);
1157 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1159 /* max_extent = -2 is interpreted similarly, but the Ansi version
1160 * rejects it while the Unicode one accepts it */
1162 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1163 todo_wine ok(ret == FALSE, "got %d\n", ret);
1164 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1165 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1166 ok(ret == TRUE, "got %d\n", ret);
1167 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1169 hfont = SelectObject(hdc, hfont);
1170 DeleteObject(hfont);
1171 ReleaseDC(NULL, hdc);
1174 static void test_GetGlyphIndices(void)
1181 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1182 WORD glyphs[(sizeof(testtext)/2)-1];
1186 if (!pGetGlyphIndicesW) {
1187 win_skip("GetGlyphIndicesW not available on platform\n");
1193 memset(&lf, 0, sizeof(lf));
1194 strcpy(lf.lfFaceName, "System");
1196 lf.lfCharSet = ANSI_CHARSET;
1198 hfont = CreateFontIndirectA(&lf);
1199 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1200 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1201 if (textm.tmCharSet == ANSI_CHARSET)
1203 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1204 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1205 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1206 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1208 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1209 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1210 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1211 textm.tmDefaultChar, glyphs[4]);
1214 /* FIXME: Write tests for non-ANSI charsets. */
1215 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1217 if(!is_font_installed("Tahoma"))
1219 skip("Tahoma is not installed so skipping this test\n");
1222 memset(&lf, 0, sizeof(lf));
1223 strcpy(lf.lfFaceName, "Tahoma");
1226 hfont = CreateFontIndirectA(&lf);
1227 hOldFont = SelectObject(hdc, hfont);
1228 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1229 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1230 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1231 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1232 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1234 testtext[0] = textm.tmDefaultChar;
1235 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1236 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1237 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1238 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1239 DeleteObject(SelectObject(hdc, hOldFont));
1242 static void test_GetKerningPairs(void)
1244 static const struct kerning_data
1246 const char face_name[LF_FACESIZE];
1248 /* some interesting fields from OUTLINETEXTMETRIC */
1249 LONG tmHeight, tmAscent, tmDescent;
1254 UINT otmsCapEmHeight;
1259 UINT otmusMinimumPPEM;
1260 /* small subset of kerning pairs to test */
1261 DWORD total_kern_pairs;
1262 const KERNINGPAIR kern_pair[26];
1265 {"Arial", 12, 12, 9, 3,
1266 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1269 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1270 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1271 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1272 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1273 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1274 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1275 {933,970,+1},{933,972,-1}
1278 {"Arial", -34, 39, 32, 7,
1279 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1282 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1283 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1284 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1285 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1286 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1287 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1288 {933,970,+2},{933,972,-3}
1291 { "Arial", 120, 120, 97, 23,
1292 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1295 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1296 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1297 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1298 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1299 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1300 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1301 {933,970,+6},{933,972,-10}
1304 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1305 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1306 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1309 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1310 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1311 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1312 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1313 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1314 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1315 {933,970,+54},{933,972,-83}
1321 HFONT hfont, hfont_old;
1322 KERNINGPAIR *kern_pair;
1324 DWORD total_kern_pairs, ret, i, n, matches;
1328 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1329 * which may render this test unusable, so we're trying to avoid that.
1331 SetLastError(0xdeadbeef);
1332 GetKerningPairsW(hdc, 0, NULL);
1333 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1335 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1340 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1342 OUTLINETEXTMETRICW otm;
1345 if (!is_font_installed(kd[i].face_name))
1347 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1351 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1353 memset(&lf, 0, sizeof(lf));
1354 strcpy(lf.lfFaceName, kd[i].face_name);
1355 lf.lfHeight = kd[i].height;
1356 hfont = CreateFontIndirect(&lf);
1359 hfont_old = SelectObject(hdc, hfont);
1361 SetLastError(0xdeadbeef);
1362 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1363 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1364 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1366 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1367 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1368 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1369 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1370 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1371 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1373 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1374 kd[i].otmEMSquare, otm.otmEMSquare);
1375 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1376 kd[i].otmAscent, otm.otmAscent);
1377 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1378 kd[i].otmDescent, otm.otmDescent);
1379 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1380 kd[i].otmLineGap, otm.otmLineGap);
1381 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1382 kd[i].otmMacDescent, otm.otmMacDescent);
1383 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1384 kd[i].otmMacAscent, otm.otmMacAscent);
1386 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1387 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1388 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1389 kd[i].otmsXHeight, otm.otmsXHeight);
1390 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1391 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1392 kd[i].otmMacLineGap, otm.otmMacLineGap);
1393 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1394 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1397 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1398 trace("total_kern_pairs %u\n", total_kern_pairs);
1399 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1401 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1404 SetLastError(0xdeadbeef);
1405 ret = GetKerningPairsW(hdc, 0, kern_pair);
1406 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1407 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1408 ok(ret == 0, "got %u, expected 0\n", ret);
1410 ret = GetKerningPairsW(hdc, 100, NULL);
1411 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1413 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1414 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1416 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1417 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1421 for (n = 0; n < ret; n++)
1424 /* Disabled to limit console spam */
1425 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1426 trace("{'%c','%c',%d},\n",
1427 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1428 for (j = 0; j < kd[i].total_kern_pairs; j++)
1430 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1431 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1433 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1434 "pair %d:%d got %d, expected %d\n",
1435 kern_pair[n].wFirst, kern_pair[n].wSecond,
1436 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1442 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1443 matches, kd[i].total_kern_pairs);
1445 HeapFree(GetProcessHeap(), 0, kern_pair);
1447 SelectObject(hdc, hfont_old);
1448 DeleteObject(hfont);
1454 static void test_height_selection(void)
1456 static const struct font_data
1458 const char face_name[LF_FACESIZE];
1459 int requested_height;
1460 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1463 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1464 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1465 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1466 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1467 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1468 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1469 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1470 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1471 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1472 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1476 HFONT hfont, old_hfont;
1480 hdc = CreateCompatibleDC(0);
1483 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1485 if (!is_truetype_font_installed(fd[i].face_name))
1487 skip("%s is not installed\n", fd[i].face_name);
1491 memset(&lf, 0, sizeof(lf));
1492 lf.lfHeight = fd[i].requested_height;
1493 lf.lfWeight = fd[i].weight;
1494 strcpy(lf.lfFaceName, fd[i].face_name);
1496 hfont = CreateFontIndirect(&lf);
1499 old_hfont = SelectObject(hdc, hfont);
1500 ret = GetTextMetrics(hdc, &tm);
1501 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1502 if(fd[i].dpi == tm.tmDigitizedAspectX)
1504 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1505 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);
1506 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);
1507 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);
1508 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);
1509 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1510 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);
1512 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);
1515 SelectObject(hdc, old_hfont);
1516 DeleteObject(hfont);
1522 static void test_GetOutlineTextMetrics(void)
1524 OUTLINETEXTMETRIC *otm;
1526 HFONT hfont, hfont_old;
1528 DWORD ret, otm_size;
1531 if (!is_font_installed("Arial"))
1533 skip("Arial is not installed\n");
1539 memset(&lf, 0, sizeof(lf));
1540 strcpy(lf.lfFaceName, "Arial");
1542 lf.lfWeight = FW_NORMAL;
1543 lf.lfPitchAndFamily = DEFAULT_PITCH;
1544 lf.lfQuality = PROOF_QUALITY;
1545 hfont = CreateFontIndirect(&lf);
1548 hfont_old = SelectObject(hdc, hfont);
1549 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1550 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1552 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1554 memset(otm, 0xAA, otm_size);
1555 SetLastError(0xdeadbeef);
1556 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1557 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1558 ok(ret == 1 /* Win9x */ ||
1559 ret == otm->otmSize /* XP*/,
1560 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1561 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1563 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1564 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1565 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1566 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1569 memset(otm, 0xAA, otm_size);
1570 SetLastError(0xdeadbeef);
1571 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1572 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1573 ok(ret == 1 /* Win9x */ ||
1574 ret == otm->otmSize /* XP*/,
1575 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1576 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1578 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1579 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1580 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1581 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1584 /* ask about truncated data */
1585 memset(otm, 0xAA, otm_size);
1586 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1587 SetLastError(0xdeadbeef);
1588 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1589 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1590 ok(ret == 1 /* Win9x */ ||
1591 ret == otm->otmSize /* XP*/,
1592 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1593 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1595 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1596 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1597 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1599 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1601 HeapFree(GetProcessHeap(), 0, otm);
1603 SelectObject(hdc, hfont_old);
1604 DeleteObject(hfont);
1609 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1613 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1614 areaWidth = clientArea->right - clientArea->left,
1616 BOOL lastExtent = FALSE;
1617 PSTR pFirstChar, pLastChar;
1623 int GetTextExtentExPointWWidth;
1626 GetTextMetricsA(hdc, &tm);
1627 y = clientArea->top;
1630 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1636 /* if not at the end of the string, ... */
1637 if (*str == '\0') break;
1638 /* ... add the next word to the current extent */
1639 while (*str != '\0' && *str++ != tm.tmBreakChar);
1641 SetTextJustification(hdc, 0, 0);
1642 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1643 } while ((int) size.cx < areaWidth);
1645 /* ignore trailing break chars */
1647 while (*(pLastChar - 1) == tm.tmBreakChar)
1653 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1655 SetTextJustification(hdc, 0, 0);
1656 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1658 /* do not justify the last extent */
1659 if (*str != '\0' && breakCount > 0)
1661 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1662 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1663 justifiedWidth = size.cx;
1665 else lastExtent = TRUE;
1667 /* catch errors and report them */
1668 if (!lastExtent && (justifiedWidth != areaWidth))
1670 memset(error[nErrors].extent, 0, 100);
1671 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1672 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1678 } while (*str && y < clientArea->bottom);
1680 for (e = 0; e < nErrors; e++)
1682 /* The width returned by GetTextExtentPoint32() is exactly the same
1683 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1684 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1685 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1686 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1690 static void test_SetTextJustification(void)
1697 static char testText[] =
1698 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1699 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1700 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1701 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1702 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1703 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1704 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1706 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1707 GetClientRect( hwnd, &clientArea );
1708 hdc = GetDC( hwnd );
1710 memset(&lf, 0, sizeof lf);
1711 lf.lfCharSet = ANSI_CHARSET;
1712 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1713 lf.lfWeight = FW_DONTCARE;
1715 lf.lfQuality = DEFAULT_QUALITY;
1716 lstrcpyA(lf.lfFaceName, "Times New Roman");
1717 hfont = create_font("Times New Roman", &lf);
1718 SelectObject(hdc, hfont);
1720 testJustification(hdc, testText, &clientArea);
1722 DeleteObject(hfont);
1723 ReleaseDC(hwnd, hdc);
1724 DestroyWindow(hwnd);
1727 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1731 HFONT hfont, hfont_old;
1738 assert(count <= 128);
1740 memset(&lf, 0, sizeof(lf));
1742 lf.lfCharSet = charset;
1744 lstrcpyA(lf.lfFaceName, "Arial");
1745 SetLastError(0xdeadbeef);
1746 hfont = CreateFontIndirectA(&lf);
1747 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1750 hfont_old = SelectObject(hdc, hfont);
1752 cs = GetTextCharsetInfo(hdc, &fs, 0);
1753 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1755 SetLastError(0xdeadbeef);
1756 ret = GetTextFaceA(hdc, sizeof(name), name);
1757 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1759 if (charset == SYMBOL_CHARSET)
1761 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1762 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1766 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1767 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1770 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1772 trace("Can't find codepage for charset %d\n", cs);
1776 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1778 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1780 skip("Font code page %d, looking for code page %d\n",
1781 pGdiGetCodePage(hdc), code_page);
1789 WCHAR unicode_buf[128];
1791 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1793 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1795 SetLastError(0xdeadbeef);
1796 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1797 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1798 count, ret, GetLastError());
1804 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1806 SetLastError(0xdeadbeef);
1807 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1808 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1809 count, ret, GetLastError());
1812 SelectObject(hdc, hfont_old);
1813 DeleteObject(hfont);
1820 static void test_font_charset(void)
1822 static struct charset_data
1826 WORD font_idxA[128], font_idxW[128];
1829 { ANSI_CHARSET, 1252 },
1830 { RUSSIAN_CHARSET, 1251 },
1831 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1835 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1837 win_skip("Skipping the font charset test on a Win9x platform\n");
1841 if (!is_font_installed("Arial"))
1843 skip("Arial is not installed\n");
1847 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1849 if (cd[i].charset == SYMBOL_CHARSET)
1851 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1853 skip("Symbol or Wingdings is not installed\n");
1857 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1858 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1859 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1862 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1865 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1866 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1869 skip("Symbol or Wingdings is not installed\n");
1872 static void test_GetFontUnicodeRanges(void)
1876 HFONT hfont, hfont_old;
1881 if (!pGetFontUnicodeRanges)
1883 win_skip("GetFontUnicodeRanges not available before W2K\n");
1887 memset(&lf, 0, sizeof(lf));
1888 lstrcpyA(lf.lfFaceName, "Arial");
1889 hfont = create_font("Arial", &lf);
1892 hfont_old = SelectObject(hdc, hfont);
1894 size = pGetFontUnicodeRanges(NULL, NULL);
1895 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1897 size = pGetFontUnicodeRanges(hdc, NULL);
1898 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1900 gs = HeapAlloc(GetProcessHeap(), 0, size);
1902 size = pGetFontUnicodeRanges(hdc, gs);
1903 ok(size, "GetFontUnicodeRanges failed\n");
1905 if (0) /* Disabled to limit console spam */
1906 for (i = 0; i < gs->cRanges; i++)
1907 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1908 trace("found %u ranges\n", gs->cRanges);
1910 HeapFree(GetProcessHeap(), 0, gs);
1912 SelectObject(hdc, hfont_old);
1913 DeleteObject(hfont);
1914 ReleaseDC(NULL, hdc);
1917 #define MAX_ENUM_FONTS 4096
1919 struct enum_font_data
1922 LOGFONT lf[MAX_ENUM_FONTS];
1925 struct enum_font_dataW
1928 LOGFONTW lf[MAX_ENUM_FONTS];
1931 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1933 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1935 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1937 if (type != TRUETYPE_FONTTYPE) return 1;
1938 if (0) /* Disabled to limit console spam */
1939 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1940 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1941 if (efd->total < MAX_ENUM_FONTS)
1942 efd->lf[efd->total++] = *lf;
1944 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1949 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1951 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1953 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1955 if (type != TRUETYPE_FONTTYPE) return 1;
1956 if (0) /* Disabled to limit console spam */
1957 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1958 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1959 if (efd->total < MAX_ENUM_FONTS)
1960 efd->lf[efd->total++] = *lf;
1962 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1967 static void get_charset_stats(struct enum_font_data *efd,
1968 int *ansi_charset, int *symbol_charset,
1969 int *russian_charset)
1974 *symbol_charset = 0;
1975 *russian_charset = 0;
1977 for (i = 0; i < efd->total; i++)
1979 switch (efd->lf[i].lfCharSet)
1984 case SYMBOL_CHARSET:
1985 (*symbol_charset)++;
1987 case RUSSIAN_CHARSET:
1988 (*russian_charset)++;
1994 static void get_charset_statsW(struct enum_font_dataW *efd,
1995 int *ansi_charset, int *symbol_charset,
1996 int *russian_charset)
2001 *symbol_charset = 0;
2002 *russian_charset = 0;
2004 for (i = 0; i < efd->total; i++)
2006 switch (efd->lf[i].lfCharSet)
2011 case SYMBOL_CHARSET:
2012 (*symbol_charset)++;
2014 case RUSSIAN_CHARSET:
2015 (*russian_charset)++;
2021 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2023 struct enum_font_data efd;
2024 struct enum_font_dataW efdw;
2027 int i, ret, ansi_charset, symbol_charset, russian_charset;
2029 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2031 if (*font_name && !is_truetype_font_installed(font_name))
2033 skip("%s is not installed\n", font_name);
2039 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2040 * while EnumFontFamiliesEx doesn't.
2042 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2045 * Use EnumFontFamiliesW since win98 crashes when the
2046 * second parameter is NULL using EnumFontFamilies
2049 SetLastError(0xdeadbeef);
2050 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2051 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2054 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2055 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2056 ansi_charset, symbol_charset, russian_charset);
2057 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2058 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2059 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2060 ok(russian_charset > 0 ||
2061 broken(russian_charset == 0), /* NT4 */
2062 "NULL family should enumerate RUSSIAN_CHARSET\n");
2066 SetLastError(0xdeadbeef);
2067 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2068 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2071 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2072 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2073 ansi_charset, symbol_charset, russian_charset);
2074 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2075 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2076 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2077 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2082 SetLastError(0xdeadbeef);
2083 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2084 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2085 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2086 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2087 ansi_charset, symbol_charset, russian_charset,
2088 *font_name ? font_name : "<empty>");
2090 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2092 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2093 for (i = 0; i < efd.total; i++)
2095 /* FIXME: remove completely once Wine is fixed */
2096 if (efd.lf[i].lfCharSet != font_charset)
2099 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2102 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2103 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2104 font_name, efd.lf[i].lfFaceName);
2107 memset(&lf, 0, sizeof(lf));
2108 lf.lfCharSet = ANSI_CHARSET;
2109 lstrcpy(lf.lfFaceName, font_name);
2111 SetLastError(0xdeadbeef);
2112 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2113 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2114 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2115 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2116 ansi_charset, symbol_charset, russian_charset,
2117 *font_name ? font_name : "<empty>");
2118 if (font_charset == SYMBOL_CHARSET)
2121 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2123 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2127 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2128 for (i = 0; i < efd.total; i++)
2130 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2132 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2133 font_name, efd.lf[i].lfFaceName);
2137 /* DEFAULT_CHARSET should enumerate all available charsets */
2138 memset(&lf, 0, sizeof(lf));
2139 lf.lfCharSet = DEFAULT_CHARSET;
2140 lstrcpy(lf.lfFaceName, font_name);
2142 SetLastError(0xdeadbeef);
2143 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2144 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2145 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2146 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2147 ansi_charset, symbol_charset, russian_charset,
2148 *font_name ? font_name : "<empty>");
2149 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2150 for (i = 0; i < efd.total; i++)
2153 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2154 font_name, efd.lf[i].lfFaceName);
2158 switch (font_charset)
2161 ok(ansi_charset > 0,
2162 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2164 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2165 ok(russian_charset > 0,
2166 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2168 case SYMBOL_CHARSET:
2170 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2172 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2173 ok(!russian_charset,
2174 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2176 case DEFAULT_CHARSET:
2177 ok(ansi_charset > 0,
2178 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2179 ok(symbol_charset > 0,
2180 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2181 ok(russian_charset > 0,
2182 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2188 ok(ansi_charset > 0,
2189 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2190 ok(symbol_charset > 0,
2191 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2192 ok(russian_charset > 0,
2193 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2196 memset(&lf, 0, sizeof(lf));
2197 lf.lfCharSet = SYMBOL_CHARSET;
2198 lstrcpy(lf.lfFaceName, font_name);
2200 SetLastError(0xdeadbeef);
2201 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2202 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2203 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2204 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2205 ansi_charset, symbol_charset, russian_charset,
2206 *font_name ? font_name : "<empty>");
2207 if (*font_name && font_charset == ANSI_CHARSET)
2208 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2211 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2212 for (i = 0; i < efd.total; i++)
2214 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2216 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2217 font_name, efd.lf[i].lfFaceName);
2221 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2222 ok(symbol_charset > 0,
2223 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2224 ok(!russian_charset,
2225 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2231 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2233 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2235 if (type != TRUETYPE_FONTTYPE) return 1;
2237 if (efd->total < MAX_ENUM_FONTS)
2238 efd->lf[efd->total++] = *lf;
2240 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2245 static void test_EnumFontFamiliesEx_default_charset(void)
2247 struct enum_font_data efd;
2248 LOGFONT gui_font, enum_font;
2252 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2253 ok(ret, "GetObject failed.\n");
2260 memset(&enum_font, 0, sizeof(enum_font));
2261 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2262 enum_font.lfCharSet = DEFAULT_CHARSET;
2263 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2266 if (efd.total == 0) {
2267 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2270 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2272 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2273 "(%s) got charset %d expected %d\n",
2274 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2279 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2281 HFONT hfont, hfont_prev;
2283 GLYPHMETRICS gm1, gm2;
2287 if(!pGetGlyphIndicesA)
2290 /* negative widths are handled just as positive ones */
2291 lf2.lfWidth = -lf->lfWidth;
2293 SetLastError(0xdeadbeef);
2294 hfont = CreateFontIndirectA(lf);
2295 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2296 check_font("original", lf, hfont);
2298 hfont_prev = SelectObject(hdc, hfont);
2300 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2301 if (ret == GDI_ERROR || idx == 0xffff)
2303 SelectObject(hdc, hfont_prev);
2304 DeleteObject(hfont);
2305 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2309 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2310 memset(&gm1, 0xab, sizeof(gm1));
2311 SetLastError(0xdeadbeef);
2312 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2313 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2315 SelectObject(hdc, hfont_prev);
2316 DeleteObject(hfont);
2318 SetLastError(0xdeadbeef);
2319 hfont = CreateFontIndirectA(&lf2);
2320 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2321 check_font("negative width", &lf2, hfont);
2323 hfont_prev = SelectObject(hdc, hfont);
2325 memset(&gm2, 0xbb, sizeof(gm2));
2326 SetLastError(0xdeadbeef);
2327 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2328 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2330 SelectObject(hdc, hfont_prev);
2331 DeleteObject(hfont);
2333 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2334 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2335 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2336 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2337 gm1.gmCellIncX == gm2.gmCellIncX &&
2338 gm1.gmCellIncY == gm2.gmCellIncY,
2339 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2340 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2341 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2342 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2343 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2346 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2347 #include "pshpack2.h"
2351 SHORT xAvgCharWidth;
2352 USHORT usWeightClass;
2353 USHORT usWidthClass;
2355 SHORT ySubscriptXSize;
2356 SHORT ySubscriptYSize;
2357 SHORT ySubscriptXOffset;
2358 SHORT ySubscriptYOffset;
2359 SHORT ySuperscriptXSize;
2360 SHORT ySuperscriptYSize;
2361 SHORT ySuperscriptXOffset;
2362 SHORT ySuperscriptYOffset;
2363 SHORT yStrikeoutSize;
2364 SHORT yStrikeoutPosition;
2367 ULONG ulUnicodeRange1;
2368 ULONG ulUnicodeRange2;
2369 ULONG ulUnicodeRange3;
2370 ULONG ulUnicodeRange4;
2373 USHORT usFirstCharIndex;
2374 USHORT usLastCharIndex;
2375 /* According to the Apple spec, original version didn't have the below fields,
2376 * version numbers were taken from the OpenType spec.
2378 /* version 0 (TrueType 1.5) */
2379 USHORT sTypoAscender;
2380 USHORT sTypoDescender;
2381 USHORT sTypoLineGap;
2383 USHORT usWinDescent;
2384 /* version 1 (TrueType 1.66) */
2385 ULONG ulCodePageRange1;
2386 ULONG ulCodePageRange2;
2387 /* version 2 (OpenType 1.2) */
2390 USHORT usDefaultChar;
2392 USHORT usMaxContext;
2394 #include "poppack.h"
2396 #ifdef WORDS_BIGENDIAN
2397 #define GET_BE_WORD(x) (x)
2398 #define GET_BE_DWORD(x) (x)
2400 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2401 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2404 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2405 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2406 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2407 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2408 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2409 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2422 } cmap_encoding_record;
2430 BYTE glyph_ids[256];
2440 USHORT search_range;
2441 USHORT entry_selector;
2444 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2447 USHORT start_count[seg_countx2 / 2];
2448 USHORT id_delta[seg_countx2 / 2];
2449 USHORT id_range_offset[seg_countx2 / 2];
2459 USHORT id_range_offset;
2460 } cmap_format_4_seg;
2462 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2464 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2465 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2466 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2467 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2468 os2->panose.bWeight, os2->panose.bProportion);
2471 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2474 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2478 for(i = 0; i < 256; i++)
2480 if(cmap->glyph_ids[i] == 0) continue;
2482 if(*first == 256) *first = i;
2484 if(*first == 256) return FALSE;
2488 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2490 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2491 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2492 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2493 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2494 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2497 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2500 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2501 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2502 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2506 for(i = 0; i < seg_count; i++)
2509 cmap_format_4_seg seg;
2511 get_seg4(cmap, i, &seg);
2512 for(code = seg.start_count; code <= seg.end_count; code++)
2514 if(seg.id_range_offset == 0)
2515 index = (seg.id_delta + code) & 0xffff;
2518 index = seg.id_range_offset / 2
2519 + code - seg.start_count
2522 /* some fonts have broken last segment */
2523 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2524 index = GET_BE_WORD(glyph_ids[index]);
2527 trace("segment %04x/%04x index %04x points to nowhere\n",
2528 seg.start_count, seg.end_count, index);
2531 if(index) index += seg.id_delta;
2533 if(*first == 0x10000)
2534 *last = *first = code;
2540 if(*first == 0x10000) return FALSE;
2544 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2547 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2549 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2551 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2552 return (BYTE *)header + GET_BE_DWORD(record->offset);
2565 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2568 cmap_header *header;
2573 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2574 ok(size != GDI_ERROR, "no cmap table found\n");
2575 if(size == GDI_ERROR) return FALSE;
2577 header = HeapAlloc(GetProcessHeap(), 0, size);
2578 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2579 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2580 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2582 cmap = get_cmap(header, 3, 1);
2584 *cmap_type = cmap_ms_unicode;
2587 cmap = get_cmap(header, 3, 0);
2588 if(cmap) *cmap_type = cmap_ms_symbol;
2592 *cmap_type = cmap_none;
2596 format = GET_BE_WORD(*(WORD *)cmap);
2600 r = get_first_last_from_cmap0(cmap, first, last);
2603 r = get_first_last_from_cmap4(cmap, first, last, size);
2606 trace("unhandled cmap format %d\n", format);
2611 HeapFree(GetProcessHeap(), 0, header);
2615 #define TT_PLATFORM_MICROSOFT 3
2616 #define TT_MS_ID_UNICODE_CS 1
2617 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2618 #define TT_NAME_ID_FULL_NAME 4
2620 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2622 struct sfnt_name_header
2625 USHORT number_of_record;
2626 USHORT storage_offset;
2638 LONG size, offset, length;
2644 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2645 ok(size != GDI_ERROR, "no name table found\n");
2646 if(size == GDI_ERROR) return FALSE;
2648 data = HeapAlloc(GetProcessHeap(), 0, size);
2649 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2650 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2652 header = (void *)data;
2653 header->format = GET_BE_WORD(header->format);
2654 header->number_of_record = GET_BE_WORD(header->number_of_record);
2655 header->storage_offset = GET_BE_WORD(header->storage_offset);
2656 if (header->format != 0)
2658 trace("got format %u\n", header->format);
2661 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2663 trace("number records out of range: %d\n", header->number_of_record);
2666 if (header->storage_offset >= size)
2668 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2672 entry = (void *)&header[1];
2673 for (i = 0; i < header->number_of_record; i++)
2675 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2676 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2677 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2678 GET_BE_WORD(entry[i].name_id) != name_id)
2683 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2684 length = GET_BE_WORD(entry[i].length);
2685 if (offset + length > size)
2687 trace("entry %d is out of range\n", i);
2690 if (length >= out_size)
2692 trace("buffer too small for entry %d\n", i);
2696 name = (WCHAR *)(data + offset);
2697 for (c = 0; c < length / 2; c++)
2698 out_buf[c] = GET_BE_WORD(name[c]);
2706 HeapFree(GetProcessHeap(), 0, data);
2710 static void test_text_metrics(const LOGFONTA *lf)
2713 HFONT hfont, hfont_old;
2717 const char *font_name = lf->lfFaceName;
2718 DWORD cmap_first = 0, cmap_last = 0;
2719 cmap_type cmap_type;
2720 BOOL sys_lang_non_english;
2722 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2725 SetLastError(0xdeadbeef);
2726 hfont = CreateFontIndirectA(lf);
2727 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2729 hfont_old = SelectObject(hdc, hfont);
2731 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2732 if (size == GDI_ERROR)
2734 trace("OS/2 chunk was not found\n");
2737 if (size > sizeof(tt_os2))
2739 trace("got too large OS/2 chunk of size %u\n", size);
2740 size = sizeof(tt_os2);
2743 memset(&tt_os2, 0, sizeof(tt_os2));
2744 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2745 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2747 SetLastError(0xdeadbeef);
2748 ret = GetTextMetricsA(hdc, &tmA);
2749 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2751 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2753 skip("Unable to retrieve first and last glyphs from cmap\n");
2757 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2758 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2759 UINT os2_first_char, os2_last_char, default_char, break_char;
2763 version = GET_BE_WORD(tt_os2.version);
2765 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2766 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2767 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2768 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2770 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2771 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2772 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2774 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2779 case 1257: /* Baltic */
2780 expect_last_W = 0xf8fd;
2783 expect_last_W = 0xf0ff;
2785 expect_break_W = 0x20;
2786 expect_default_W = expect_break_W - 1;
2787 expect_first_A = 0x1e;
2788 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2792 expect_first_W = cmap_first;
2793 expect_last_W = min(cmap_last, os2_last_char);
2794 if(os2_first_char <= 1)
2795 expect_break_W = os2_first_char + 2;
2796 else if(os2_first_char > 0xff)
2797 expect_break_W = 0x20;
2799 expect_break_W = os2_first_char;
2800 expect_default_W = expect_break_W - 1;
2801 expect_first_A = expect_default_W - 1;
2802 expect_last_A = min(expect_last_W, 0xff);
2804 expect_break_A = expect_break_W;
2805 expect_default_A = expect_default_W;
2807 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2808 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2809 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2810 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2811 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2813 ok(tmA.tmFirstChar == expect_first_A ||
2814 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2815 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2816 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2817 ok(tmA.tmLastChar == expect_last_A ||
2818 tmA.tmLastChar == 0xff /* win9x */,
2819 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2821 skip("tmLastChar is DBCS lead byte\n");
2822 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2823 font_name, tmA.tmBreakChar, expect_break_A);
2824 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2825 "A: tmDefaultChar for %s got %02x expected %02x\n",
2826 font_name, tmA.tmDefaultChar, expect_default_A);
2829 SetLastError(0xdeadbeef);
2830 ret = GetTextMetricsW(hdc, &tmW);
2831 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2832 "GetTextMetricsW error %u\n", GetLastError());
2835 /* Wine uses the os2 first char */
2836 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2837 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2838 font_name, tmW.tmFirstChar, expect_first_W);
2840 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2841 font_name, tmW.tmFirstChar, expect_first_W);
2843 /* Wine uses the os2 last char */
2844 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2845 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2846 font_name, tmW.tmLastChar, expect_last_W);
2848 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2849 font_name, tmW.tmLastChar, expect_last_W);
2850 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2851 font_name, tmW.tmBreakChar, expect_break_W);
2852 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2853 "W: tmDefaultChar for %s got %02x expected %02x\n",
2854 font_name, tmW.tmDefaultChar, expect_default_W);
2856 /* Test the aspect ratio while we have tmW */
2857 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2858 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2859 tmW.tmDigitizedAspectX, ret);
2860 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2861 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2862 tmW.tmDigitizedAspectX, ret);
2866 /* test FF_ values */
2867 switch(tt_os2.panose.bFamilyType)
2871 case PAN_FAMILY_TEXT_DISPLAY:
2872 case PAN_FAMILY_PICTORIAL:
2874 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2875 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2877 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2880 switch(tt_os2.panose.bSerifStyle)
2885 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2888 case PAN_SERIF_COVE:
2889 case PAN_SERIF_OBTUSE_COVE:
2890 case PAN_SERIF_SQUARE_COVE:
2891 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2892 case PAN_SERIF_SQUARE:
2893 case PAN_SERIF_THIN:
2894 case PAN_SERIF_BONE:
2895 case PAN_SERIF_EXAGGERATED:
2896 case PAN_SERIF_TRIANGLE:
2897 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2900 case PAN_SERIF_NORMAL_SANS:
2901 case PAN_SERIF_OBTUSE_SANS:
2902 case PAN_SERIF_PERP_SANS:
2903 case PAN_SERIF_FLARED:
2904 case PAN_SERIF_ROUNDED:
2905 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2910 case PAN_FAMILY_SCRIPT:
2911 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2914 case PAN_FAMILY_DECORATIVE:
2915 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2919 test_negative_width(hdc, lf);
2922 SelectObject(hdc, hfont_old);
2923 DeleteObject(hfont);
2928 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2930 INT *enumed = (INT *)lParam;
2932 if (type == TRUETYPE_FONTTYPE)
2935 test_text_metrics(lf);
2940 static void test_GetTextMetrics(void)
2946 /* Report only once */
2947 if(!pGetGlyphIndicesA)
2948 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2952 memset(&lf, 0, sizeof(lf));
2953 lf.lfCharSet = DEFAULT_CHARSET;
2955 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2956 trace("Tested metrics of %d truetype fonts\n", enumed);
2961 static void test_nonexistent_font(void)
2969 { "Times New Roman Baltic", 186 },
2970 { "Times New Roman CE", 238 },
2971 { "Times New Roman CYR", 204 },
2972 { "Times New Roman Greek", 161 },
2973 { "Times New Roman TUR", 162 }
2979 INT cs, expected_cs, i;
2980 char buf[LF_FACESIZE];
2982 if (!is_truetype_font_installed("Arial") ||
2983 !is_truetype_font_installed("Times New Roman"))
2985 skip("Arial or Times New Roman not installed\n");
2989 expected_cs = GetACP();
2990 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2992 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2995 expected_cs = csi.ciCharset;
2996 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3000 memset(&lf, 0, sizeof(lf));
3002 lf.lfWeight = FW_REGULAR;
3003 lf.lfCharSet = ANSI_CHARSET;
3004 lf.lfPitchAndFamily = FF_SWISS;
3005 strcpy(lf.lfFaceName, "Nonexistent font");
3006 hfont = CreateFontIndirectA(&lf);
3007 hfont = SelectObject(hdc, hfont);
3008 GetTextFaceA(hdc, sizeof(buf), buf);
3009 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3010 cs = GetTextCharset(hdc);
3011 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3012 DeleteObject(SelectObject(hdc, hfont));
3014 memset(&lf, 0, sizeof(lf));
3016 lf.lfWeight = FW_DONTCARE;
3017 strcpy(lf.lfFaceName, "Nonexistent font");
3018 hfont = CreateFontIndirectA(&lf);
3019 hfont = SelectObject(hdc, hfont);
3020 GetTextFaceA(hdc, sizeof(buf), buf);
3021 todo_wine /* Wine uses Arial for all substitutions */
3022 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3023 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3024 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3026 cs = GetTextCharset(hdc);
3027 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3028 DeleteObject(SelectObject(hdc, hfont));
3030 memset(&lf, 0, sizeof(lf));
3032 lf.lfWeight = FW_REGULAR;
3033 strcpy(lf.lfFaceName, "Nonexistent font");
3034 hfont = CreateFontIndirectA(&lf);
3035 hfont = SelectObject(hdc, hfont);
3036 GetTextFaceA(hdc, sizeof(buf), buf);
3037 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3038 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3039 cs = GetTextCharset(hdc);
3040 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3041 DeleteObject(SelectObject(hdc, hfont));
3043 memset(&lf, 0, sizeof(lf));
3045 lf.lfWeight = FW_DONTCARE;
3046 strcpy(lf.lfFaceName, "Times New Roman");
3047 hfont = CreateFontIndirectA(&lf);
3048 hfont = SelectObject(hdc, hfont);
3049 GetTextFaceA(hdc, sizeof(buf), buf);
3050 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3051 cs = GetTextCharset(hdc);
3052 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3053 DeleteObject(SelectObject(hdc, hfont));
3055 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3057 memset(&lf, 0, sizeof(lf));
3059 lf.lfWeight = FW_REGULAR;
3060 strcpy(lf.lfFaceName, font_subst[i].name);
3061 hfont = CreateFontIndirectA(&lf);
3062 hfont = SelectObject(hdc, hfont);
3063 cs = GetTextCharset(hdc);
3064 if (font_subst[i].charset == expected_cs)
3066 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3067 GetTextFaceA(hdc, sizeof(buf), buf);
3068 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3072 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3073 GetTextFaceA(hdc, sizeof(buf), buf);
3074 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3075 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3077 DeleteObject(SelectObject(hdc, hfont));
3079 memset(&lf, 0, sizeof(lf));
3081 lf.lfWeight = FW_DONTCARE;
3082 strcpy(lf.lfFaceName, font_subst[i].name);
3083 hfont = CreateFontIndirectA(&lf);
3084 hfont = SelectObject(hdc, hfont);
3085 GetTextFaceA(hdc, sizeof(buf), buf);
3086 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3087 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3088 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3089 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3090 "got %s for font %s\n", buf, font_subst[i].name);
3091 cs = GetTextCharset(hdc);
3092 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3093 DeleteObject(SelectObject(hdc, hfont));
3099 static void test_GdiRealizationInfo(void)
3104 HFONT hfont, hfont_old;
3107 if(!pGdiRealizationInfo)
3109 win_skip("GdiRealizationInfo not available\n");
3115 memset(info, 0xcc, sizeof(info));
3116 r = pGdiRealizationInfo(hdc, info);
3117 ok(r != 0, "ret 0\n");
3118 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3119 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3121 if (!is_truetype_font_installed("Arial"))
3123 skip("skipping GdiRealizationInfo with truetype font\n");
3127 memset(&lf, 0, sizeof(lf));
3128 strcpy(lf.lfFaceName, "Arial");
3130 lf.lfWeight = FW_NORMAL;
3131 hfont = CreateFontIndirectA(&lf);
3132 hfont_old = SelectObject(hdc, hfont);
3134 memset(info, 0xcc, sizeof(info));
3135 r = pGdiRealizationInfo(hdc, info);
3136 ok(r != 0, "ret 0\n");
3137 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3138 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3140 DeleteObject(SelectObject(hdc, hfont_old));
3146 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3147 the nul in the count of characters copied when the face name buffer is not
3148 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3149 always includes it. */
3150 static void test_GetTextFace(void)
3152 static const char faceA[] = "Tahoma";
3153 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3156 char bufA[LF_FACESIZE];
3157 WCHAR bufW[LF_FACESIZE];
3162 if(!is_font_installed("Tahoma"))
3164 skip("Tahoma is not installed so skipping this test\n");
3169 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3170 f = CreateFontIndirectA(&fA);
3171 ok(f != NULL, "CreateFontIndirectA failed\n");
3174 g = SelectObject(dc, f);
3175 n = GetTextFaceA(dc, sizeof bufA, bufA);
3176 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3177 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3179 /* Play with the count arg. */
3181 n = GetTextFaceA(dc, 0, bufA);
3182 ok(n == 0, "GetTextFaceA returned %d\n", n);
3183 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3186 n = GetTextFaceA(dc, 1, bufA);
3187 ok(n == 0, "GetTextFaceA returned %d\n", n);
3188 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3190 bufA[0] = 'x'; bufA[1] = 'y';
3191 n = GetTextFaceA(dc, 2, bufA);
3192 ok(n == 1, "GetTextFaceA returned %d\n", n);
3193 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3195 n = GetTextFaceA(dc, 0, NULL);
3196 ok(n == sizeof faceA ||
3197 broken(n == 0), /* win98, winMe */
3198 "GetTextFaceA returned %d\n", n);
3200 DeleteObject(SelectObject(dc, g));
3201 ReleaseDC(NULL, dc);
3204 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3205 SetLastError(0xdeadbeef);
3206 f = CreateFontIndirectW(&fW);
3207 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3209 win_skip("CreateFontIndirectW is not implemented\n");
3212 ok(f != NULL, "CreateFontIndirectW failed\n");
3215 g = SelectObject(dc, f);
3216 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3217 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3218 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3220 /* Play with the count arg. */
3222 n = GetTextFaceW(dc, 0, bufW);
3223 ok(n == 0, "GetTextFaceW returned %d\n", n);
3224 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3227 n = GetTextFaceW(dc, 1, bufW);
3228 ok(n == 1, "GetTextFaceW returned %d\n", n);
3229 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3231 bufW[0] = 'x'; bufW[1] = 'y';
3232 n = GetTextFaceW(dc, 2, bufW);
3233 ok(n == 2, "GetTextFaceW returned %d\n", n);
3234 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3236 n = GetTextFaceW(dc, 0, NULL);
3237 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3239 DeleteObject(SelectObject(dc, g));
3240 ReleaseDC(NULL, dc);
3243 static void test_orientation(void)
3245 static const char test_str[11] = "Test String";
3248 HFONT hfont, old_hfont;
3251 if (!is_truetype_font_installed("Arial"))
3253 skip("Arial is not installed\n");
3257 hdc = CreateCompatibleDC(0);
3258 memset(&lf, 0, sizeof(lf));
3259 lstrcpyA(lf.lfFaceName, "Arial");
3261 lf.lfOrientation = lf.lfEscapement = 900;
3262 hfont = create_font("orientation", &lf);
3263 old_hfont = SelectObject(hdc, hfont);
3264 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3265 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3266 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3267 SelectObject(hdc, old_hfont);
3268 DeleteObject(hfont);
3272 static void test_oemcharset(void)
3276 HFONT hfont, old_hfont;
3279 hdc = CreateCompatibleDC(0);
3280 ZeroMemory(&lf, sizeof(lf));
3282 lf.lfCharSet = OEM_CHARSET;
3283 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3284 lstrcpyA(lf.lfFaceName, "Terminal");
3285 hfont = CreateFontIndirectA(&lf);
3286 old_hfont = SelectObject(hdc, hfont);
3287 charset = GetTextCharset(hdc);
3289 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3290 hfont = SelectObject(hdc, old_hfont);
3291 GetObjectA(hfont, sizeof(clf), &clf);
3292 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3293 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3294 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3295 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3296 DeleteObject(hfont);
3300 static void test_GetGlyphOutline(void)
3303 GLYPHMETRICS gm, gm2;
3305 HFONT hfont, old_hfont;
3314 {ANSI_CHARSET, 0x30, 0x30},
3315 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3316 {HANGEUL_CHARSET, 0x8141, 0xac02},
3317 {JOHAB_CHARSET, 0x8446, 0x3135},
3318 {GB2312_CHARSET, 0x8141, 0x4e04},
3319 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3323 if (!is_truetype_font_installed("Tahoma"))
3325 skip("Tahoma is not installed\n");
3329 hdc = CreateCompatibleDC(0);
3330 memset(&lf, 0, sizeof(lf));
3332 lstrcpyA(lf.lfFaceName, "Tahoma");
3333 SetLastError(0xdeadbeef);
3334 hfont = CreateFontIndirectA(&lf);
3335 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3336 old_hfont = SelectObject(hdc, hfont);
3338 memset(&gm, 0, sizeof(gm));
3339 SetLastError(0xdeadbeef);
3340 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3341 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3343 memset(&gm, 0, sizeof(gm));
3344 SetLastError(0xdeadbeef);
3345 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3346 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3347 ok(GetLastError() == 0xdeadbeef ||
3348 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3349 "expected 0xdeadbeef, got %u\n", GetLastError());
3351 memset(&gm, 0, sizeof(gm));
3352 SetLastError(0xdeadbeef);
3353 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3354 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3355 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3357 memset(&gm, 0, sizeof(gm));
3358 SetLastError(0xdeadbeef);
3359 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3360 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3362 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3363 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3366 /* test for needed buffer size request on space char */
3367 memset(&gm, 0, sizeof(gm));
3368 SetLastError(0xdeadbeef);
3369 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3370 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3371 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3373 /* requesting buffer size for space char + error */
3374 memset(&gm, 0, sizeof(gm));
3375 SetLastError(0xdeadbeef);
3376 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3377 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3379 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3380 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3383 SelectObject(hdc, old_hfont);
3384 DeleteObject(hfont);
3386 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3388 lf.lfFaceName[0] = '\0';
3389 lf.lfCharSet = c[i].cs;
3390 lf.lfPitchAndFamily = 0;
3391 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3393 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3397 old_hfont = SelectObject(hdc, hfont);
3399 /* expected to ignore superfluous bytes (sigle-byte character) */
3400 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3401 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3402 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3404 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3405 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3406 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3408 /* expected to ignore superfluous bytes (double-byte character) */
3409 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3410 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3411 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3412 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3414 /* expected to match wide-char version results */
3415 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3416 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3418 hfont = SelectObject(hdc, old_hfont);
3419 DeleteObject(hfont);
3425 /* bug #9995: there is a limit to the character width that can be specified */
3426 static void test_GetTextMetrics2(const char *fontname, int font_height)
3432 int ave_width, height, width, ratio, scale;
3434 if (!is_truetype_font_installed( fontname)) {
3435 skip("%s is not installed\n", fontname);
3438 hdc = CreateCompatibleDC(0);
3439 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3440 /* select width = 0 */
3441 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3442 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3443 DEFAULT_QUALITY, VARIABLE_PITCH,
3445 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3446 of = SelectObject( hdc, hf);
3447 ret = GetTextMetricsA( hdc, &tm);
3448 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3449 height = tm.tmHeight;
3450 ave_width = tm.tmAveCharWidth;
3451 SelectObject( hdc, of);
3454 trace("height %d, ave width %d\n", height, ave_width);
3456 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3458 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3459 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3460 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3461 ok(hf != 0, "CreateFont failed\n");
3462 of = SelectObject(hdc, hf);
3463 ret = GetTextMetrics(hdc, &tm);
3464 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3465 SelectObject(hdc, of);
3468 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3474 ratio = width / height;
3475 scale = width / ave_width;
3477 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3478 width, height, ratio, width, ave_width, scale);
3480 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3483 static void test_CreateFontIndirect(void)
3485 LOGFONTA lf, getobj_lf;
3488 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3490 memset(&lf, 0, sizeof(lf));
3491 lf.lfCharSet = ANSI_CHARSET;
3492 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3495 lf.lfQuality = DEFAULT_QUALITY;
3496 lf.lfItalic = FALSE;
3497 lf.lfWeight = FW_DONTCARE;
3499 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3501 lstrcpyA(lf.lfFaceName, TestName[i]);
3502 hfont = CreateFontIndirectA(&lf);
3503 ok(hfont != 0, "CreateFontIndirectA failed\n");
3504 SetLastError(0xdeadbeef);
3505 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3506 ok(ret, "GetObject failed: %d\n", GetLastError());
3507 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3508 ok(lf.lfWeight == getobj_lf.lfWeight ||
3509 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3510 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3511 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3512 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3513 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3514 DeleteObject(hfont);
3518 static void test_CreateFontIndirectEx(void)
3520 ENUMLOGFONTEXDVA lfex;
3523 if (!pCreateFontIndirectExA)
3525 win_skip("CreateFontIndirectExA is not available\n");
3529 if (!is_truetype_font_installed("Arial"))
3531 skip("Arial is not installed\n");
3535 SetLastError(0xdeadbeef);
3536 hfont = pCreateFontIndirectExA(NULL);
3537 ok(hfont == NULL, "got %p\n", hfont);
3538 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3540 memset(&lfex, 0, sizeof(lfex));
3541 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3542 hfont = pCreateFontIndirectExA(&lfex);
3543 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3545 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3546 DeleteObject(hfont);
3549 static void free_font(void *font)
3551 UnmapViewOfFile(font);
3554 static void *load_font(const char *font_name, DWORD *font_size)
3556 char file_name[MAX_PATH];
3557 HANDLE file, mapping;
3560 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3561 strcat(file_name, "\\fonts\\");
3562 strcat(file_name, font_name);
3564 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3565 if (file == INVALID_HANDLE_VALUE) return NULL;
3567 *font_size = GetFileSize(file, NULL);
3569 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3576 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3579 CloseHandle(mapping);
3583 static void test_AddFontMemResource(void)
3586 DWORD font_size, num_fonts;
3590 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3592 win_skip("AddFontMemResourceEx is not available on this platform\n");
3596 font = load_font("sserife.fon", &font_size);
3599 skip("Unable to locate and load font sserife.fon\n");
3603 SetLastError(0xdeadbeef);
3604 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3605 ok(!ret, "AddFontMemResourceEx should fail\n");
3606 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3607 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3610 SetLastError(0xdeadbeef);
3611 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3612 ok(!ret, "AddFontMemResourceEx should fail\n");
3613 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3614 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3617 SetLastError(0xdeadbeef);
3618 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3619 ok(!ret, "AddFontMemResourceEx should fail\n");
3620 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3621 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3624 SetLastError(0xdeadbeef);
3625 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3626 ok(!ret, "AddFontMemResourceEx should fail\n");
3627 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3628 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3631 SetLastError(0xdeadbeef);
3632 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3633 ok(!ret, "AddFontMemResourceEx should fail\n");
3634 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3635 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3638 SetLastError(0xdeadbeef);
3639 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3640 ok(!ret, "AddFontMemResourceEx should fail\n");
3641 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3642 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3645 num_fonts = 0xdeadbeef;
3646 SetLastError(0xdeadbeef);
3647 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3648 ok(!ret, "AddFontMemResourceEx should fail\n");
3649 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3650 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3652 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3654 if (0) /* hangs under windows 2000 */
3656 num_fonts = 0xdeadbeef;
3657 SetLastError(0xdeadbeef);
3658 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3659 ok(!ret, "AddFontMemResourceEx should fail\n");
3660 ok(GetLastError() == 0xdeadbeef,
3661 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3663 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3666 num_fonts = 0xdeadbeef;
3667 SetLastError(0xdeadbeef);
3668 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3669 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3670 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3671 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3675 SetLastError(0xdeadbeef);
3676 bRet = pRemoveFontMemResourceEx(ret);
3677 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3679 /* test invalid pointer to number of loaded fonts */
3680 font = load_font("sserife.fon", &font_size);
3681 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3683 SetLastError(0xdeadbeef);
3684 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3685 ok(!ret, "AddFontMemResourceEx should fail\n");
3686 ok(GetLastError() == 0xdeadbeef,
3687 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3690 SetLastError(0xdeadbeef);
3691 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3692 ok(!ret, "AddFontMemResourceEx should fail\n");
3693 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3694 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3700 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3704 if (type != TRUETYPE_FONTTYPE) return 1;
3706 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3708 lf = (LOGFONT *)lparam;
3713 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3718 if (type != TRUETYPE_FONTTYPE) return 1;
3720 lf = (LOGFONT *)lparam;
3721 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3724 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3731 static void test_EnumFonts(void)
3737 if (!is_truetype_font_installed("Arial"))
3739 skip("Arial is not installed\n");
3743 /* Windows uses localized font face names, so Arial Bold won't be found */
3744 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3746 skip("User locale is not English, skipping the test\n");
3750 hdc = CreateCompatibleDC(0);
3752 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3753 ok(!ret, "font Arial is not enumerated\n");
3754 ret = strcmp(lf.lfFaceName, "Arial");
3755 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3756 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3758 lstrcpy(lf.lfFaceName, "Arial");
3759 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3760 ok(!ret, "font Arial is not enumerated\n");
3761 ret = strcmp(lf.lfFaceName, "Arial");
3762 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3763 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3765 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3766 ok(!ret, "font Arial Bold is not enumerated\n");
3767 ret = strcmp(lf.lfFaceName, "Arial");
3768 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3769 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3771 lstrcpy(lf.lfFaceName, "Arial Bold");
3772 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3773 ok(ret, "font Arial Bold should not be enumerated\n");
3775 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3776 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3777 ret = strcmp(lf.lfFaceName, "Arial");
3778 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3779 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3781 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3782 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3783 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3785 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3786 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3788 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3789 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3790 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3795 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3797 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3798 const char *fullname = (const char *)lParam;
3800 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3805 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3810 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3817 static void test_fullname(void)
3819 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3820 char buf[LF_FULLFACESIZE];
3826 hdc = CreateCompatibleDC(0);
3827 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3829 memset(&lf, 0, sizeof(lf));
3830 lf.lfCharSet = ANSI_CHARSET;
3831 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3834 lf.lfQuality = DEFAULT_QUALITY;
3835 lf.lfItalic = FALSE;
3836 lf.lfWeight = FW_DONTCARE;
3838 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3840 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3842 skip("%s is not installed\n", TestName[i]);
3846 lstrcpyA(lf.lfFaceName, TestName[i]);
3847 hfont = CreateFontIndirectA(&lf);
3848 ok(hfont != 0, "CreateFontIndirectA failed\n");
3850 of = SelectObject(hdc, hfont);
3852 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3853 "face full name could not be read\n");
3854 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3855 SelectObject(hdc, of);
3856 DeleteObject(hfont);
3861 static BOOL write_ttf_file(char *tmp_name)
3863 char tmp_path[MAX_PATH];
3870 SetLastError(0xdeadbeef);
3871 rsrc = FindResource(GetModuleHandle(0), "wine_test.ttf", RT_RCDATA);
3872 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
3873 if (!rsrc) return FALSE;
3874 SetLastError(0xdeadbeef);
3875 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
3876 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
3877 if (!rsrc_data) return FALSE;
3878 SetLastError(0xdeadbeef);
3879 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
3880 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
3881 if (!rsrc_size) return FALSE;
3883 SetLastError(0xdeadbeef);
3884 ret = GetTempPath(MAX_PATH, tmp_path);
3885 ok(ret, "GetTempPath() error %d\n", GetLastError());
3886 SetLastError(0xdeadbeef);
3887 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
3888 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3890 SetLastError(0xdeadbeef);
3891 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
3892 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
3893 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
3895 SetLastError(0xdeadbeef);
3896 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
3897 ok(ret, "WriteFile() error %d\n", GetLastError());
3903 static void test_CreateScalableFontResource(void)
3905 char ttf_name[MAX_PATH];
3906 char tmp_path[MAX_PATH];
3907 char fot_name[MAX_PATH];
3911 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
3913 win_skip("AddFontResourceExA is not available on this platform\n");
3917 if (!write_ttf_file(ttf_name))
3919 skip("Failed to create ttf file for testing\n");
3923 trace("created %s\n", ttf_name);
3925 ret = is_truetype_font_installed("wine_test");
3926 ok(!ret, "font wine_test should not be enumerated\n");
3928 ret = GetTempPath(MAX_PATH, tmp_path);
3929 ok(ret, "GetTempPath() error %d\n", GetLastError());
3930 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
3931 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3933 ret = GetFileAttributes(fot_name);
3934 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
3936 SetLastError(0xdeadbeef);
3937 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3938 ok(!ret, "CreateScalableFontResource() should fail\n");
3939 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3941 SetLastError(0xdeadbeef);
3942 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
3943 ok(!ret, "CreateScalableFontResource() should fail\n");
3944 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3946 file_part = strrchr(ttf_name, '\\');
3947 SetLastError(0xdeadbeef);
3948 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
3949 ok(!ret, "CreateScalableFontResource() should fail\n");
3950 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3952 SetLastError(0xdeadbeef);
3953 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
3954 ok(!ret, "CreateScalableFontResource() should fail\n");
3956 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3958 SetLastError(0xdeadbeef);
3959 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
3960 ok(!ret, "CreateScalableFontResource() should fail\n");
3962 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3964 ret = DeleteFile(fot_name);
3965 ok(ret, "DeleteFile() error %d\n", GetLastError());
3967 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3969 ok(!ret, "RemoveFontResourceEx() should fail\n");
3971 /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3974 /* test public font resource */
3975 SetLastError(0xdeadbeef);
3976 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3977 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3979 ret = is_truetype_font_installed("wine_test");
3980 ok(!ret, "font wine_test should not be enumerated\n");
3982 SetLastError(0xdeadbeef);
3983 ret = pAddFontResourceExA(fot_name, 0, 0);
3984 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3986 ret = is_truetype_font_installed("wine_test");
3987 ok(ret, "font wine_test should be enumerated\n");
3989 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3990 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
3992 SetLastError(0xdeadbeef);
3993 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3995 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3997 ret = is_truetype_font_installed("wine_test");
3999 ok(!ret, "font wine_test should not be enumerated\n");
4001 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4004 /* remove once RemoveFontResource is implemented */
4005 DeleteFile(fot_name);
4006 DeleteFile(ttf_name);
4010 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4011 ok(!ret, "RemoveFontResourceEx() should fail\n");
4013 DeleteFile(fot_name);
4015 /* test hidden font resource */
4016 SetLastError(0xdeadbeef);
4017 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4018 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4020 ret = is_truetype_font_installed("wine_test");
4021 ok(!ret, "font wine_test should not be enumerated\n");
4023 SetLastError(0xdeadbeef);
4024 ret = pAddFontResourceExA(fot_name, 0, 0);
4025 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4027 ret = is_truetype_font_installed("wine_test");
4028 ok(!ret, "font wine_test should not be enumerated\n");
4030 /* XP allows removing a private font added with 0 flags */
4031 SetLastError(0xdeadbeef);
4032 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4033 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4035 ret = is_truetype_font_installed("wine_test");
4036 ok(!ret, "font wine_test should not be enumerated\n");
4038 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4039 ok(!ret, "RemoveFontResourceEx() should fail\n");
4041 DeleteFile(fot_name);
4042 DeleteFile(ttf_name);
4051 test_outline_font();
4052 test_bitmap_font_metrics();
4053 test_GdiGetCharDimensions();
4054 test_GetCharABCWidths();
4055 test_text_extents();
4056 test_GetGlyphIndices();
4057 test_GetKerningPairs();
4058 test_GetOutlineTextMetrics();
4059 test_SetTextJustification();
4060 test_font_charset();
4061 test_GetFontUnicodeRanges();
4062 test_nonexistent_font();
4064 test_height_selection();
4065 test_AddFontMemResource();
4068 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4069 * I'd like to avoid them in this test.
4071 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4072 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4073 if (is_truetype_font_installed("Arial Black") &&
4074 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4076 test_EnumFontFamilies("", ANSI_CHARSET);
4077 test_EnumFontFamilies("", SYMBOL_CHARSET);
4078 test_EnumFontFamilies("", DEFAULT_CHARSET);
4081 skip("Arial Black or Symbol/Wingdings is not installed\n");
4082 test_EnumFontFamiliesEx_default_charset();
4083 test_GetTextMetrics();
4084 test_GdiRealizationInfo();
4086 test_GetGlyphOutline();
4087 test_GetTextMetrics2("Tahoma", -11);
4088 test_GetTextMetrics2("Tahoma", -55);
4089 test_GetTextMetrics2("Tahoma", -110);
4090 test_GetTextMetrics2("Arial", -11);
4091 test_GetTextMetrics2("Arial", -55);
4092 test_GetTextMetrics2("Arial", -110);
4093 test_CreateFontIndirect();
4094 test_CreateFontIndirectEx();
4098 /* CreateScalableFontResource should be last test until RemoveFontResource
4099 * is properly implemented.
4101 test_CreateScalableFontResource();