2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
46 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
48 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
49 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
50 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
51 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
53 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
55 static HMODULE hgdi32 = 0;
56 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
58 static void init(void)
60 hgdi32 = GetModuleHandleA("gdi32.dll");
62 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
63 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
64 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
65 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
66 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
67 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
68 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
69 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
70 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
71 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
72 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
73 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
74 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
75 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
76 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
79 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
81 if (type != TRUETYPE_FONTTYPE) return 1;
86 static BOOL is_truetype_font_installed(const char *name)
91 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
98 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
103 static BOOL is_font_installed(const char *name)
108 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
115 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
123 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
124 /* NT4 tries to be clever and only returns the minimum length */
125 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
127 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
128 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
129 ok(lf->lfHeight == getobj_lf.lfHeight ||
130 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
131 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
132 ok(lf->lfWidth == getobj_lf.lfWidth ||
133 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
134 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
135 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
136 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
137 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
138 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
139 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
140 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
141 ok(lf->lfWeight == getobj_lf.lfWeight ||
142 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
143 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
144 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
145 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
146 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
147 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
148 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
149 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
150 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
151 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
152 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
153 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
154 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
157 static HFONT create_font(const char* test, const LOGFONTA* lf)
159 HFONT hfont = CreateFontIndirectA(lf);
160 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
162 check_font(test, lf, hfont);
166 static void test_logfont(void)
171 memset(&lf, 0, sizeof lf);
173 lf.lfCharSet = ANSI_CHARSET;
174 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
175 lf.lfWeight = FW_DONTCARE;
178 lf.lfQuality = DEFAULT_QUALITY;
180 lstrcpyA(lf.lfFaceName, "Arial");
181 hfont = create_font("Arial", &lf);
184 memset(&lf, 'A', sizeof(lf));
185 hfont = CreateFontIndirectA(&lf);
186 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
188 lf.lfFaceName[LF_FACESIZE - 1] = 0;
189 check_font("AAA...", &lf, hfont);
193 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
195 if (type & RASTER_FONTTYPE)
197 LOGFONT *lf = (LOGFONT *)lParam;
199 return 0; /* stop enumeration */
202 return 1; /* continue enumeration */
205 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
207 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
208 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
209 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
210 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
211 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
212 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
213 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
214 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
215 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
216 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
217 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
218 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
219 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
220 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
221 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
222 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
223 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
224 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
225 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
226 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
229 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
230 LONG lfWidth, const char *test_str,
231 INT test_str_len, const TEXTMETRICA *tm_orig,
232 const SIZE *size_orig, INT width_of_A_orig,
233 INT scale_x, INT scale_y)
236 OUTLINETEXTMETRIC otm;
239 INT width_of_A, cx, cy;
245 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
247 GetObjectA(hfont, sizeof(lf), &lf);
249 if (GetOutlineTextMetricsA(hdc, 0, NULL))
251 otm.otmSize = sizeof(otm) / 2;
252 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253 ok(ret == sizeof(otm)/2 /* XP */ ||
254 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
256 memset(&otm, 0x1, sizeof(otm));
257 otm.otmSize = sizeof(otm);
258 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259 ok(ret == sizeof(otm) /* XP */ ||
260 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
262 memset(&tm, 0x2, sizeof(tm));
263 ret = GetTextMetricsA(hdc, &tm);
264 ok(ret, "GetTextMetricsA failed\n");
265 /* the structure size is aligned */
266 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
268 ok(0, "tm != otm\n");
269 compare_tm(&tm, &otm.otmTextMetrics);
272 tm = otm.otmTextMetrics;
273 if (0) /* these metrics are scaled too, but with rounding errors */
275 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
276 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
278 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
279 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
280 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
281 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
282 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
283 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
287 ret = GetTextMetricsA(hdc, &tm);
288 ok(ret, "GetTextMetricsA failed\n");
291 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
292 cy = tm.tmHeight / tm_orig->tmHeight;
293 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
294 lfHeight, scale_x, scale_y, cx, cy);
295 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
296 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
297 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
298 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
299 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
301 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
305 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
308 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
310 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
312 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
313 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
315 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
317 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);
320 /* Test how GDI scales bitmap font metrics */
321 static void test_bitmap_font(void)
323 static const char test_str[11] = "Test String";
326 HFONT hfont, old_hfont;
329 INT ret, i, width_orig, height_orig, scale, lfWidth;
331 hdc = CreateCompatibleDC(0);
333 /* "System" has only 1 pixel size defined, otherwise the test breaks */
334 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
338 trace("no bitmap fonts were found, skipping the test\n");
342 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
344 height_orig = bitmap_lf.lfHeight;
345 lfWidth = bitmap_lf.lfWidth;
347 hfont = create_font("bitmap", &bitmap_lf);
348 old_hfont = SelectObject(hdc, hfont);
349 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
350 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
351 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
352 SelectObject(hdc, old_hfont);
355 bitmap_lf.lfHeight = 0;
356 bitmap_lf.lfWidth = 4;
357 hfont = create_font("bitmap", &bitmap_lf);
358 old_hfont = SelectObject(hdc, hfont);
359 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
360 SelectObject(hdc, old_hfont);
363 bitmap_lf.lfHeight = height_orig;
364 bitmap_lf.lfWidth = lfWidth;
366 /* test fractional scaling */
367 for (i = 1; i <= height_orig * 6; i++)
371 bitmap_lf.lfHeight = i;
372 hfont = create_font("fractional", &bitmap_lf);
373 scale = (i + height_orig - 1) / height_orig;
374 nearest_height = scale * height_orig;
375 /* Only jump to the next height if the difference <= 25% original height */
376 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
377 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
378 so we'll not test this particular height. */
379 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
380 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
381 old_hfont = SelectObject(hdc, hfont);
382 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
383 SelectObject(hdc, old_hfont);
387 /* test integer scaling 3x2 */
388 bitmap_lf.lfHeight = height_orig * 2;
389 bitmap_lf.lfWidth *= 3;
390 hfont = create_font("3x2", &bitmap_lf);
391 old_hfont = SelectObject(hdc, hfont);
392 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
393 SelectObject(hdc, old_hfont);
396 /* test integer scaling 3x3 */
397 bitmap_lf.lfHeight = height_orig * 3;
398 bitmap_lf.lfWidth = 0;
399 hfont = create_font("3x3", &bitmap_lf);
400 old_hfont = SelectObject(hdc, hfont);
401 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
402 SelectObject(hdc, old_hfont);
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
411 static const char test_str[11] = "Test String";
414 HFONT hfont, old_hfont, old_hfont_2;
415 OUTLINETEXTMETRICA otm;
417 INT width_orig, height_orig, lfWidth;
420 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
424 if (!is_truetype_font_installed("Arial"))
426 skip("Arial is not installed\n");
430 hdc = CreateCompatibleDC(0);
432 memset(&lf, 0, sizeof(lf));
433 strcpy(lf.lfFaceName, "Arial");
435 hfont = create_font("outline", &lf);
436 old_hfont = SelectObject(hdc, hfont);
437 otm.otmSize = sizeof(otm);
438 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
442 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
443 SelectObject(hdc, old_hfont);
446 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
447 lf.lfHeight = otm.otmEMSquare;
448 lf.lfHeight = -lf.lfHeight;
449 hfont = create_font("outline", &lf);
450 old_hfont = SelectObject(hdc, hfont);
451 otm.otmSize = sizeof(otm);
452 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
453 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
454 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
455 SelectObject(hdc, old_hfont);
458 height_orig = otm.otmTextMetrics.tmHeight;
459 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
461 /* test integer scaling 3x2 */
462 lf.lfHeight = height_orig * 2;
463 lf.lfWidth = lfWidth * 3;
464 hfont = create_font("3x2", &lf);
465 old_hfont = SelectObject(hdc, hfont);
466 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
467 SelectObject(hdc, old_hfont);
470 /* test integer scaling 3x3 */
471 lf.lfHeight = height_orig * 3;
472 lf.lfWidth = lfWidth * 3;
473 hfont = create_font("3x3", &lf);
474 old_hfont = SelectObject(hdc, hfont);
475 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
476 SelectObject(hdc, old_hfont);
479 /* test integer scaling 1x1 */
480 lf.lfHeight = height_orig * 1;
481 lf.lfWidth = lfWidth * 1;
482 hfont = create_font("1x1", &lf);
483 old_hfont = SelectObject(hdc, hfont);
484 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 SelectObject(hdc, old_hfont);
488 /* test integer scaling 1x1 */
489 lf.lfHeight = height_orig;
491 hfont = create_font("1x1", &lf);
492 old_hfont = SelectObject(hdc, hfont);
493 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
495 /* with an identity matrix */
496 memset(&gm, 0, sizeof(gm));
497 SetLastError(0xdeadbeef);
498 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
499 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
500 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
501 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
502 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
503 /* with a custom matrix */
504 memset(&gm, 0, sizeof(gm));
505 SetLastError(0xdeadbeef);
506 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
507 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
508 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
509 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
510 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
512 /* Test that changing the DC transformation affects only the font
513 * selected on this DC and doesn't affect the same font selected on
516 hdc_2 = CreateCompatibleDC(0);
517 old_hfont_2 = SelectObject(hdc_2, hfont);
518 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
520 SetMapMode(hdc, MM_ANISOTROPIC);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* test restrictions of compatibility mode GM_COMPATIBLE */
526 /* part 1: rescaling only X should not change font scaling on screen.
527 So compressing the X axis by 2 is not done, and this
528 appears as X scaling of 2 that no one requested. */
529 SetWindowExtEx(hdc, 100, 100, NULL);
530 SetViewportExtEx(hdc, 50, 100, NULL);
531 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
532 /* font metrics on another DC should be unchanged */
533 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
535 /* part 2: rescaling only Y should change font scaling.
536 As also X is scaled by a factor of 2, but this is not
537 requested by the DC transformation, we get a scaling factor
538 of 2 in the X coordinate. */
539 SetViewportExtEx(hdc, 100, 200, NULL);
540 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
541 /* font metrics on another DC should be unchanged */
542 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
544 /* restore scaling */
545 SetMapMode(hdc, MM_TEXT);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
550 SelectObject(hdc_2, old_hfont_2);
553 if (!SetGraphicsMode(hdc, GM_ADVANCED))
555 SelectObject(hdc, old_hfont);
558 skip("GM_ADVANCED is not supported on this platform\n");
569 SetLastError(0xdeadbeef);
570 ret = SetWorldTransform(hdc, &xform);
571 ok(ret, "SetWorldTransform error %u\n", GetLastError());
573 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
575 /* with an identity matrix */
576 memset(&gm, 0, sizeof(gm));
577 SetLastError(0xdeadbeef);
578 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581 pt.x = width_orig; pt.y = 0;
583 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
584 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
585 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
586 /* with a custom matrix */
587 memset(&gm, 0, sizeof(gm));
588 SetLastError(0xdeadbeef);
589 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
590 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
591 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
592 pt.x = width_orig; pt.y = 0;
594 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
595 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
596 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598 SetLastError(0xdeadbeef);
599 ret = SetMapMode(hdc, MM_LOMETRIC);
600 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
604 /* with an identity matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
612 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
614 /* with a custom matrix */
615 memset(&gm, 0, sizeof(gm));
616 SetLastError(0xdeadbeef);
617 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
618 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
619 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
620 pt.x = width_orig; pt.y = 0;
622 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
623 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
625 SetLastError(0xdeadbeef);
626 ret = SetMapMode(hdc, MM_TEXT);
627 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
629 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
631 /* with an identity matrix */
632 memset(&gm, 0, sizeof(gm));
633 SetLastError(0xdeadbeef);
634 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
635 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
636 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
637 pt.x = width_orig; pt.y = 0;
639 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
640 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
641 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
642 /* with a custom matrix */
643 memset(&gm, 0, sizeof(gm));
644 SetLastError(0xdeadbeef);
645 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
646 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
647 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
648 pt.x = width_orig; pt.y = 0;
650 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
651 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
652 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
654 SelectObject(hdc, old_hfont);
659 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
661 LOGFONT *lf = (LOGFONT *)lParam;
663 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
666 return 0; /* stop enumeration */
668 return 1; /* continue enumeration */
671 #define FH_SCALE 0x80000000
672 static void test_bitmap_font_metrics(void)
674 static const struct font_data
676 const char face_name[LF_FACESIZE];
677 int weight, height, ascent, descent, int_leading, ext_leading;
678 int ave_char_width, max_char_width, dpi;
679 BYTE first_char, last_char, def_char, break_char;
685 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
686 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
687 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
688 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
689 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
690 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
691 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
692 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
693 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
694 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
696 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
697 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
698 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
699 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
700 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
701 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
702 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
703 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
704 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
705 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
707 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
708 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
709 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
710 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
711 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
712 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
713 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
714 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
715 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
716 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
717 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
718 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
719 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
720 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
721 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
722 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
724 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
725 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
726 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
727 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
728 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
729 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
730 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
731 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
732 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
733 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
734 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
735 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
737 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
739 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
740 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
741 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
742 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
743 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
744 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
745 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
746 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
747 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
748 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
749 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
750 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
751 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
752 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
753 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
755 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
756 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
757 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
758 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
759 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
760 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
761 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
762 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
763 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
764 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
765 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
767 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
768 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
769 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
771 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
772 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
773 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
775 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
776 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
777 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
779 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
780 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
782 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
783 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
784 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN },
785 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
786 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
787 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN },
788 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
789 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
790 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC },
791 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN },
792 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
793 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
794 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC },
795 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN },
796 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
797 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
798 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC },
799 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN },
800 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
801 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC },
802 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN },
804 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
805 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
806 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
807 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
808 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
809 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
810 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
811 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
812 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
813 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
814 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
815 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
817 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
818 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
819 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
821 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
823 /* FIXME: add "Terminal" */
825 static const int font_log_pixels[] = { 96, 120 };
828 HFONT hfont, old_hfont;
830 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
832 char face_name[LF_FACESIZE];
835 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
836 trace("system language id %04x\n", system_lang_id);
838 expected_cs = GetACP();
839 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
841 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
844 expected_cs = csi.ciCharset;
845 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
847 hdc = CreateCompatibleDC(0);
850 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
851 GetDeviceCaps(hdc, LOGPIXELSY));
853 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
856 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
858 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
862 font_res = font_log_pixels[i];
865 trace("best font resolution is %d\n", font_res);
867 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
871 memset(&lf, 0, sizeof(lf));
873 height = fd[i].height & ~FH_SCALE;
874 lf.lfHeight = height;
875 strcpy(lf.lfFaceName, fd[i].face_name);
877 for(bit = 0; bit < 32; bit++)
884 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
885 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
887 lf.lfCharSet = csi.ciCharset;
888 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
889 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
890 if (fd[i].height & FH_SCALE)
891 ok(ret, "scaled font height %d should not be enumerated\n", height);
894 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
896 if (ret) /* FIXME: Remove once Wine is fixed */
897 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
899 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
902 if (ret && !(fd[i].height & FH_SCALE))
905 hfont = create_font(lf.lfFaceName, &lf);
906 old_hfont = SelectObject(hdc, hfont);
907 bRet = GetTextMetrics(hdc, &tm);
908 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
910 SetLastError(0xdeadbeef);
911 ret = GetTextFace(hdc, sizeof(face_name), face_name);
912 ok(ret, "GetTextFace error %u\n", GetLastError());
914 SetLastError(0xdeadbeef);
915 ret = GetTextCharset(hdc);
917 if (lstrcmp(face_name, fd[i].face_name) != 0)
919 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
920 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
921 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
922 SelectObject(hdc, old_hfont);
927 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
929 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
930 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
932 if(fd[i].dpi == tm.tmDigitizedAspectX)
934 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
935 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
937 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
938 if (fd[i].height & FH_SCALE)
939 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
941 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);
942 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
943 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
944 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
945 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
946 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
947 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
948 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
949 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
950 make default char test fail */
951 if (tm.tmCharSet == lf.lfCharSet)
952 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
953 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
954 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
956 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
957 that make the max width bigger */
958 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
959 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
962 skip("Skipping font metrics test for system langid 0x%x\n",
965 SelectObject(hdc, old_hfont);
973 static void test_GdiGetCharDimensions(void)
979 LONG avgwidth, height;
980 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
982 if (!pGdiGetCharDimensions)
984 win_skip("GdiGetCharDimensions not available on this platform\n");
988 hdc = CreateCompatibleDC(NULL);
990 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
991 avgwidth = ((size.cx / 26) + 1) / 2;
993 ret = pGdiGetCharDimensions(hdc, &tm, &height);
994 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
995 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
997 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
998 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1000 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1001 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1004 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1005 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1006 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1011 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1012 const TEXTMETRIC *lpntme,
1013 DWORD FontType, LPARAM lParam)
1015 if (FontType & TRUETYPE_FONTTYPE)
1019 hfont = CreateFontIndirect(lpelfe);
1022 *(HFONT *)lParam = hfont;
1030 static void test_GetCharABCWidths(void)
1032 static const WCHAR str[] = {'a',0};
1054 {0xffffff, 0xffffff},
1055 {0x1000000, 0x1000000},
1056 {0xffffff, 0x1000000},
1057 {0xffffffff, 0xffffffff},
1065 BOOL r[sizeof range / sizeof range[0]];
1068 {ANSI_CHARSET, 0x30, 0x30,
1069 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1070 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1071 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1072 {HANGEUL_CHARSET, 0x8141, 0xac02,
1073 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1074 {JOHAB_CHARSET, 0x8446, 0x3135,
1075 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1076 {GB2312_CHARSET, 0x8141, 0x4e04,
1077 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1078 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1079 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1083 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1085 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1089 memset(&lf, 0, sizeof(lf));
1090 strcpy(lf.lfFaceName, "System");
1093 hfont = CreateFontIndirectA(&lf);
1095 hfont = SelectObject(hdc, hfont);
1097 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1098 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1100 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1101 ok(!ret, "GetCharABCWidthsI should have failed\n");
1103 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1104 ok(!ret, "GetCharABCWidthsI should have failed\n");
1106 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1107 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1109 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1110 ok(!ret, "GetCharABCWidthsW should have failed\n");
1112 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1113 ok(!ret, "GetCharABCWidthsW should have failed\n");
1115 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1116 ok(!ret, "GetCharABCWidthsW should have failed\n");
1118 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1119 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1121 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1122 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1124 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1125 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1127 hfont = SelectObject(hdc, hfont);
1128 DeleteObject(hfont);
1130 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1134 UINT code = 0x41, j;
1136 lf.lfFaceName[0] = '\0';
1137 lf.lfCharSet = c[i].cs;
1138 lf.lfPitchAndFamily = 0;
1139 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1141 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1145 memset(a, 0, sizeof a);
1146 memset(w, 0, sizeof w);
1147 hfont = SelectObject(hdc, hfont);
1148 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1149 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1150 memcmp(a, w, sizeof a) == 0,
1151 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1153 memset(a, 0xbb, sizeof a);
1154 ret = pGetCharABCWidthsA(hdc, code, code, a);
1155 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1156 memset(full, 0xcc, sizeof full);
1157 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1158 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1159 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1160 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1162 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1164 memset(full, 0xdd, sizeof full);
1165 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1166 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1167 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1170 UINT last = range[j].last - range[j].first;
1171 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1172 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1173 "GetCharABCWidthsA %x should match. codepage = %u\n",
1174 range[j].last, c[i].cs);
1178 hfont = SelectObject(hdc, hfont);
1179 DeleteObject(hfont);
1182 ReleaseDC(NULL, hdc);
1185 static void test_text_extents(void)
1187 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1189 INT i, len, fit1, fit2;
1198 memset(&lf, 0, sizeof(lf));
1199 strcpy(lf.lfFaceName, "Arial");
1202 hfont = CreateFontIndirectA(&lf);
1204 hfont = SelectObject(hdc, hfont);
1205 GetTextMetricsA(hdc, &tm);
1206 GetTextExtentPointA(hdc, "o", 1, &sz);
1207 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1209 SetLastError(0xdeadbeef);
1210 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1211 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1213 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1214 hfont = SelectObject(hdc, hfont);
1215 DeleteObject(hfont);
1221 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1222 extents[0] = 1; /* So that the increasing sequence test will fail
1223 if the extents array is untouched. */
1224 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1225 GetTextExtentPointW(hdc, wt, len, &sz2);
1226 ok(sz1.cy == sz2.cy,
1227 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1228 /* Because of the '\n' in the string GetTextExtentExPoint and
1229 GetTextExtentPoint return different widths under Win2k, but
1230 under WinXP they return the same width. So we don't test that
1233 for (i = 1; i < len; ++i)
1234 ok(extents[i-1] <= extents[i],
1235 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1237 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1238 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1239 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1240 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1241 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1242 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1243 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1244 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1245 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1246 ok(extents[0] == extents[2] && extents[1] == extents[3],
1247 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1248 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1249 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1250 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1251 HeapFree(GetProcessHeap(), 0, extents);
1253 /* extents functions fail with -ve counts (the interesting case being -1) */
1254 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1255 ok(ret == FALSE, "got %d\n", ret);
1256 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1257 ok(ret == FALSE, "got %d\n", ret);
1258 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1259 ok(ret == FALSE, "got %d\n", ret);
1261 /* max_extent = 0 succeeds and returns zero */
1263 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1265 broken(ret == FALSE), /* NT4, 2k */
1268 broken(fit1 == -215), /* NT4, 2k */
1269 "fit = %d\n", fit1);
1270 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1271 ok(ret == TRUE, "got %d\n", ret);
1272 ok(fit2 == 0, "fit = %d\n", fit2);
1274 /* max_extent = -1 is interpreted as a very large width that will
1275 * definitely fit our three characters */
1277 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1278 ok(ret == TRUE, "got %d\n", ret);
1279 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1280 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1281 ok(ret == TRUE, "got %d\n", ret);
1282 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1284 /* max_extent = -2 is interpreted similarly, but the Ansi version
1285 * rejects it while the Unicode one accepts it */
1287 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1288 todo_wine ok(ret == FALSE, "got %d\n", ret);
1289 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1290 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1291 ok(ret == TRUE, "got %d\n", ret);
1292 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1294 hfont = SelectObject(hdc, hfont);
1295 DeleteObject(hfont);
1296 ReleaseDC(NULL, hdc);
1299 static void test_GetGlyphIndices(void)
1306 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1307 WORD glyphs[(sizeof(testtext)/2)-1];
1311 if (!pGetGlyphIndicesW) {
1312 win_skip("GetGlyphIndicesW not available on platform\n");
1318 memset(&lf, 0, sizeof(lf));
1319 strcpy(lf.lfFaceName, "System");
1321 lf.lfCharSet = ANSI_CHARSET;
1323 hfont = CreateFontIndirectA(&lf);
1324 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1325 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1326 if (textm.tmCharSet == ANSI_CHARSET)
1328 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1329 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1330 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1331 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1333 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1334 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1335 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1336 textm.tmDefaultChar, glyphs[4]);
1339 /* FIXME: Write tests for non-ANSI charsets. */
1340 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1342 if(!is_font_installed("Tahoma"))
1344 skip("Tahoma is not installed so skipping this test\n");
1347 memset(&lf, 0, sizeof(lf));
1348 strcpy(lf.lfFaceName, "Tahoma");
1351 hfont = CreateFontIndirectA(&lf);
1352 hOldFont = SelectObject(hdc, hfont);
1353 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1354 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1355 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1356 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1357 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1359 testtext[0] = textm.tmDefaultChar;
1360 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1361 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1362 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1363 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1364 DeleteObject(SelectObject(hdc, hOldFont));
1367 static void test_GetKerningPairs(void)
1369 static const struct kerning_data
1371 const char face_name[LF_FACESIZE];
1373 /* some interesting fields from OUTLINETEXTMETRIC */
1374 LONG tmHeight, tmAscent, tmDescent;
1379 UINT otmsCapEmHeight;
1384 UINT otmusMinimumPPEM;
1385 /* small subset of kerning pairs to test */
1386 DWORD total_kern_pairs;
1387 const KERNINGPAIR kern_pair[26];
1390 {"Arial", 12, 12, 9, 3,
1391 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1394 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1395 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1396 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1397 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1398 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1399 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1400 {933,970,+1},{933,972,-1}
1403 {"Arial", -34, 39, 32, 7,
1404 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1407 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1408 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1409 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1410 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1411 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1412 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1413 {933,970,+2},{933,972,-3}
1416 { "Arial", 120, 120, 97, 23,
1417 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1420 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1421 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1422 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1423 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1424 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1425 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1426 {933,970,+6},{933,972,-10}
1429 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1430 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1431 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1434 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1435 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1436 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1437 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1438 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1439 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1440 {933,970,+54},{933,972,-83}
1446 HFONT hfont, hfont_old;
1447 KERNINGPAIR *kern_pair;
1449 DWORD total_kern_pairs, ret, i, n, matches;
1453 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1454 * which may render this test unusable, so we're trying to avoid that.
1456 SetLastError(0xdeadbeef);
1457 GetKerningPairsW(hdc, 0, NULL);
1458 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1460 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1465 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1467 OUTLINETEXTMETRICW otm;
1470 if (!is_font_installed(kd[i].face_name))
1472 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1476 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1478 memset(&lf, 0, sizeof(lf));
1479 strcpy(lf.lfFaceName, kd[i].face_name);
1480 lf.lfHeight = kd[i].height;
1481 hfont = CreateFontIndirect(&lf);
1484 hfont_old = SelectObject(hdc, hfont);
1486 SetLastError(0xdeadbeef);
1487 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1488 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1489 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1491 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1492 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1493 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1494 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1495 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1496 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1498 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1499 kd[i].otmEMSquare, otm.otmEMSquare);
1500 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1501 kd[i].otmAscent, otm.otmAscent);
1502 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1503 kd[i].otmDescent, otm.otmDescent);
1504 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1505 kd[i].otmLineGap, otm.otmLineGap);
1506 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1507 kd[i].otmMacDescent, otm.otmMacDescent);
1508 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1509 kd[i].otmMacAscent, otm.otmMacAscent);
1511 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1512 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1513 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1514 kd[i].otmsXHeight, otm.otmsXHeight);
1515 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1516 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1517 kd[i].otmMacLineGap, otm.otmMacLineGap);
1518 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1519 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1522 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1523 trace("total_kern_pairs %u\n", total_kern_pairs);
1524 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1526 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1529 SetLastError(0xdeadbeef);
1530 ret = GetKerningPairsW(hdc, 0, kern_pair);
1531 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1532 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1533 ok(ret == 0, "got %u, expected 0\n", ret);
1535 ret = GetKerningPairsW(hdc, 100, NULL);
1536 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1538 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1539 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1541 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1542 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1546 for (n = 0; n < ret; n++)
1549 /* Disabled to limit console spam */
1550 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1551 trace("{'%c','%c',%d},\n",
1552 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1553 for (j = 0; j < kd[i].total_kern_pairs; j++)
1555 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1556 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1558 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1559 "pair %d:%d got %d, expected %d\n",
1560 kern_pair[n].wFirst, kern_pair[n].wSecond,
1561 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1567 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1568 matches, kd[i].total_kern_pairs);
1570 HeapFree(GetProcessHeap(), 0, kern_pair);
1572 SelectObject(hdc, hfont_old);
1573 DeleteObject(hfont);
1579 static void test_height_selection(void)
1581 static const struct font_data
1583 const char face_name[LF_FACESIZE];
1584 int requested_height;
1585 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1588 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1589 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1590 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1591 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1592 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1593 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1594 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1595 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1596 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1597 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1601 HFONT hfont, old_hfont;
1605 hdc = CreateCompatibleDC(0);
1608 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1610 if (!is_truetype_font_installed(fd[i].face_name))
1612 skip("%s is not installed\n", fd[i].face_name);
1616 memset(&lf, 0, sizeof(lf));
1617 lf.lfHeight = fd[i].requested_height;
1618 lf.lfWeight = fd[i].weight;
1619 strcpy(lf.lfFaceName, fd[i].face_name);
1621 hfont = CreateFontIndirect(&lf);
1624 old_hfont = SelectObject(hdc, hfont);
1625 ret = GetTextMetrics(hdc, &tm);
1626 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1627 if(fd[i].dpi == tm.tmDigitizedAspectX)
1629 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1630 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);
1631 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);
1632 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);
1633 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);
1634 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1635 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);
1637 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);
1640 SelectObject(hdc, old_hfont);
1641 DeleteObject(hfont);
1647 static void test_GetOutlineTextMetrics(void)
1649 OUTLINETEXTMETRIC *otm;
1651 HFONT hfont, hfont_old;
1653 DWORD ret, otm_size;
1656 if (!is_font_installed("Arial"))
1658 skip("Arial is not installed\n");
1664 memset(&lf, 0, sizeof(lf));
1665 strcpy(lf.lfFaceName, "Arial");
1667 lf.lfWeight = FW_NORMAL;
1668 lf.lfPitchAndFamily = DEFAULT_PITCH;
1669 lf.lfQuality = PROOF_QUALITY;
1670 hfont = CreateFontIndirect(&lf);
1673 hfont_old = SelectObject(hdc, hfont);
1674 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1675 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1677 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1679 memset(otm, 0xAA, otm_size);
1680 SetLastError(0xdeadbeef);
1681 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1682 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1683 ok(ret == 1 /* Win9x */ ||
1684 ret == otm->otmSize /* XP*/,
1685 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1686 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1688 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1689 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1690 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1691 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1694 memset(otm, 0xAA, otm_size);
1695 SetLastError(0xdeadbeef);
1696 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1697 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1698 ok(ret == 1 /* Win9x */ ||
1699 ret == otm->otmSize /* XP*/,
1700 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1701 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1703 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1704 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1705 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1706 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1709 /* ask about truncated data */
1710 memset(otm, 0xAA, otm_size);
1711 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1712 SetLastError(0xdeadbeef);
1713 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1714 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1715 ok(ret == 1 /* Win9x */ ||
1716 ret == otm->otmSize /* XP*/,
1717 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1718 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1720 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1721 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1722 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1724 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1726 HeapFree(GetProcessHeap(), 0, otm);
1728 SelectObject(hdc, hfont_old);
1729 DeleteObject(hfont);
1734 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1738 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1739 areaWidth = clientArea->right - clientArea->left,
1741 BOOL lastExtent = FALSE;
1742 PSTR pFirstChar, pLastChar;
1748 int GetTextExtentExPointWWidth;
1751 GetTextMetricsA(hdc, &tm);
1752 y = clientArea->top;
1755 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1761 /* if not at the end of the string, ... */
1762 if (*str == '\0') break;
1763 /* ... add the next word to the current extent */
1764 while (*str != '\0' && *str++ != tm.tmBreakChar);
1766 SetTextJustification(hdc, 0, 0);
1767 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1768 } while ((int) size.cx < areaWidth);
1770 /* ignore trailing break chars */
1772 while (*(pLastChar - 1) == tm.tmBreakChar)
1778 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1780 SetTextJustification(hdc, 0, 0);
1781 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1783 /* do not justify the last extent */
1784 if (*str != '\0' && breakCount > 0)
1786 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1787 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1788 justifiedWidth = size.cx;
1790 else lastExtent = TRUE;
1792 /* catch errors and report them */
1793 if (!lastExtent && (justifiedWidth != areaWidth))
1795 memset(error[nErrors].extent, 0, 100);
1796 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1797 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1803 } while (*str && y < clientArea->bottom);
1805 for (e = 0; e < nErrors; e++)
1807 /* The width returned by GetTextExtentPoint32() is exactly the same
1808 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1809 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1810 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1811 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1815 static void test_SetTextJustification(void)
1822 static char testText[] =
1823 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1824 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1825 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1826 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1827 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1828 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1829 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1831 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1832 GetClientRect( hwnd, &clientArea );
1833 hdc = GetDC( hwnd );
1835 memset(&lf, 0, sizeof lf);
1836 lf.lfCharSet = ANSI_CHARSET;
1837 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1838 lf.lfWeight = FW_DONTCARE;
1840 lf.lfQuality = DEFAULT_QUALITY;
1841 lstrcpyA(lf.lfFaceName, "Times New Roman");
1842 hfont = create_font("Times New Roman", &lf);
1843 SelectObject(hdc, hfont);
1845 testJustification(hdc, testText, &clientArea);
1847 DeleteObject(hfont);
1848 ReleaseDC(hwnd, hdc);
1849 DestroyWindow(hwnd);
1852 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1856 HFONT hfont, hfont_old;
1863 assert(count <= 128);
1865 memset(&lf, 0, sizeof(lf));
1867 lf.lfCharSet = charset;
1869 lstrcpyA(lf.lfFaceName, "Arial");
1870 SetLastError(0xdeadbeef);
1871 hfont = CreateFontIndirectA(&lf);
1872 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1875 hfont_old = SelectObject(hdc, hfont);
1877 cs = GetTextCharsetInfo(hdc, &fs, 0);
1878 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1880 SetLastError(0xdeadbeef);
1881 ret = GetTextFaceA(hdc, sizeof(name), name);
1882 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1884 if (charset == SYMBOL_CHARSET)
1886 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1887 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1891 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1892 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1895 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1897 trace("Can't find codepage for charset %d\n", cs);
1901 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1903 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1905 skip("Font code page %d, looking for code page %d\n",
1906 pGdiGetCodePage(hdc), code_page);
1914 WCHAR unicode_buf[128];
1916 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1918 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1920 SetLastError(0xdeadbeef);
1921 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1922 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1923 count, ret, GetLastError());
1929 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1931 SetLastError(0xdeadbeef);
1932 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1933 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1934 count, ret, GetLastError());
1937 SelectObject(hdc, hfont_old);
1938 DeleteObject(hfont);
1945 static void test_font_charset(void)
1947 static struct charset_data
1951 WORD font_idxA[128], font_idxW[128];
1954 { ANSI_CHARSET, 1252 },
1955 { RUSSIAN_CHARSET, 1251 },
1956 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1960 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1962 win_skip("Skipping the font charset test on a Win9x platform\n");
1966 if (!is_font_installed("Arial"))
1968 skip("Arial is not installed\n");
1972 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1974 if (cd[i].charset == SYMBOL_CHARSET)
1976 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1978 skip("Symbol or Wingdings is not installed\n");
1982 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1983 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1984 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1987 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1990 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1991 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1994 skip("Symbol or Wingdings is not installed\n");
1997 static void test_GetFontUnicodeRanges(void)
2001 HFONT hfont, hfont_old;
2006 if (!pGetFontUnicodeRanges)
2008 win_skip("GetFontUnicodeRanges not available before W2K\n");
2012 memset(&lf, 0, sizeof(lf));
2013 lstrcpyA(lf.lfFaceName, "Arial");
2014 hfont = create_font("Arial", &lf);
2017 hfont_old = SelectObject(hdc, hfont);
2019 size = pGetFontUnicodeRanges(NULL, NULL);
2020 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2022 size = pGetFontUnicodeRanges(hdc, NULL);
2023 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2025 gs = HeapAlloc(GetProcessHeap(), 0, size);
2027 size = pGetFontUnicodeRanges(hdc, gs);
2028 ok(size, "GetFontUnicodeRanges failed\n");
2030 if (0) /* Disabled to limit console spam */
2031 for (i = 0; i < gs->cRanges; i++)
2032 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2033 trace("found %u ranges\n", gs->cRanges);
2035 HeapFree(GetProcessHeap(), 0, gs);
2037 SelectObject(hdc, hfont_old);
2038 DeleteObject(hfont);
2039 ReleaseDC(NULL, hdc);
2042 #define MAX_ENUM_FONTS 4096
2044 struct enum_font_data
2047 LOGFONT lf[MAX_ENUM_FONTS];
2050 struct enum_font_dataW
2053 LOGFONTW lf[MAX_ENUM_FONTS];
2056 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2058 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2059 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2061 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2062 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2064 if (type != TRUETYPE_FONTTYPE) return 1;
2066 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2068 if (0) /* Disabled to limit console spam */
2069 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2070 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2071 if (efd->total < MAX_ENUM_FONTS)
2072 efd->lf[efd->total++] = *lf;
2074 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2079 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2081 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2082 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2084 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2085 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2087 if (type != TRUETYPE_FONTTYPE) return 1;
2089 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2091 if (0) /* Disabled to limit console spam */
2092 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2093 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2094 if (efd->total < MAX_ENUM_FONTS)
2095 efd->lf[efd->total++] = *lf;
2097 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2102 static void get_charset_stats(struct enum_font_data *efd,
2103 int *ansi_charset, int *symbol_charset,
2104 int *russian_charset)
2109 *symbol_charset = 0;
2110 *russian_charset = 0;
2112 for (i = 0; i < efd->total; i++)
2114 switch (efd->lf[i].lfCharSet)
2119 case SYMBOL_CHARSET:
2120 (*symbol_charset)++;
2122 case RUSSIAN_CHARSET:
2123 (*russian_charset)++;
2129 static void get_charset_statsW(struct enum_font_dataW *efd,
2130 int *ansi_charset, int *symbol_charset,
2131 int *russian_charset)
2136 *symbol_charset = 0;
2137 *russian_charset = 0;
2139 for (i = 0; i < efd->total; i++)
2141 switch (efd->lf[i].lfCharSet)
2146 case SYMBOL_CHARSET:
2147 (*symbol_charset)++;
2149 case RUSSIAN_CHARSET:
2150 (*russian_charset)++;
2156 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2158 struct enum_font_data efd;
2159 struct enum_font_dataW efdw;
2162 int i, ret, ansi_charset, symbol_charset, russian_charset;
2164 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2166 if (*font_name && !is_truetype_font_installed(font_name))
2168 skip("%s is not installed\n", font_name);
2174 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2175 * while EnumFontFamiliesEx doesn't.
2177 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2180 * Use EnumFontFamiliesW since win98 crashes when the
2181 * second parameter is NULL using EnumFontFamilies
2184 SetLastError(0xdeadbeef);
2185 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2186 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2189 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2190 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2191 ansi_charset, symbol_charset, russian_charset);
2192 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2193 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2194 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2195 ok(russian_charset > 0 ||
2196 broken(russian_charset == 0), /* NT4 */
2197 "NULL family should enumerate RUSSIAN_CHARSET\n");
2201 SetLastError(0xdeadbeef);
2202 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2203 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2206 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2207 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2208 ansi_charset, symbol_charset, russian_charset);
2209 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2210 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2211 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2212 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2217 SetLastError(0xdeadbeef);
2218 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2219 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2220 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2221 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2222 ansi_charset, symbol_charset, russian_charset,
2223 *font_name ? font_name : "<empty>");
2225 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2227 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2228 for (i = 0; i < efd.total; i++)
2230 /* FIXME: remove completely once Wine is fixed */
2231 if (efd.lf[i].lfCharSet != font_charset)
2234 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2237 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2238 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2239 font_name, efd.lf[i].lfFaceName);
2242 memset(&lf, 0, sizeof(lf));
2243 lf.lfCharSet = ANSI_CHARSET;
2244 lstrcpy(lf.lfFaceName, font_name);
2246 SetLastError(0xdeadbeef);
2247 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2248 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2249 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2250 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2251 ansi_charset, symbol_charset, russian_charset,
2252 *font_name ? font_name : "<empty>");
2253 if (font_charset == SYMBOL_CHARSET)
2256 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2258 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2262 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2263 for (i = 0; i < efd.total; i++)
2265 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2267 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2268 font_name, efd.lf[i].lfFaceName);
2272 /* DEFAULT_CHARSET should enumerate all available charsets */
2273 memset(&lf, 0, sizeof(lf));
2274 lf.lfCharSet = DEFAULT_CHARSET;
2275 lstrcpy(lf.lfFaceName, font_name);
2277 SetLastError(0xdeadbeef);
2278 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2279 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2280 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2281 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2282 ansi_charset, symbol_charset, russian_charset,
2283 *font_name ? font_name : "<empty>");
2284 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2285 for (i = 0; i < efd.total; i++)
2288 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2289 font_name, efd.lf[i].lfFaceName);
2293 switch (font_charset)
2296 ok(ansi_charset > 0,
2297 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2299 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2300 ok(russian_charset > 0,
2301 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2303 case SYMBOL_CHARSET:
2305 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2307 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2308 ok(!russian_charset,
2309 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2311 case DEFAULT_CHARSET:
2312 ok(ansi_charset > 0,
2313 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2314 ok(symbol_charset > 0,
2315 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2316 ok(russian_charset > 0,
2317 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2323 ok(ansi_charset > 0,
2324 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2325 ok(symbol_charset > 0,
2326 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2327 ok(russian_charset > 0,
2328 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2331 memset(&lf, 0, sizeof(lf));
2332 lf.lfCharSet = SYMBOL_CHARSET;
2333 lstrcpy(lf.lfFaceName, font_name);
2335 SetLastError(0xdeadbeef);
2336 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2337 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2338 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2339 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2340 ansi_charset, symbol_charset, russian_charset,
2341 *font_name ? font_name : "<empty>");
2342 if (*font_name && font_charset == ANSI_CHARSET)
2343 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2346 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2347 for (i = 0; i < efd.total; i++)
2349 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2351 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2352 font_name, efd.lf[i].lfFaceName);
2356 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2357 ok(symbol_charset > 0,
2358 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2359 ok(!russian_charset,
2360 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2366 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2368 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2370 if (type != TRUETYPE_FONTTYPE) return 1;
2372 if (efd->total < MAX_ENUM_FONTS)
2373 efd->lf[efd->total++] = *lf;
2375 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2380 static void test_EnumFontFamiliesEx_default_charset(void)
2382 struct enum_font_data efd;
2383 LOGFONT gui_font, enum_font;
2387 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2388 ok(ret, "GetObject failed.\n");
2395 memset(&enum_font, 0, sizeof(enum_font));
2396 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2397 enum_font.lfCharSet = DEFAULT_CHARSET;
2398 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2401 if (efd.total == 0) {
2402 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2405 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2407 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2408 "(%s) got charset %d expected %d\n",
2409 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2414 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2416 HFONT hfont, hfont_prev;
2418 GLYPHMETRICS gm1, gm2;
2422 if(!pGetGlyphIndicesA)
2425 /* negative widths are handled just as positive ones */
2426 lf2.lfWidth = -lf->lfWidth;
2428 SetLastError(0xdeadbeef);
2429 hfont = CreateFontIndirectA(lf);
2430 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2431 check_font("original", lf, hfont);
2433 hfont_prev = SelectObject(hdc, hfont);
2435 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2436 if (ret == GDI_ERROR || idx == 0xffff)
2438 SelectObject(hdc, hfont_prev);
2439 DeleteObject(hfont);
2440 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2444 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2445 memset(&gm1, 0xab, sizeof(gm1));
2446 SetLastError(0xdeadbeef);
2447 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2448 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2450 SelectObject(hdc, hfont_prev);
2451 DeleteObject(hfont);
2453 SetLastError(0xdeadbeef);
2454 hfont = CreateFontIndirectA(&lf2);
2455 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2456 check_font("negative width", &lf2, hfont);
2458 hfont_prev = SelectObject(hdc, hfont);
2460 memset(&gm2, 0xbb, sizeof(gm2));
2461 SetLastError(0xdeadbeef);
2462 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2463 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2465 SelectObject(hdc, hfont_prev);
2466 DeleteObject(hfont);
2468 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2469 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2470 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2471 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2472 gm1.gmCellIncX == gm2.gmCellIncX &&
2473 gm1.gmCellIncY == gm2.gmCellIncY,
2474 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2475 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2476 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2477 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2478 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2481 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2482 #include "pshpack2.h"
2486 SHORT xAvgCharWidth;
2487 USHORT usWeightClass;
2488 USHORT usWidthClass;
2490 SHORT ySubscriptXSize;
2491 SHORT ySubscriptYSize;
2492 SHORT ySubscriptXOffset;
2493 SHORT ySubscriptYOffset;
2494 SHORT ySuperscriptXSize;
2495 SHORT ySuperscriptYSize;
2496 SHORT ySuperscriptXOffset;
2497 SHORT ySuperscriptYOffset;
2498 SHORT yStrikeoutSize;
2499 SHORT yStrikeoutPosition;
2502 ULONG ulUnicodeRange1;
2503 ULONG ulUnicodeRange2;
2504 ULONG ulUnicodeRange3;
2505 ULONG ulUnicodeRange4;
2508 USHORT usFirstCharIndex;
2509 USHORT usLastCharIndex;
2510 /* According to the Apple spec, original version didn't have the below fields,
2511 * version numbers were taken from the OpenType spec.
2513 /* version 0 (TrueType 1.5) */
2514 USHORT sTypoAscender;
2515 USHORT sTypoDescender;
2516 USHORT sTypoLineGap;
2518 USHORT usWinDescent;
2519 /* version 1 (TrueType 1.66) */
2520 ULONG ulCodePageRange1;
2521 ULONG ulCodePageRange2;
2522 /* version 2 (OpenType 1.2) */
2525 USHORT usDefaultChar;
2527 USHORT usMaxContext;
2529 #include "poppack.h"
2531 #ifdef WORDS_BIGENDIAN
2532 #define GET_BE_WORD(x) (x)
2533 #define GET_BE_DWORD(x) (x)
2535 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2536 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2539 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2540 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2541 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2542 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2543 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2544 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2557 } cmap_encoding_record;
2565 BYTE glyph_ids[256];
2575 USHORT search_range;
2576 USHORT entry_selector;
2579 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2582 USHORT start_count[seg_countx2 / 2];
2583 USHORT id_delta[seg_countx2 / 2];
2584 USHORT id_range_offset[seg_countx2 / 2];
2594 USHORT id_range_offset;
2595 } cmap_format_4_seg;
2597 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2599 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2600 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2601 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2602 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2603 os2->panose.bWeight, os2->panose.bProportion);
2606 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2609 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2613 for(i = 0; i < 256; i++)
2615 if(cmap->glyph_ids[i] == 0) continue;
2617 if(*first == 256) *first = i;
2619 if(*first == 256) return FALSE;
2623 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2625 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2626 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2627 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2628 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2629 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2632 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2635 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2636 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2637 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2641 for(i = 0; i < seg_count; i++)
2644 cmap_format_4_seg seg;
2646 get_seg4(cmap, i, &seg);
2647 for(code = seg.start_count; code <= seg.end_count; code++)
2649 if(seg.id_range_offset == 0)
2650 index = (seg.id_delta + code) & 0xffff;
2653 index = seg.id_range_offset / 2
2654 + code - seg.start_count
2657 /* some fonts have broken last segment */
2658 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2659 index = GET_BE_WORD(glyph_ids[index]);
2662 trace("segment %04x/%04x index %04x points to nowhere\n",
2663 seg.start_count, seg.end_count, index);
2666 if(index) index += seg.id_delta;
2668 if(*first == 0x10000)
2669 *last = *first = code;
2675 if(*first == 0x10000) return FALSE;
2679 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2682 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2684 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2686 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2687 return (BYTE *)header + GET_BE_DWORD(record->offset);
2700 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2703 cmap_header *header;
2708 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2709 ok(size != GDI_ERROR, "no cmap table found\n");
2710 if(size == GDI_ERROR) return FALSE;
2712 header = HeapAlloc(GetProcessHeap(), 0, size);
2713 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2714 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2715 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2717 cmap = get_cmap(header, 3, 1);
2719 *cmap_type = cmap_ms_unicode;
2722 cmap = get_cmap(header, 3, 0);
2723 if(cmap) *cmap_type = cmap_ms_symbol;
2727 *cmap_type = cmap_none;
2731 format = GET_BE_WORD(*(WORD *)cmap);
2735 r = get_first_last_from_cmap0(cmap, first, last);
2738 r = get_first_last_from_cmap4(cmap, first, last, size);
2741 trace("unhandled cmap format %d\n", format);
2746 HeapFree(GetProcessHeap(), 0, header);
2750 #define TT_PLATFORM_MICROSOFT 3
2751 #define TT_MS_ID_UNICODE_CS 1
2752 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2753 #define TT_NAME_ID_FULL_NAME 4
2755 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2757 struct sfnt_name_header
2760 USHORT number_of_record;
2761 USHORT storage_offset;
2773 LONG size, offset, length;
2779 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2780 ok(size != GDI_ERROR, "no name table found\n");
2781 if(size == GDI_ERROR) return FALSE;
2783 data = HeapAlloc(GetProcessHeap(), 0, size);
2784 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2785 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2787 header = (void *)data;
2788 header->format = GET_BE_WORD(header->format);
2789 header->number_of_record = GET_BE_WORD(header->number_of_record);
2790 header->storage_offset = GET_BE_WORD(header->storage_offset);
2791 if (header->format != 0)
2793 trace("got format %u\n", header->format);
2796 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2798 trace("number records out of range: %d\n", header->number_of_record);
2801 if (header->storage_offset >= size)
2803 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2807 entry = (void *)&header[1];
2808 for (i = 0; i < header->number_of_record; i++)
2810 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2811 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2812 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2813 GET_BE_WORD(entry[i].name_id) != name_id)
2818 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2819 length = GET_BE_WORD(entry[i].length);
2820 if (offset + length > size)
2822 trace("entry %d is out of range\n", i);
2825 if (length >= out_size)
2827 trace("buffer too small for entry %d\n", i);
2831 name = (WCHAR *)(data + offset);
2832 for (c = 0; c < length / 2; c++)
2833 out_buf[c] = GET_BE_WORD(name[c]);
2841 HeapFree(GetProcessHeap(), 0, data);
2845 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2848 HFONT hfont, hfont_old;
2852 const char *font_name = lf->lfFaceName;
2853 DWORD cmap_first = 0, cmap_last = 0;
2854 UINT ascent, descent, cell_height;
2855 cmap_type cmap_type;
2856 BOOL sys_lang_non_english;
2858 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2861 SetLastError(0xdeadbeef);
2862 hfont = CreateFontIndirectA(lf);
2863 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2865 hfont_old = SelectObject(hdc, hfont);
2867 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2868 if (size == GDI_ERROR)
2870 trace("OS/2 chunk was not found\n");
2873 if (size > sizeof(tt_os2))
2875 trace("got too large OS/2 chunk of size %u\n", size);
2876 size = sizeof(tt_os2);
2879 memset(&tt_os2, 0, sizeof(tt_os2));
2880 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2881 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2883 ascent = GET_BE_WORD(tt_os2.usWinAscent);
2884 descent = GET_BE_WORD(tt_os2.usWinDescent);
2885 cell_height = ascent + descent;
2886 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
2887 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
2889 SetLastError(0xdeadbeef);
2890 ret = GetTextMetricsA(hdc, &tmA);
2891 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2893 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2895 skip("Unable to retrieve first and last glyphs from cmap\n");
2899 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2900 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2901 UINT os2_first_char, os2_last_char, default_char, break_char;
2905 version = GET_BE_WORD(tt_os2.version);
2907 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2908 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2909 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2910 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2912 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2913 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2914 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2916 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2921 case 1257: /* Baltic */
2922 expect_last_W = 0xf8fd;
2925 expect_last_W = 0xf0ff;
2927 expect_break_W = 0x20;
2928 expect_default_W = expect_break_W - 1;
2929 expect_first_A = 0x1e;
2930 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2934 expect_first_W = cmap_first;
2935 expect_last_W = min(cmap_last, os2_last_char);
2936 if(os2_first_char <= 1)
2937 expect_break_W = os2_first_char + 2;
2938 else if(os2_first_char > 0xff)
2939 expect_break_W = 0x20;
2941 expect_break_W = os2_first_char;
2942 expect_default_W = expect_break_W - 1;
2943 expect_first_A = expect_default_W - 1;
2944 expect_last_A = min(expect_last_W, 0xff);
2946 expect_break_A = expect_break_W;
2947 expect_default_A = expect_default_W;
2949 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2950 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2951 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2952 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2953 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2955 ok(tmA.tmFirstChar == expect_first_A ||
2956 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2957 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2958 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2959 ok(tmA.tmLastChar == expect_last_A ||
2960 tmA.tmLastChar == 0xff /* win9x */,
2961 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2963 skip("tmLastChar is DBCS lead byte\n");
2964 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2965 font_name, tmA.tmBreakChar, expect_break_A);
2966 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2967 "A: tmDefaultChar for %s got %02x expected %02x\n",
2968 font_name, tmA.tmDefaultChar, expect_default_A);
2971 SetLastError(0xdeadbeef);
2972 ret = GetTextMetricsW(hdc, &tmW);
2973 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2974 "GetTextMetricsW error %u\n", GetLastError());
2977 /* Wine uses the os2 first char */
2978 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2979 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2980 font_name, tmW.tmFirstChar, expect_first_W);
2982 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2983 font_name, tmW.tmFirstChar, expect_first_W);
2985 /* Wine uses the os2 last char */
2986 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2987 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2988 font_name, tmW.tmLastChar, expect_last_W);
2990 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2991 font_name, tmW.tmLastChar, expect_last_W);
2992 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2993 font_name, tmW.tmBreakChar, expect_break_W);
2994 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2995 "W: tmDefaultChar for %s got %02x expected %02x\n",
2996 font_name, tmW.tmDefaultChar, expect_default_W);
2998 /* Test the aspect ratio while we have tmW */
2999 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3000 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3001 tmW.tmDigitizedAspectX, ret);
3002 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3003 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3004 tmW.tmDigitizedAspectX, ret);
3008 /* test FF_ values */
3009 switch(tt_os2.panose.bFamilyType)
3013 case PAN_FAMILY_TEXT_DISPLAY:
3014 case PAN_FAMILY_PICTORIAL:
3016 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3017 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3019 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3022 switch(tt_os2.panose.bSerifStyle)
3027 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3030 case PAN_SERIF_COVE:
3031 case PAN_SERIF_OBTUSE_COVE:
3032 case PAN_SERIF_SQUARE_COVE:
3033 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3034 case PAN_SERIF_SQUARE:
3035 case PAN_SERIF_THIN:
3036 case PAN_SERIF_BONE:
3037 case PAN_SERIF_EXAGGERATED:
3038 case PAN_SERIF_TRIANGLE:
3039 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3042 case PAN_SERIF_NORMAL_SANS:
3043 case PAN_SERIF_OBTUSE_SANS:
3044 case PAN_SERIF_PERP_SANS:
3045 case PAN_SERIF_FLARED:
3046 case PAN_SERIF_ROUNDED:
3047 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3052 case PAN_FAMILY_SCRIPT:
3053 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3056 case PAN_FAMILY_DECORATIVE:
3057 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3061 test_negative_width(hdc, lf);
3064 SelectObject(hdc, hfont_old);
3065 DeleteObject(hfont);
3070 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3072 INT *enumed = (INT *)lParam;
3074 if (type == TRUETYPE_FONTTYPE)
3077 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3082 static void test_GetTextMetrics(void)
3088 /* Report only once */
3089 if(!pGetGlyphIndicesA)
3090 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3094 memset(&lf, 0, sizeof(lf));
3095 lf.lfCharSet = DEFAULT_CHARSET;
3097 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3098 trace("Tested metrics of %d truetype fonts\n", enumed);
3103 static void test_nonexistent_font(void)
3111 { "Times New Roman Baltic", 186 },
3112 { "Times New Roman CE", 238 },
3113 { "Times New Roman CYR", 204 },
3114 { "Times New Roman Greek", 161 },
3115 { "Times New Roman TUR", 162 }
3121 INT cs, expected_cs, i;
3122 char buf[LF_FACESIZE];
3124 if (!is_truetype_font_installed("Arial") ||
3125 !is_truetype_font_installed("Times New Roman"))
3127 skip("Arial or Times New Roman not installed\n");
3131 expected_cs = GetACP();
3132 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3134 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3137 expected_cs = csi.ciCharset;
3138 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3142 memset(&lf, 0, sizeof(lf));
3144 lf.lfWeight = FW_REGULAR;
3145 lf.lfCharSet = ANSI_CHARSET;
3146 lf.lfPitchAndFamily = FF_SWISS;
3147 strcpy(lf.lfFaceName, "Nonexistent font");
3148 hfont = CreateFontIndirectA(&lf);
3149 hfont = SelectObject(hdc, hfont);
3150 GetTextFaceA(hdc, sizeof(buf), buf);
3151 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3152 cs = GetTextCharset(hdc);
3153 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3154 DeleteObject(SelectObject(hdc, hfont));
3156 memset(&lf, 0, sizeof(lf));
3158 lf.lfWeight = FW_DONTCARE;
3159 strcpy(lf.lfFaceName, "Nonexistent font");
3160 hfont = CreateFontIndirectA(&lf);
3161 hfont = SelectObject(hdc, hfont);
3162 GetTextFaceA(hdc, sizeof(buf), buf);
3163 todo_wine /* Wine uses Arial for all substitutions */
3164 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3165 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3166 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3168 cs = GetTextCharset(hdc);
3169 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3170 DeleteObject(SelectObject(hdc, hfont));
3172 memset(&lf, 0, sizeof(lf));
3174 lf.lfWeight = FW_REGULAR;
3175 strcpy(lf.lfFaceName, "Nonexistent font");
3176 hfont = CreateFontIndirectA(&lf);
3177 hfont = SelectObject(hdc, hfont);
3178 GetTextFaceA(hdc, sizeof(buf), buf);
3179 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3180 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3181 cs = GetTextCharset(hdc);
3182 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3183 DeleteObject(SelectObject(hdc, hfont));
3185 memset(&lf, 0, sizeof(lf));
3187 lf.lfWeight = FW_DONTCARE;
3188 strcpy(lf.lfFaceName, "Times New Roman");
3189 hfont = CreateFontIndirectA(&lf);
3190 hfont = SelectObject(hdc, hfont);
3191 GetTextFaceA(hdc, sizeof(buf), buf);
3192 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3193 cs = GetTextCharset(hdc);
3194 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3195 DeleteObject(SelectObject(hdc, hfont));
3197 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3199 memset(&lf, 0, sizeof(lf));
3201 lf.lfWeight = FW_REGULAR;
3202 strcpy(lf.lfFaceName, font_subst[i].name);
3203 hfont = CreateFontIndirectA(&lf);
3204 hfont = SelectObject(hdc, hfont);
3205 cs = GetTextCharset(hdc);
3206 if (font_subst[i].charset == expected_cs)
3208 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3209 GetTextFaceA(hdc, sizeof(buf), buf);
3210 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3214 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3215 GetTextFaceA(hdc, sizeof(buf), buf);
3216 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3217 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3219 DeleteObject(SelectObject(hdc, hfont));
3221 memset(&lf, 0, sizeof(lf));
3223 lf.lfWeight = FW_DONTCARE;
3224 strcpy(lf.lfFaceName, font_subst[i].name);
3225 hfont = CreateFontIndirectA(&lf);
3226 hfont = SelectObject(hdc, hfont);
3227 GetTextFaceA(hdc, sizeof(buf), buf);
3228 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3229 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3230 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3231 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3232 "got %s for font %s\n", buf, font_subst[i].name);
3233 cs = GetTextCharset(hdc);
3234 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3235 DeleteObject(SelectObject(hdc, hfont));
3241 static void test_GdiRealizationInfo(void)
3246 HFONT hfont, hfont_old;
3249 if(!pGdiRealizationInfo)
3251 win_skip("GdiRealizationInfo not available\n");
3257 memset(info, 0xcc, sizeof(info));
3258 r = pGdiRealizationInfo(hdc, info);
3259 ok(r != 0, "ret 0\n");
3260 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3261 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3263 if (!is_truetype_font_installed("Arial"))
3265 skip("skipping GdiRealizationInfo with truetype font\n");
3269 memset(&lf, 0, sizeof(lf));
3270 strcpy(lf.lfFaceName, "Arial");
3272 lf.lfWeight = FW_NORMAL;
3273 hfont = CreateFontIndirectA(&lf);
3274 hfont_old = SelectObject(hdc, hfont);
3276 memset(info, 0xcc, sizeof(info));
3277 r = pGdiRealizationInfo(hdc, info);
3278 ok(r != 0, "ret 0\n");
3279 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3280 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3282 DeleteObject(SelectObject(hdc, hfont_old));
3288 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3289 the nul in the count of characters copied when the face name buffer is not
3290 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3291 always includes it. */
3292 static void test_GetTextFace(void)
3294 static const char faceA[] = "Tahoma";
3295 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3298 char bufA[LF_FACESIZE];
3299 WCHAR bufW[LF_FACESIZE];
3304 if(!is_font_installed("Tahoma"))
3306 skip("Tahoma is not installed so skipping this test\n");
3311 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3312 f = CreateFontIndirectA(&fA);
3313 ok(f != NULL, "CreateFontIndirectA failed\n");
3316 g = SelectObject(dc, f);
3317 n = GetTextFaceA(dc, sizeof bufA, bufA);
3318 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3319 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3321 /* Play with the count arg. */
3323 n = GetTextFaceA(dc, 0, bufA);
3324 ok(n == 0, "GetTextFaceA returned %d\n", n);
3325 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3328 n = GetTextFaceA(dc, 1, bufA);
3329 ok(n == 0, "GetTextFaceA returned %d\n", n);
3330 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3332 bufA[0] = 'x'; bufA[1] = 'y';
3333 n = GetTextFaceA(dc, 2, bufA);
3334 ok(n == 1, "GetTextFaceA returned %d\n", n);
3335 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3337 n = GetTextFaceA(dc, 0, NULL);
3338 ok(n == sizeof faceA ||
3339 broken(n == 0), /* win98, winMe */
3340 "GetTextFaceA returned %d\n", n);
3342 DeleteObject(SelectObject(dc, g));
3343 ReleaseDC(NULL, dc);
3346 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3347 SetLastError(0xdeadbeef);
3348 f = CreateFontIndirectW(&fW);
3349 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3351 win_skip("CreateFontIndirectW is not implemented\n");
3354 ok(f != NULL, "CreateFontIndirectW failed\n");
3357 g = SelectObject(dc, f);
3358 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3359 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3360 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3362 /* Play with the count arg. */
3364 n = GetTextFaceW(dc, 0, bufW);
3365 ok(n == 0, "GetTextFaceW returned %d\n", n);
3366 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3369 n = GetTextFaceW(dc, 1, bufW);
3370 ok(n == 1, "GetTextFaceW returned %d\n", n);
3371 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3373 bufW[0] = 'x'; bufW[1] = 'y';
3374 n = GetTextFaceW(dc, 2, bufW);
3375 ok(n == 2, "GetTextFaceW returned %d\n", n);
3376 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3378 n = GetTextFaceW(dc, 0, NULL);
3379 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3381 DeleteObject(SelectObject(dc, g));
3382 ReleaseDC(NULL, dc);
3385 static void test_orientation(void)
3387 static const char test_str[11] = "Test String";
3390 HFONT hfont, old_hfont;
3393 if (!is_truetype_font_installed("Arial"))
3395 skip("Arial is not installed\n");
3399 hdc = CreateCompatibleDC(0);
3400 memset(&lf, 0, sizeof(lf));
3401 lstrcpyA(lf.lfFaceName, "Arial");
3403 lf.lfOrientation = lf.lfEscapement = 900;
3404 hfont = create_font("orientation", &lf);
3405 old_hfont = SelectObject(hdc, hfont);
3406 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3407 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3408 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3409 SelectObject(hdc, old_hfont);
3410 DeleteObject(hfont);
3414 static void test_oemcharset(void)
3418 HFONT hfont, old_hfont;
3421 hdc = CreateCompatibleDC(0);
3422 ZeroMemory(&lf, sizeof(lf));
3424 lf.lfCharSet = OEM_CHARSET;
3425 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3426 lstrcpyA(lf.lfFaceName, "Terminal");
3427 hfont = CreateFontIndirectA(&lf);
3428 old_hfont = SelectObject(hdc, hfont);
3429 charset = GetTextCharset(hdc);
3431 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3432 hfont = SelectObject(hdc, old_hfont);
3433 GetObjectA(hfont, sizeof(clf), &clf);
3434 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3435 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3436 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3437 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3438 DeleteObject(hfont);
3442 static void test_GetGlyphOutline(void)
3445 GLYPHMETRICS gm, gm2;
3447 HFONT hfont, old_hfont;
3456 {ANSI_CHARSET, 0x30, 0x30},
3457 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3458 {HANGEUL_CHARSET, 0x8141, 0xac02},
3459 {JOHAB_CHARSET, 0x8446, 0x3135},
3460 {GB2312_CHARSET, 0x8141, 0x4e04},
3461 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3465 if (!is_truetype_font_installed("Tahoma"))
3467 skip("Tahoma is not installed\n");
3471 hdc = CreateCompatibleDC(0);
3472 memset(&lf, 0, sizeof(lf));
3474 lstrcpyA(lf.lfFaceName, "Tahoma");
3475 SetLastError(0xdeadbeef);
3476 hfont = CreateFontIndirectA(&lf);
3477 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3478 old_hfont = SelectObject(hdc, hfont);
3480 memset(&gm, 0, sizeof(gm));
3481 SetLastError(0xdeadbeef);
3482 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3483 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3485 memset(&gm, 0, sizeof(gm));
3486 SetLastError(0xdeadbeef);
3487 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3488 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3489 ok(GetLastError() == 0xdeadbeef ||
3490 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3491 "expected 0xdeadbeef, got %u\n", GetLastError());
3493 memset(&gm, 0, sizeof(gm));
3494 SetLastError(0xdeadbeef);
3495 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3496 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3497 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3499 memset(&gm, 0, sizeof(gm));
3500 SetLastError(0xdeadbeef);
3501 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3502 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3504 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3505 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3508 /* test for needed buffer size request on space char */
3509 memset(&gm, 0, sizeof(gm));
3510 SetLastError(0xdeadbeef);
3511 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3512 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3513 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3515 /* requesting buffer size for space char + error */
3516 memset(&gm, 0, sizeof(gm));
3517 SetLastError(0xdeadbeef);
3518 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3519 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3521 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3522 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3525 SelectObject(hdc, old_hfont);
3526 DeleteObject(hfont);
3528 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3530 lf.lfFaceName[0] = '\0';
3531 lf.lfCharSet = c[i].cs;
3532 lf.lfPitchAndFamily = 0;
3533 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3535 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3539 old_hfont = SelectObject(hdc, hfont);
3541 /* expected to ignore superfluous bytes (sigle-byte character) */
3542 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3543 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3544 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3546 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3547 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3548 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3550 /* expected to ignore superfluous bytes (double-byte character) */
3551 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3552 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3553 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3554 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3556 /* expected to match wide-char version results */
3557 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3558 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3560 hfont = SelectObject(hdc, old_hfont);
3561 DeleteObject(hfont);
3567 /* bug #9995: there is a limit to the character width that can be specified */
3568 static void test_GetTextMetrics2(const char *fontname, int font_height)
3574 int ave_width, height, width, ratio, scale;
3576 if (!is_truetype_font_installed( fontname)) {
3577 skip("%s is not installed\n", fontname);
3580 hdc = CreateCompatibleDC(0);
3581 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3582 /* select width = 0 */
3583 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3584 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3585 DEFAULT_QUALITY, VARIABLE_PITCH,
3587 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3588 of = SelectObject( hdc, hf);
3589 ret = GetTextMetricsA( hdc, &tm);
3590 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3591 height = tm.tmHeight;
3592 ave_width = tm.tmAveCharWidth;
3593 SelectObject( hdc, of);
3596 trace("height %d, ave width %d\n", height, ave_width);
3598 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3600 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3601 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3602 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3603 ok(hf != 0, "CreateFont failed\n");
3604 of = SelectObject(hdc, hf);
3605 ret = GetTextMetrics(hdc, &tm);
3606 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3607 SelectObject(hdc, of);
3610 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3616 ratio = width / height;
3617 scale = width / ave_width;
3619 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3620 width, height, ratio, width, ave_width, scale);
3622 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3625 static void test_CreateFontIndirect(void)
3627 LOGFONTA lf, getobj_lf;
3630 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3632 memset(&lf, 0, sizeof(lf));
3633 lf.lfCharSet = ANSI_CHARSET;
3634 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3637 lf.lfQuality = DEFAULT_QUALITY;
3638 lf.lfItalic = FALSE;
3639 lf.lfWeight = FW_DONTCARE;
3641 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3643 lstrcpyA(lf.lfFaceName, TestName[i]);
3644 hfont = CreateFontIndirectA(&lf);
3645 ok(hfont != 0, "CreateFontIndirectA failed\n");
3646 SetLastError(0xdeadbeef);
3647 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3648 ok(ret, "GetObject failed: %d\n", GetLastError());
3649 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3650 ok(lf.lfWeight == getobj_lf.lfWeight ||
3651 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3652 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3653 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3654 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3655 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3656 DeleteObject(hfont);
3660 static void test_CreateFontIndirectEx(void)
3662 ENUMLOGFONTEXDVA lfex;
3665 if (!pCreateFontIndirectExA)
3667 win_skip("CreateFontIndirectExA is not available\n");
3671 if (!is_truetype_font_installed("Arial"))
3673 skip("Arial is not installed\n");
3677 SetLastError(0xdeadbeef);
3678 hfont = pCreateFontIndirectExA(NULL);
3679 ok(hfont == NULL, "got %p\n", hfont);
3680 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3682 memset(&lfex, 0, sizeof(lfex));
3683 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3684 hfont = pCreateFontIndirectExA(&lfex);
3685 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3687 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3688 DeleteObject(hfont);
3691 static void free_font(void *font)
3693 UnmapViewOfFile(font);
3696 static void *load_font(const char *font_name, DWORD *font_size)
3698 char file_name[MAX_PATH];
3699 HANDLE file, mapping;
3702 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3703 strcat(file_name, "\\fonts\\");
3704 strcat(file_name, font_name);
3706 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3707 if (file == INVALID_HANDLE_VALUE) return NULL;
3709 *font_size = GetFileSize(file, NULL);
3711 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3718 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3721 CloseHandle(mapping);
3725 static void test_AddFontMemResource(void)
3728 DWORD font_size, num_fonts;
3732 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3734 win_skip("AddFontMemResourceEx is not available on this platform\n");
3738 font = load_font("sserife.fon", &font_size);
3741 skip("Unable to locate and load font sserife.fon\n");
3745 SetLastError(0xdeadbeef);
3746 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3747 ok(!ret, "AddFontMemResourceEx should fail\n");
3748 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3749 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3752 SetLastError(0xdeadbeef);
3753 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3754 ok(!ret, "AddFontMemResourceEx should fail\n");
3755 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3756 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3759 SetLastError(0xdeadbeef);
3760 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3761 ok(!ret, "AddFontMemResourceEx should fail\n");
3762 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3763 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3766 SetLastError(0xdeadbeef);
3767 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3768 ok(!ret, "AddFontMemResourceEx should fail\n");
3769 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3770 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3773 SetLastError(0xdeadbeef);
3774 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3775 ok(!ret, "AddFontMemResourceEx should fail\n");
3776 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3777 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3780 SetLastError(0xdeadbeef);
3781 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3782 ok(!ret, "AddFontMemResourceEx should fail\n");
3783 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3784 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3787 num_fonts = 0xdeadbeef;
3788 SetLastError(0xdeadbeef);
3789 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3790 ok(!ret, "AddFontMemResourceEx should fail\n");
3791 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3792 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3794 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3796 if (0) /* hangs under windows 2000 */
3798 num_fonts = 0xdeadbeef;
3799 SetLastError(0xdeadbeef);
3800 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3801 ok(!ret, "AddFontMemResourceEx should fail\n");
3802 ok(GetLastError() == 0xdeadbeef,
3803 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3805 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3808 num_fonts = 0xdeadbeef;
3809 SetLastError(0xdeadbeef);
3810 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3811 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3812 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3813 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3817 SetLastError(0xdeadbeef);
3818 bRet = pRemoveFontMemResourceEx(ret);
3819 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3821 /* test invalid pointer to number of loaded fonts */
3822 font = load_font("sserife.fon", &font_size);
3823 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3825 SetLastError(0xdeadbeef);
3826 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3827 ok(!ret, "AddFontMemResourceEx should fail\n");
3828 ok(GetLastError() == 0xdeadbeef,
3829 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3832 SetLastError(0xdeadbeef);
3833 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3834 ok(!ret, "AddFontMemResourceEx should fail\n");
3835 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3836 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3842 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3846 if (type != TRUETYPE_FONTTYPE) return 1;
3848 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3850 lf = (LOGFONT *)lparam;
3855 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3860 if (type != TRUETYPE_FONTTYPE) return 1;
3862 lf = (LOGFONT *)lparam;
3863 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3866 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3873 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3878 static void test_EnumFonts(void)
3884 if (!is_truetype_font_installed("Arial"))
3886 skip("Arial is not installed\n");
3890 /* Windows uses localized font face names, so Arial Bold won't be found */
3891 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3893 skip("User locale is not English, skipping the test\n");
3897 hdc = CreateCompatibleDC(0);
3899 /* check that the enumproc's retval is returned */
3900 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
3901 ok(ret == 0xcafe, "got %08x\n", ret);
3903 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3904 ok(!ret, "font Arial is not enumerated\n");
3905 ret = strcmp(lf.lfFaceName, "Arial");
3906 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3907 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3909 lstrcpy(lf.lfFaceName, "Arial");
3910 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3911 ok(!ret, "font Arial is not enumerated\n");
3912 ret = strcmp(lf.lfFaceName, "Arial");
3913 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3914 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3916 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3917 ok(!ret, "font Arial Bold is not enumerated\n");
3918 ret = strcmp(lf.lfFaceName, "Arial");
3919 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3920 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3922 lstrcpy(lf.lfFaceName, "Arial Bold");
3923 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3924 ok(ret, "font Arial Bold should not be enumerated\n");
3926 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3927 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3928 ret = strcmp(lf.lfFaceName, "Arial");
3929 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3930 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3932 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3933 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3934 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3936 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3937 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3939 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3940 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3941 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3946 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3948 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3949 const char *fullname = (const char *)lParam;
3951 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3956 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3961 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3968 static void test_fullname(void)
3970 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3971 char buf[LF_FULLFACESIZE];
3977 hdc = CreateCompatibleDC(0);
3978 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3980 memset(&lf, 0, sizeof(lf));
3981 lf.lfCharSet = ANSI_CHARSET;
3982 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3985 lf.lfQuality = DEFAULT_QUALITY;
3986 lf.lfItalic = FALSE;
3987 lf.lfWeight = FW_DONTCARE;
3989 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3991 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3993 skip("%s is not installed\n", TestName[i]);
3997 lstrcpyA(lf.lfFaceName, TestName[i]);
3998 hfont = CreateFontIndirectA(&lf);
3999 ok(hfont != 0, "CreateFontIndirectA failed\n");
4001 of = SelectObject(hdc, hfont);
4003 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
4004 "face full name could not be read\n");
4005 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
4006 SelectObject(hdc, of);
4007 DeleteObject(hfont);
4012 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4014 char tmp_path[MAX_PATH];
4021 SetLastError(0xdeadbeef);
4022 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4023 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4024 if (!rsrc) return FALSE;
4025 SetLastError(0xdeadbeef);
4026 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4027 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4028 if (!rsrc_data) return FALSE;
4029 SetLastError(0xdeadbeef);
4030 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4031 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4032 if (!rsrc_size) return FALSE;
4034 SetLastError(0xdeadbeef);
4035 ret = GetTempPath(MAX_PATH, tmp_path);
4036 ok(ret, "GetTempPath() error %d\n", GetLastError());
4037 SetLastError(0xdeadbeef);
4038 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4039 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4041 SetLastError(0xdeadbeef);
4042 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4043 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4044 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4046 SetLastError(0xdeadbeef);
4047 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4048 ok(ret, "WriteFile() error %d\n", GetLastError());
4054 static void test_CreateScalableFontResource(void)
4056 char ttf_name[MAX_PATH];
4057 char tmp_path[MAX_PATH];
4058 char fot_name[MAX_PATH];
4062 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4064 win_skip("AddFontResourceExA is not available on this platform\n");
4068 if (!write_ttf_file("wine_test.ttf", ttf_name))
4070 skip("Failed to create ttf file for testing\n");
4074 trace("created %s\n", ttf_name);
4076 ret = is_truetype_font_installed("wine_test");
4077 ok(!ret, "font wine_test should not be enumerated\n");
4079 ret = GetTempPath(MAX_PATH, tmp_path);
4080 ok(ret, "GetTempPath() error %d\n", GetLastError());
4081 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4082 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4084 ret = GetFileAttributes(fot_name);
4085 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4087 SetLastError(0xdeadbeef);
4088 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4089 ok(!ret, "CreateScalableFontResource() should fail\n");
4090 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4092 SetLastError(0xdeadbeef);
4093 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4094 ok(!ret, "CreateScalableFontResource() should fail\n");
4095 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4097 file_part = strrchr(ttf_name, '\\');
4098 SetLastError(0xdeadbeef);
4099 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4100 ok(!ret, "CreateScalableFontResource() should fail\n");
4101 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4103 SetLastError(0xdeadbeef);
4104 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4105 ok(!ret, "CreateScalableFontResource() should fail\n");
4106 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4108 SetLastError(0xdeadbeef);
4109 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4110 ok(!ret, "CreateScalableFontResource() should fail\n");
4111 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4113 ret = DeleteFile(fot_name);
4114 ok(ret, "DeleteFile() error %d\n", GetLastError());
4116 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4118 ok(!ret, "RemoveFontResourceEx() should fail\n");
4120 /* test public font resource */
4121 SetLastError(0xdeadbeef);
4122 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4123 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4125 ret = is_truetype_font_installed("wine_test");
4126 ok(!ret, "font wine_test should not be enumerated\n");
4128 SetLastError(0xdeadbeef);
4129 ret = pAddFontResourceExA(fot_name, 0, 0);
4130 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4132 ret = is_truetype_font_installed("wine_test");
4133 ok(ret, "font wine_test should be enumerated\n");
4135 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4137 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4139 SetLastError(0xdeadbeef);
4140 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4141 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4143 ret = is_truetype_font_installed("wine_test");
4145 ok(!ret, "font wine_test should not be enumerated\n");
4147 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4150 /* remove once RemoveFontResource is implemented */
4151 DeleteFile(fot_name);
4152 DeleteFile(ttf_name);
4156 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4157 ok(!ret, "RemoveFontResourceEx() should fail\n");
4159 DeleteFile(fot_name);
4161 /* test hidden font resource */
4162 SetLastError(0xdeadbeef);
4163 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4164 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4166 ret = is_truetype_font_installed("wine_test");
4167 ok(!ret, "font wine_test should not be enumerated\n");
4169 SetLastError(0xdeadbeef);
4170 ret = pAddFontResourceExA(fot_name, 0, 0);
4171 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4173 ret = is_truetype_font_installed("wine_test");
4174 ok(!ret, "font wine_test should not be enumerated\n");
4176 /* XP allows removing a private font added with 0 flags */
4177 SetLastError(0xdeadbeef);
4178 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4179 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4181 ret = is_truetype_font_installed("wine_test");
4182 ok(!ret, "font wine_test should not be enumerated\n");
4184 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4185 ok(!ret, "RemoveFontResourceEx() should fail\n");
4187 DeleteFile(fot_name);
4188 DeleteFile(ttf_name);
4191 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4194 HFONT hfont, hfont_prev;
4198 static const WCHAR str[] = { 0x2025 };
4200 *installed = is_truetype_font_installed(name);
4204 lf.lfEscapement = 0;
4205 lf.lfOrientation = 0;
4206 lf.lfWeight = FW_DONTCARE;
4210 lf.lfCharSet = DEFAULT_CHARSET;
4211 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4212 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4213 lf.lfQuality = DEFAULT_QUALITY;
4214 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4215 strcpy(lf.lfFaceName, name);
4217 hfont = CreateFontIndirectA(&lf);
4218 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4222 hfont_prev = SelectObject(hdc, hfont);
4223 ok(hfont_prev != NULL, "SelectObject failed\n");
4225 ret = GetTextFaceA(hdc, sizeof facename, facename);
4226 ok(ret, "GetTextFaceA failed\n");
4227 *selected = !strcmp(facename, name);
4229 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4230 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4232 memset(gm, 0, sizeof *gm);
4234 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4235 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4237 SelectObject(hdc, hfont_prev);
4238 DeleteObject(hfont);
4239 ReleaseDC(NULL, hdc);
4242 static void test_vertical_font(void)
4244 char ttf_name[MAX_PATH];
4246 BOOL ret, installed, selected;
4250 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4252 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4256 if (!write_ttf_file("vertical.ttf", ttf_name))
4258 skip("Failed to create ttf file for testing\n");
4262 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4263 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4265 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4266 ok(installed, "@WineTestVertical is not installed\n");
4267 ok(selected, "@WineTestVertical is not selected\n");
4268 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4269 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4270 gm.gmBlackBoxX, gm.gmBlackBoxY);
4272 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4273 ok(installed, "@@WineTestVertical is not installed\n");
4274 ok(selected, "@@WineTestVertical is not selected\n");
4275 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4276 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4277 gm.gmBlackBoxX, gm.gmBlackBoxY);
4279 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4281 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4282 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4284 DeleteFile(ttf_name);
4287 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4288 DWORD type, LPARAM lParam)
4290 if (lf->lfFaceName[0] == '@') {
4296 static void test_east_asian_font_selection(void)
4299 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4300 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4305 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4309 char face_name[LF_FACESIZE];
4312 memset(&lf, 0, sizeof lf);
4313 lf.lfFaceName[0] = '\0';
4314 lf.lfCharSet = charset[i];
4316 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4318 skip("Vertical font for charset %u is not installed\n", charset[i]);
4322 hfont = CreateFontIndirectA(&lf);
4323 hfont = SelectObject(hdc, hfont);
4324 memset(face_name, 0, sizeof face_name);
4325 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4326 ok(ret && face_name[0] != '@',
4327 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4328 DeleteObject(SelectObject(hdc, hfont));
4330 memset(&lf, 0, sizeof lf);
4331 strcpy(lf.lfFaceName, "@");
4332 lf.lfCharSet = charset[i];
4333 hfont = CreateFontIndirectA(&lf);
4334 hfont = SelectObject(hdc, hfont);
4335 memset(face_name, 0, sizeof face_name);
4336 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4337 ok(ret && face_name[0] == '@',
4338 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4339 DeleteObject(SelectObject(hdc, hfont));
4341 ReleaseDC(NULL, hdc);
4350 test_outline_font();
4351 test_bitmap_font_metrics();
4352 test_GdiGetCharDimensions();
4353 test_GetCharABCWidths();
4354 test_text_extents();
4355 test_GetGlyphIndices();
4356 test_GetKerningPairs();
4357 test_GetOutlineTextMetrics();
4358 test_SetTextJustification();
4359 test_font_charset();
4360 test_GetFontUnicodeRanges();
4361 test_nonexistent_font();
4363 test_height_selection();
4364 test_AddFontMemResource();
4367 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4368 * I'd like to avoid them in this test.
4370 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4371 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4372 if (is_truetype_font_installed("Arial Black") &&
4373 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4375 test_EnumFontFamilies("", ANSI_CHARSET);
4376 test_EnumFontFamilies("", SYMBOL_CHARSET);
4377 test_EnumFontFamilies("", DEFAULT_CHARSET);
4380 skip("Arial Black or Symbol/Wingdings is not installed\n");
4381 test_EnumFontFamiliesEx_default_charset();
4382 test_GetTextMetrics();
4383 test_GdiRealizationInfo();
4385 test_GetGlyphOutline();
4386 test_GetTextMetrics2("Tahoma", -11);
4387 test_GetTextMetrics2("Tahoma", -55);
4388 test_GetTextMetrics2("Tahoma", -110);
4389 test_GetTextMetrics2("Arial", -11);
4390 test_GetTextMetrics2("Arial", -55);
4391 test_GetTextMetrics2("Arial", -110);
4392 test_CreateFontIndirect();
4393 test_CreateFontIndirectEx();
4396 test_east_asian_font_selection();
4398 /* These tests should be last test until RemoveFontResource
4399 * is properly implemented.
4401 test_vertical_font();
4402 test_CreateScalableFontResource();