gdi32/tests: Better trace in test_fullname2_helper.
[wine.git] / dlls / gdi32 / tests / font.c
blobbbfa02b8e435505ef89a3496902625f546fde655
1 /*
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
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
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;
83 return 0;
86 static BOOL is_truetype_font_installed(const char *name)
88 HDC hdc = GetDC(0);
89 BOOL ret = FALSE;
91 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
92 ret = TRUE;
94 ReleaseDC(0, hdc);
95 return ret;
98 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
100 return 0;
103 static BOOL is_font_installed(const char *name)
105 HDC hdc = GetDC(0);
106 BOOL ret = FALSE;
108 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
109 ret = TRUE;
111 ReleaseDC(0, hdc);
112 return ret;
115 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
117 LOGFONTA getobj_lf;
118 int ret, minlen = 0;
120 if (!hfont)
121 return;
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)
126 minlen++;
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);
161 if (hfont)
162 check_font(test, lf, hfont);
163 return hfont;
166 static void test_logfont(void)
168 LOGFONTA lf;
169 HFONT hfont;
171 memset(&lf, 0, sizeof lf);
173 lf.lfCharSet = ANSI_CHARSET;
174 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
175 lf.lfWeight = FW_DONTCARE;
176 lf.lfHeight = 16;
177 lf.lfWidth = 16;
178 lf.lfQuality = DEFAULT_QUALITY;
180 lstrcpyA(lf.lfFaceName, "Arial");
181 hfont = create_font("Arial", &lf);
182 DeleteObject(hfont);
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);
190 DeleteObject(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;
198 *lf = *elf;
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)
235 LOGFONTA lf;
236 OUTLINETEXTMETRIC otm;
237 TEXTMETRICA tm;
238 SIZE size;
239 INT width_of_A, cx, cy;
240 UINT ret;
242 if (!hfont)
243 return;
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);
285 else
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);
302 if (lf.lfHeight)
304 if (lf.lfWidth)
305 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
307 else
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";
324 HDC hdc;
325 LOGFONTA bitmap_lf;
326 HFONT hfont, old_hfont;
327 TEXTMETRICA tm_orig;
328 SIZE size_orig;
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);
335 if (ret)
337 ReleaseDC(0, hdc);
338 trace("no bitmap fonts were found, skipping the test\n");
339 return;
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);
353 DeleteObject(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);
361 DeleteObject(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++)
369 INT nearest_height;
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);
384 DeleteObject(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);
394 DeleteObject(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);
403 DeleteObject(hfont);
405 DeleteDC(hdc);
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
411 static const char test_str[11] = "Test String";
412 HDC hdc, hdc_2;
413 LOGFONTA lf;
414 HFONT hfont, old_hfont, old_hfont_2;
415 OUTLINETEXTMETRICA otm;
416 SIZE size_orig;
417 INT width_orig, height_orig, lfWidth;
418 XFORM xform;
419 GLYPHMETRICS gm;
420 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
421 POINT pt;
422 INT ret;
424 if (!is_truetype_font_installed("Arial"))
426 skip("Arial is not installed\n");
427 return;
430 hdc = CreateCompatibleDC(0);
432 memset(&lf, 0, sizeof(lf));
433 strcpy(lf.lfFaceName, "Arial");
434 lf.lfHeight = 72;
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);
444 DeleteObject(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);
456 DeleteObject(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);
468 DeleteObject(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);
477 DeleteObject(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);
486 DeleteObject(hfont);
488 /* test integer scaling 1x1 */
489 lf.lfHeight = height_orig;
490 lf.lfWidth = 0;
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
514 * another DC.
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);
551 DeleteDC(hdc_2);
553 if (!SetGraphicsMode(hdc, GM_ADVANCED))
555 SelectObject(hdc, old_hfont);
556 DeleteObject(hfont);
557 DeleteDC(hdc);
558 skip("GM_ADVANCED is not supported on this platform\n");
559 return;
562 xform.eM11 = 20.0f;
563 xform.eM12 = 0.0f;
564 xform.eM21 = 0.0f;
565 xform.eM22 = 20.0f;
566 xform.eDx = 0.0f;
567 xform.eDy = 0.0f;
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;
582 LPtoDP(hdc, &pt, 1);
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;
593 LPtoDP(hdc, &pt, 1);
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;
611 LPtoDP(hdc, &pt, 1);
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;
621 LPtoDP(hdc, &pt, 1);
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;
638 LPtoDP(hdc, &pt, 1);
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;
649 LPtoDP(hdc, &pt, 1);
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);
655 DeleteObject(hfont);
656 DeleteDC(hdc);
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))
665 *lf = *elf;
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;
680 DWORD ansi_bitfield;
681 WORD skip_lang_id;
682 int scaled_height;
683 } fd[] =
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 };
826 HDC hdc;
827 LOGFONT lf;
828 HFONT hfont, old_hfont;
829 TEXTMETRIC tm;
830 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
831 WORD system_lang_id;
832 char face_name[LF_FACESIZE];
833 CHARSETINFO csi;
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);
842 return;
844 expected_cs = csi.ciCharset;
845 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
847 hdc = CreateCompatibleDC(0);
848 assert(hdc);
850 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
851 GetDeviceCaps(hdc, LOGPIXELSY));
853 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
854 diff = 32768;
855 font_res = 0;
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);
859 if (new_diff < diff)
861 diff = new_diff;
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++)
869 int bit, height;
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++)
879 GLYPHMETRICS gm;
880 DWORD fs[2];
881 BOOL bRet;
883 fs[0] = 1L << bit;
884 fs[1] = 0;
885 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
886 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
888 lf.lfCharSet = csi.ciCharset;
889 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
890 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
891 if (fd[i].height & FH_SCALE)
892 ok(ret, "scaled font height %d should not be enumerated\n", height);
893 else
895 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
897 if (ret) /* FIXME: Remove once Wine is fixed */
898 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 else
900 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
903 if (ret && !(fd[i].height & FH_SCALE))
904 continue;
906 hfont = create_font(lf.lfFaceName, &lf);
907 old_hfont = SelectObject(hdc, hfont);
909 SetLastError(0xdeadbeef);
910 ret = GetTextFace(hdc, sizeof(face_name), face_name);
911 ok(ret, "GetTextFace error %u\n", GetLastError());
913 if (lstrcmp(face_name, fd[i].face_name) != 0)
915 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
916 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
917 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
918 SelectObject(hdc, old_hfont);
919 DeleteObject(hfont);
920 continue;
923 memset(&gm, 0, sizeof(gm));
924 SetLastError(0xdeadbeef);
925 ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
926 todo_wine {
927 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
928 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
931 bRet = GetTextMetrics(hdc, &tm);
932 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
934 SetLastError(0xdeadbeef);
935 ret = GetTextCharset(hdc);
936 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
938 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
939 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
941 if(fd[i].dpi == tm.tmDigitizedAspectX)
943 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
944 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
946 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
947 if (fd[i].height & FH_SCALE)
948 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);
949 else
950 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);
951 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
952 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
953 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);
954 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);
955 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);
956 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
957 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
958 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
959 make default char test fail */
960 if (tm.tmCharSet == lf.lfCharSet)
961 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
962 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
963 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);
965 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
966 that make the max width bigger */
967 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
968 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);
970 else
971 skip("Skipping font metrics test for system langid 0x%x\n",
972 system_lang_id);
974 SelectObject(hdc, old_hfont);
975 DeleteObject(hfont);
979 DeleteDC(hdc);
982 static void test_GdiGetCharDimensions(void)
984 HDC hdc;
985 TEXTMETRICW tm;
986 LONG ret;
987 SIZE size;
988 LONG avgwidth, height;
989 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
991 if (!pGdiGetCharDimensions)
993 win_skip("GdiGetCharDimensions not available on this platform\n");
994 return;
997 hdc = CreateCompatibleDC(NULL);
999 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1000 avgwidth = ((size.cx / 26) + 1) / 2;
1002 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1003 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1004 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1006 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1007 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1009 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1010 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1012 height = 0;
1013 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1014 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1015 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1017 DeleteDC(hdc);
1020 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1021 const TEXTMETRIC *lpntme,
1022 DWORD FontType, LPARAM lParam)
1024 if (FontType & TRUETYPE_FONTTYPE)
1026 HFONT hfont;
1028 hfont = CreateFontIndirect(lpelfe);
1029 if (hfont)
1031 *(HFONT *)lParam = hfont;
1032 return 0;
1036 return 1;
1039 static void test_GetCharABCWidths(void)
1041 static const WCHAR str[] = {'a',0};
1042 BOOL ret;
1043 HDC hdc;
1044 LOGFONTA lf;
1045 HFONT hfont;
1046 ABC abc[1];
1047 ABCFLOAT abcf[1];
1048 WORD glyphs[1];
1049 DWORD nb;
1050 static const struct
1052 UINT first;
1053 UINT last;
1054 } range[] =
1056 {0xff, 0xff},
1057 {0x100, 0x100},
1058 {0xff, 0x100},
1059 {0x1ff, 0xff00},
1060 {0xffff, 0xffff},
1061 {0x10000, 0x10000},
1062 {0xffff, 0x10000},
1063 {0xffffff, 0xffffff},
1064 {0x1000000, 0x1000000},
1065 {0xffffff, 0x1000000},
1066 {0xffffffff, 0xffffffff},
1067 {0x00, 0xff}
1069 static const struct
1071 UINT cs;
1072 UINT a;
1073 UINT w;
1074 BOOL r[sizeof range / sizeof range[0]];
1075 } c[] =
1077 {ANSI_CHARSET, 0x30, 0x30,
1078 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1079 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1080 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1081 {HANGEUL_CHARSET, 0x8141, 0xac02,
1082 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1083 {JOHAB_CHARSET, 0x8446, 0x3135,
1084 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1085 {GB2312_CHARSET, 0x8141, 0x4e04,
1086 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1087 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1088 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1090 UINT i;
1092 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1094 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1095 return;
1098 memset(&lf, 0, sizeof(lf));
1099 strcpy(lf.lfFaceName, "System");
1100 lf.lfHeight = 20;
1102 hfont = CreateFontIndirectA(&lf);
1103 hdc = GetDC(0);
1104 hfont = SelectObject(hdc, hfont);
1106 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1107 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1109 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1110 ok(!ret, "GetCharABCWidthsI should have failed\n");
1112 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1113 ok(!ret, "GetCharABCWidthsI should have failed\n");
1115 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1116 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1118 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1119 ok(!ret, "GetCharABCWidthsW should have failed\n");
1121 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1122 ok(!ret, "GetCharABCWidthsW should have failed\n");
1124 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1125 ok(!ret, "GetCharABCWidthsW should have failed\n");
1127 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1128 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1130 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1131 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1133 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1134 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1136 hfont = SelectObject(hdc, hfont);
1137 DeleteObject(hfont);
1139 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1141 ABC a[2], w[2];
1142 ABC full[256];
1143 UINT code = 0x41, j;
1145 lf.lfFaceName[0] = '\0';
1146 lf.lfCharSet = c[i].cs;
1147 lf.lfPitchAndFamily = 0;
1148 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1150 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1151 continue;
1154 memset(a, 0, sizeof a);
1155 memset(w, 0, sizeof w);
1156 hfont = SelectObject(hdc, hfont);
1157 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1158 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1159 memcmp(a, w, sizeof a) == 0,
1160 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1162 memset(a, 0xbb, sizeof a);
1163 ret = pGetCharABCWidthsA(hdc, code, code, a);
1164 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1165 memset(full, 0xcc, sizeof full);
1166 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1167 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1168 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1169 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1171 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1173 memset(full, 0xdd, sizeof full);
1174 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1175 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1176 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1177 if (ret)
1179 UINT last = range[j].last - range[j].first;
1180 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1181 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1182 "GetCharABCWidthsA %x should match. codepage = %u\n",
1183 range[j].last, c[i].cs);
1187 hfont = SelectObject(hdc, hfont);
1188 DeleteObject(hfont);
1191 ReleaseDC(NULL, hdc);
1194 static void test_text_extents(void)
1196 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1197 LPINT extents;
1198 INT i, len, fit1, fit2;
1199 LOGFONTA lf;
1200 TEXTMETRICA tm;
1201 HDC hdc;
1202 HFONT hfont;
1203 SIZE sz;
1204 SIZE sz1, sz2;
1205 BOOL ret;
1207 memset(&lf, 0, sizeof(lf));
1208 strcpy(lf.lfFaceName, "Arial");
1209 lf.lfHeight = 20;
1211 hfont = CreateFontIndirectA(&lf);
1212 hdc = GetDC(0);
1213 hfont = SelectObject(hdc, hfont);
1214 GetTextMetricsA(hdc, &tm);
1215 GetTextExtentPointA(hdc, "o", 1, &sz);
1216 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1218 SetLastError(0xdeadbeef);
1219 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1220 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1222 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1223 hfont = SelectObject(hdc, hfont);
1224 DeleteObject(hfont);
1225 ReleaseDC(0, hdc);
1226 return;
1229 len = lstrlenW(wt);
1230 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1231 extents[0] = 1; /* So that the increasing sequence test will fail
1232 if the extents array is untouched. */
1233 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1234 GetTextExtentPointW(hdc, wt, len, &sz2);
1235 ok(sz1.cy == sz2.cy,
1236 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1237 /* Because of the '\n' in the string GetTextExtentExPoint and
1238 GetTextExtentPoint return different widths under Win2k, but
1239 under WinXP they return the same width. So we don't test that
1240 here. */
1242 for (i = 1; i < len; ++i)
1243 ok(extents[i-1] <= extents[i],
1244 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1246 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1247 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1248 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1249 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1250 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1251 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1252 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1253 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1254 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1255 ok(extents[0] == extents[2] && extents[1] == extents[3],
1256 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1257 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1258 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1259 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1260 HeapFree(GetProcessHeap(), 0, extents);
1262 /* extents functions fail with -ve counts (the interesting case being -1) */
1263 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1264 ok(ret == FALSE, "got %d\n", ret);
1265 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1266 ok(ret == FALSE, "got %d\n", ret);
1267 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1268 ok(ret == FALSE, "got %d\n", ret);
1270 /* max_extent = 0 succeeds and returns zero */
1271 fit1 = fit2 = -215;
1272 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1273 ok(ret == TRUE ||
1274 broken(ret == FALSE), /* NT4, 2k */
1275 "got %d\n", ret);
1276 ok(fit1 == 0 ||
1277 broken(fit1 == -215), /* NT4, 2k */
1278 "fit = %d\n", fit1);
1279 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1280 ok(ret == TRUE, "got %d\n", ret);
1281 ok(fit2 == 0, "fit = %d\n", fit2);
1283 /* max_extent = -1 is interpreted as a very large width that will
1284 * definitely fit our three characters */
1285 fit1 = fit2 = -215;
1286 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1287 ok(ret == TRUE, "got %d\n", ret);
1288 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1289 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1290 ok(ret == TRUE, "got %d\n", ret);
1291 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1293 /* max_extent = -2 is interpreted similarly, but the Ansi version
1294 * rejects it while the Unicode one accepts it */
1295 fit1 = fit2 = -215;
1296 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1297 todo_wine ok(ret == FALSE, "got %d\n", ret);
1298 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1299 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1300 ok(ret == TRUE, "got %d\n", ret);
1301 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1303 hfont = SelectObject(hdc, hfont);
1304 DeleteObject(hfont);
1305 ReleaseDC(NULL, hdc);
1308 static void test_GetGlyphIndices(void)
1310 HDC hdc;
1311 HFONT hfont;
1312 DWORD charcount;
1313 LOGFONTA lf;
1314 DWORD flags = 0;
1315 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1316 WORD glyphs[(sizeof(testtext)/2)-1];
1317 TEXTMETRIC textm;
1318 HFONT hOldFont;
1320 if (!pGetGlyphIndicesW) {
1321 win_skip("GetGlyphIndicesW not available on platform\n");
1322 return;
1325 hdc = GetDC(0);
1327 memset(&lf, 0, sizeof(lf));
1328 strcpy(lf.lfFaceName, "System");
1329 lf.lfHeight = 16;
1330 lf.lfCharSet = ANSI_CHARSET;
1332 hfont = CreateFontIndirectA(&lf);
1333 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1334 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1335 if (textm.tmCharSet == ANSI_CHARSET)
1337 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1338 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1339 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1340 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1341 flags = 0;
1342 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1343 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1344 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1345 textm.tmDefaultChar, glyphs[4]);
1347 else
1348 /* FIXME: Write tests for non-ANSI charsets. */
1349 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1351 if(!is_font_installed("Tahoma"))
1353 skip("Tahoma is not installed so skipping this test\n");
1354 return;
1356 memset(&lf, 0, sizeof(lf));
1357 strcpy(lf.lfFaceName, "Tahoma");
1358 lf.lfHeight = 20;
1360 hfont = CreateFontIndirectA(&lf);
1361 hOldFont = SelectObject(hdc, hfont);
1362 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1363 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1364 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1365 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1366 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1367 flags = 0;
1368 testtext[0] = textm.tmDefaultChar;
1369 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1370 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1371 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1372 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1373 DeleteObject(SelectObject(hdc, hOldFont));
1376 static void test_GetKerningPairs(void)
1378 static const struct kerning_data
1380 const char face_name[LF_FACESIZE];
1381 LONG height;
1382 /* some interesting fields from OUTLINETEXTMETRIC */
1383 LONG tmHeight, tmAscent, tmDescent;
1384 UINT otmEMSquare;
1385 INT otmAscent;
1386 INT otmDescent;
1387 UINT otmLineGap;
1388 UINT otmsCapEmHeight;
1389 UINT otmsXHeight;
1390 INT otmMacAscent;
1391 INT otmMacDescent;
1392 UINT otmMacLineGap;
1393 UINT otmusMinimumPPEM;
1394 /* small subset of kerning pairs to test */
1395 DWORD total_kern_pairs;
1396 const KERNINGPAIR kern_pair[26];
1397 } kd[] =
1399 {"Arial", 12, 12, 9, 3,
1400 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1403 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1404 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1405 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1406 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1407 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1408 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1409 {933,970,+1},{933,972,-1}
1412 {"Arial", -34, 39, 32, 7,
1413 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1416 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1417 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1418 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1419 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1420 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1421 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1422 {933,970,+2},{933,972,-3}
1425 { "Arial", 120, 120, 97, 23,
1426 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1429 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1430 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1431 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1432 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1433 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1434 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1435 {933,970,+6},{933,972,-10}
1438 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1439 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1440 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1443 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1444 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1445 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1446 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1447 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1448 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1449 {933,970,+54},{933,972,-83}
1452 #endif
1454 LOGFONT lf;
1455 HFONT hfont, hfont_old;
1456 KERNINGPAIR *kern_pair;
1457 HDC hdc;
1458 DWORD total_kern_pairs, ret, i, n, matches;
1460 hdc = GetDC(0);
1462 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1463 * which may render this test unusable, so we're trying to avoid that.
1465 SetLastError(0xdeadbeef);
1466 GetKerningPairsW(hdc, 0, NULL);
1467 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1469 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1470 ReleaseDC(0, hdc);
1471 return;
1474 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1476 OUTLINETEXTMETRICW otm;
1477 UINT uiRet;
1479 if (!is_font_installed(kd[i].face_name))
1481 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1482 continue;
1485 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1487 memset(&lf, 0, sizeof(lf));
1488 strcpy(lf.lfFaceName, kd[i].face_name);
1489 lf.lfHeight = kd[i].height;
1490 hfont = CreateFontIndirect(&lf);
1491 assert(hfont != 0);
1493 hfont_old = SelectObject(hdc, hfont);
1495 SetLastError(0xdeadbeef);
1496 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1497 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1498 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1500 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1501 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1502 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1503 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1504 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1505 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1507 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1508 kd[i].otmEMSquare, otm.otmEMSquare);
1509 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1510 kd[i].otmAscent, otm.otmAscent);
1511 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1512 kd[i].otmDescent, otm.otmDescent);
1513 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1514 kd[i].otmLineGap, otm.otmLineGap);
1515 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1516 kd[i].otmMacDescent, otm.otmMacDescent);
1517 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1518 kd[i].otmMacAscent, otm.otmMacAscent);
1519 todo_wine {
1520 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1521 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1522 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1523 kd[i].otmsXHeight, otm.otmsXHeight);
1524 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1525 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1526 kd[i].otmMacLineGap, otm.otmMacLineGap);
1527 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1528 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1531 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1532 trace("total_kern_pairs %u\n", total_kern_pairs);
1533 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1535 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1536 * passes on XP.
1538 SetLastError(0xdeadbeef);
1539 ret = GetKerningPairsW(hdc, 0, kern_pair);
1540 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1541 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1542 ok(ret == 0, "got %u, expected 0\n", ret);
1544 ret = GetKerningPairsW(hdc, 100, NULL);
1545 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1547 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1548 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1550 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1551 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1553 matches = 0;
1555 for (n = 0; n < ret; n++)
1557 DWORD j;
1558 /* Disabled to limit console spam */
1559 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1560 trace("{'%c','%c',%d},\n",
1561 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1562 for (j = 0; j < kd[i].total_kern_pairs; j++)
1564 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1565 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1567 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1568 "pair %d:%d got %d, expected %d\n",
1569 kern_pair[n].wFirst, kern_pair[n].wSecond,
1570 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1571 matches++;
1576 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1577 matches, kd[i].total_kern_pairs);
1579 HeapFree(GetProcessHeap(), 0, kern_pair);
1581 SelectObject(hdc, hfont_old);
1582 DeleteObject(hfont);
1585 ReleaseDC(0, hdc);
1588 static void test_height_selection(void)
1590 static const struct font_data
1592 const char face_name[LF_FACESIZE];
1593 int requested_height;
1594 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1595 } fd[] =
1597 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1598 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1599 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1600 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1601 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1602 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1603 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1604 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1605 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1606 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1608 HDC hdc;
1609 LOGFONT lf;
1610 HFONT hfont, old_hfont;
1611 TEXTMETRIC tm;
1612 INT ret, i;
1614 hdc = CreateCompatibleDC(0);
1615 assert(hdc);
1617 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1619 if (!is_truetype_font_installed(fd[i].face_name))
1621 skip("%s is not installed\n", fd[i].face_name);
1622 continue;
1625 memset(&lf, 0, sizeof(lf));
1626 lf.lfHeight = fd[i].requested_height;
1627 lf.lfWeight = fd[i].weight;
1628 strcpy(lf.lfFaceName, fd[i].face_name);
1630 hfont = CreateFontIndirect(&lf);
1631 assert(hfont);
1633 old_hfont = SelectObject(hdc, hfont);
1634 ret = GetTextMetrics(hdc, &tm);
1635 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1636 if(fd[i].dpi == tm.tmDigitizedAspectX)
1638 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1639 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);
1640 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);
1641 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);
1642 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);
1643 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1644 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);
1645 #endif
1646 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);
1649 SelectObject(hdc, old_hfont);
1650 DeleteObject(hfont);
1653 DeleteDC(hdc);
1656 static void test_GetOutlineTextMetrics(void)
1658 OUTLINETEXTMETRIC *otm;
1659 LOGFONT lf;
1660 HFONT hfont, hfont_old;
1661 HDC hdc;
1662 DWORD ret, otm_size;
1663 LPSTR unset_ptr;
1665 if (!is_font_installed("Arial"))
1667 skip("Arial is not installed\n");
1668 return;
1671 hdc = GetDC(0);
1673 memset(&lf, 0, sizeof(lf));
1674 strcpy(lf.lfFaceName, "Arial");
1675 lf.lfHeight = -13;
1676 lf.lfWeight = FW_NORMAL;
1677 lf.lfPitchAndFamily = DEFAULT_PITCH;
1678 lf.lfQuality = PROOF_QUALITY;
1679 hfont = CreateFontIndirect(&lf);
1680 assert(hfont != 0);
1682 hfont_old = SelectObject(hdc, hfont);
1683 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1684 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1686 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1688 memset(otm, 0xAA, otm_size);
1689 SetLastError(0xdeadbeef);
1690 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1691 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1692 ok(ret == 1 /* Win9x */ ||
1693 ret == otm->otmSize /* XP*/,
1694 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1695 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1697 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1698 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1699 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1700 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1703 memset(otm, 0xAA, otm_size);
1704 SetLastError(0xdeadbeef);
1705 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1706 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1707 ok(ret == 1 /* Win9x */ ||
1708 ret == otm->otmSize /* XP*/,
1709 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1710 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1712 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1713 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1714 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1715 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1718 /* ask about truncated data */
1719 memset(otm, 0xAA, otm_size);
1720 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1721 SetLastError(0xdeadbeef);
1722 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1723 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1724 ok(ret == 1 /* Win9x */ ||
1725 ret == otm->otmSize /* XP*/,
1726 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1727 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1729 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1730 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1731 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1733 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1735 HeapFree(GetProcessHeap(), 0, otm);
1737 SelectObject(hdc, hfont_old);
1738 DeleteObject(hfont);
1740 ReleaseDC(0, hdc);
1743 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1745 INT y,
1746 breakCount,
1747 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1748 areaWidth = clientArea->right - clientArea->left,
1749 nErrors = 0, e;
1750 BOOL lastExtent = FALSE;
1751 PSTR pFirstChar, pLastChar;
1752 SIZE size;
1753 TEXTMETRICA tm;
1754 struct err
1756 char extent[100];
1757 int GetTextExtentExPointWWidth;
1758 } error[10];
1760 GetTextMetricsA(hdc, &tm);
1761 y = clientArea->top;
1762 do {
1763 breakCount = 0;
1764 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1765 pFirstChar = str;
1767 do {
1768 pLastChar = str;
1770 /* if not at the end of the string, ... */
1771 if (*str == '\0') break;
1772 /* ... add the next word to the current extent */
1773 while (*str != '\0' && *str++ != tm.tmBreakChar);
1774 breakCount++;
1775 SetTextJustification(hdc, 0, 0);
1776 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1777 } while ((int) size.cx < areaWidth);
1779 /* ignore trailing break chars */
1780 breakCount--;
1781 while (*(pLastChar - 1) == tm.tmBreakChar)
1783 pLastChar--;
1784 breakCount--;
1787 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1789 SetTextJustification(hdc, 0, 0);
1790 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1792 /* do not justify the last extent */
1793 if (*str != '\0' && breakCount > 0)
1795 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1796 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1797 justifiedWidth = size.cx;
1799 else lastExtent = TRUE;
1801 /* catch errors and report them */
1802 if (!lastExtent && (justifiedWidth != areaWidth))
1804 memset(error[nErrors].extent, 0, 100);
1805 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1806 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1807 nErrors++;
1810 y += size.cy;
1811 str = pLastChar;
1812 } while (*str && y < clientArea->bottom);
1814 for (e = 0; e < nErrors; e++)
1816 /* The width returned by GetTextExtentPoint32() is exactly the same
1817 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1818 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1819 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1820 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1824 static void test_SetTextJustification(void)
1826 HDC hdc;
1827 RECT clientArea;
1828 LOGFONTA lf;
1829 HFONT hfont;
1830 HWND hwnd;
1831 static char testText[] =
1832 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1833 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1834 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1835 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1836 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1837 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1838 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1840 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1841 GetClientRect( hwnd, &clientArea );
1842 hdc = GetDC( hwnd );
1844 memset(&lf, 0, sizeof lf);
1845 lf.lfCharSet = ANSI_CHARSET;
1846 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1847 lf.lfWeight = FW_DONTCARE;
1848 lf.lfHeight = 20;
1849 lf.lfQuality = DEFAULT_QUALITY;
1850 lstrcpyA(lf.lfFaceName, "Times New Roman");
1851 hfont = create_font("Times New Roman", &lf);
1852 SelectObject(hdc, hfont);
1854 testJustification(hdc, testText, &clientArea);
1856 DeleteObject(hfont);
1857 ReleaseDC(hwnd, hdc);
1858 DestroyWindow(hwnd);
1861 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1863 HDC hdc;
1864 LOGFONTA lf;
1865 HFONT hfont, hfont_old;
1866 CHARSETINFO csi;
1867 FONTSIGNATURE fs;
1868 INT cs;
1869 DWORD i, ret;
1870 char name[64];
1872 assert(count <= 128);
1874 memset(&lf, 0, sizeof(lf));
1876 lf.lfCharSet = charset;
1877 lf.lfHeight = 10;
1878 lstrcpyA(lf.lfFaceName, "Arial");
1879 SetLastError(0xdeadbeef);
1880 hfont = CreateFontIndirectA(&lf);
1881 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1883 hdc = GetDC(0);
1884 hfont_old = SelectObject(hdc, hfont);
1886 cs = GetTextCharsetInfo(hdc, &fs, 0);
1887 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1889 SetLastError(0xdeadbeef);
1890 ret = GetTextFaceA(hdc, sizeof(name), name);
1891 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1893 if (charset == SYMBOL_CHARSET)
1895 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1896 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1898 else
1900 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1901 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1904 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1906 trace("Can't find codepage for charset %d\n", cs);
1907 ReleaseDC(0, hdc);
1908 return FALSE;
1910 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1912 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1914 skip("Font code page %d, looking for code page %d\n",
1915 pGdiGetCodePage(hdc), code_page);
1916 ReleaseDC(0, hdc);
1917 return FALSE;
1920 if (unicode)
1922 char ansi_buf[128];
1923 WCHAR unicode_buf[128];
1925 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1927 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1929 SetLastError(0xdeadbeef);
1930 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1931 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1932 count, ret, GetLastError());
1934 else
1936 char ansi_buf[128];
1938 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1940 SetLastError(0xdeadbeef);
1941 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1942 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1943 count, ret, GetLastError());
1946 SelectObject(hdc, hfont_old);
1947 DeleteObject(hfont);
1949 ReleaseDC(0, hdc);
1951 return TRUE;
1954 static void test_font_charset(void)
1956 static struct charset_data
1958 INT charset;
1959 UINT code_page;
1960 WORD font_idxA[128], font_idxW[128];
1961 } cd[] =
1963 { ANSI_CHARSET, 1252 },
1964 { RUSSIAN_CHARSET, 1251 },
1965 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1967 int i;
1969 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1971 win_skip("Skipping the font charset test on a Win9x platform\n");
1972 return;
1975 if (!is_font_installed("Arial"))
1977 skip("Arial is not installed\n");
1978 return;
1981 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1983 if (cd[i].charset == SYMBOL_CHARSET)
1985 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1987 skip("Symbol or Wingdings is not installed\n");
1988 break;
1991 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1992 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1993 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1996 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1997 if (i > 2)
1999 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2000 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2002 else
2003 skip("Symbol or Wingdings is not installed\n");
2006 static void test_GetFontUnicodeRanges(void)
2008 LOGFONTA lf;
2009 HDC hdc;
2010 HFONT hfont, hfont_old;
2011 DWORD size;
2012 GLYPHSET *gs;
2013 DWORD i;
2015 if (!pGetFontUnicodeRanges)
2017 win_skip("GetFontUnicodeRanges not available before W2K\n");
2018 return;
2021 memset(&lf, 0, sizeof(lf));
2022 lstrcpyA(lf.lfFaceName, "Arial");
2023 hfont = create_font("Arial", &lf);
2025 hdc = GetDC(0);
2026 hfont_old = SelectObject(hdc, hfont);
2028 size = pGetFontUnicodeRanges(NULL, NULL);
2029 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2031 size = pGetFontUnicodeRanges(hdc, NULL);
2032 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2034 gs = HeapAlloc(GetProcessHeap(), 0, size);
2036 size = pGetFontUnicodeRanges(hdc, gs);
2037 ok(size, "GetFontUnicodeRanges failed\n");
2039 if (0) /* Disabled to limit console spam */
2040 for (i = 0; i < gs->cRanges; i++)
2041 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2042 trace("found %u ranges\n", gs->cRanges);
2044 HeapFree(GetProcessHeap(), 0, gs);
2046 SelectObject(hdc, hfont_old);
2047 DeleteObject(hfont);
2048 ReleaseDC(NULL, hdc);
2051 #define MAX_ENUM_FONTS 4096
2053 struct enum_font_data
2055 int total;
2056 LOGFONT lf[MAX_ENUM_FONTS];
2059 struct enum_fullname_data
2061 int total;
2062 ENUMLOGFONT elf[MAX_ENUM_FONTS];
2065 struct enum_font_dataW
2067 int total;
2068 LOGFONTW lf[MAX_ENUM_FONTS];
2071 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2073 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2074 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2076 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2077 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2079 if (type != TRUETYPE_FONTTYPE) return 1;
2081 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2083 if (0) /* Disabled to limit console spam */
2084 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2085 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2086 if (efd->total < MAX_ENUM_FONTS)
2087 efd->lf[efd->total++] = *lf;
2088 else
2089 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2091 return 1;
2094 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2096 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2097 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2099 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2100 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2102 if (type != TRUETYPE_FONTTYPE) return 1;
2104 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2106 if (0) /* Disabled to limit console spam */
2107 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2108 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2109 if (efd->total < MAX_ENUM_FONTS)
2110 efd->lf[efd->total++] = *lf;
2111 else
2112 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2114 return 1;
2117 static void get_charset_stats(struct enum_font_data *efd,
2118 int *ansi_charset, int *symbol_charset,
2119 int *russian_charset)
2121 int i;
2123 *ansi_charset = 0;
2124 *symbol_charset = 0;
2125 *russian_charset = 0;
2127 for (i = 0; i < efd->total; i++)
2129 switch (efd->lf[i].lfCharSet)
2131 case ANSI_CHARSET:
2132 (*ansi_charset)++;
2133 break;
2134 case SYMBOL_CHARSET:
2135 (*symbol_charset)++;
2136 break;
2137 case RUSSIAN_CHARSET:
2138 (*russian_charset)++;
2139 break;
2144 static void get_charset_statsW(struct enum_font_dataW *efd,
2145 int *ansi_charset, int *symbol_charset,
2146 int *russian_charset)
2148 int i;
2150 *ansi_charset = 0;
2151 *symbol_charset = 0;
2152 *russian_charset = 0;
2154 for (i = 0; i < efd->total; i++)
2156 switch (efd->lf[i].lfCharSet)
2158 case ANSI_CHARSET:
2159 (*ansi_charset)++;
2160 break;
2161 case SYMBOL_CHARSET:
2162 (*symbol_charset)++;
2163 break;
2164 case RUSSIAN_CHARSET:
2165 (*russian_charset)++;
2166 break;
2171 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2173 struct enum_font_data efd;
2174 struct enum_font_dataW efdw;
2175 LOGFONT lf;
2176 HDC hdc;
2177 int i, ret, ansi_charset, symbol_charset, russian_charset;
2179 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2181 if (*font_name && !is_truetype_font_installed(font_name))
2183 skip("%s is not installed\n", font_name);
2184 return;
2187 hdc = GetDC(0);
2189 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2190 * while EnumFontFamiliesEx doesn't.
2192 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2195 * Use EnumFontFamiliesW since win98 crashes when the
2196 * second parameter is NULL using EnumFontFamilies
2198 efdw.total = 0;
2199 SetLastError(0xdeadbeef);
2200 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2201 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2202 if(ret)
2204 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2205 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2206 ansi_charset, symbol_charset, russian_charset);
2207 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2208 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2209 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2210 ok(russian_charset > 0 ||
2211 broken(russian_charset == 0), /* NT4 */
2212 "NULL family should enumerate RUSSIAN_CHARSET\n");
2215 efdw.total = 0;
2216 SetLastError(0xdeadbeef);
2217 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2218 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2219 if(ret)
2221 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2222 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2223 ansi_charset, symbol_charset, russian_charset);
2224 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2225 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2226 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2227 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2231 efd.total = 0;
2232 SetLastError(0xdeadbeef);
2233 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2234 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2235 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2236 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2237 ansi_charset, symbol_charset, russian_charset,
2238 *font_name ? font_name : "<empty>");
2239 if (*font_name)
2240 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2241 else
2242 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2243 for (i = 0; i < efd.total; i++)
2245 /* FIXME: remove completely once Wine is fixed */
2246 if (efd.lf[i].lfCharSet != font_charset)
2248 todo_wine
2249 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2251 else
2252 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2253 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2254 font_name, efd.lf[i].lfFaceName);
2257 memset(&lf, 0, sizeof(lf));
2258 lf.lfCharSet = ANSI_CHARSET;
2259 lstrcpy(lf.lfFaceName, font_name);
2260 efd.total = 0;
2261 SetLastError(0xdeadbeef);
2262 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2263 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2264 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2265 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2266 ansi_charset, symbol_charset, russian_charset,
2267 *font_name ? font_name : "<empty>");
2268 if (font_charset == SYMBOL_CHARSET)
2270 if (*font_name)
2271 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2272 else
2273 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2275 else
2277 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2278 for (i = 0; i < efd.total; i++)
2280 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2281 if (*font_name)
2282 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2283 font_name, efd.lf[i].lfFaceName);
2287 /* DEFAULT_CHARSET should enumerate all available charsets */
2288 memset(&lf, 0, sizeof(lf));
2289 lf.lfCharSet = DEFAULT_CHARSET;
2290 lstrcpy(lf.lfFaceName, font_name);
2291 efd.total = 0;
2292 SetLastError(0xdeadbeef);
2293 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2294 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2295 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2296 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2297 ansi_charset, symbol_charset, russian_charset,
2298 *font_name ? font_name : "<empty>");
2299 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2300 for (i = 0; i < efd.total; i++)
2302 if (*font_name)
2303 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2304 font_name, efd.lf[i].lfFaceName);
2306 if (*font_name)
2308 switch (font_charset)
2310 case ANSI_CHARSET:
2311 ok(ansi_charset > 0,
2312 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2313 ok(!symbol_charset,
2314 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2315 ok(russian_charset > 0,
2316 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2317 break;
2318 case SYMBOL_CHARSET:
2319 ok(!ansi_charset,
2320 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2321 ok(symbol_charset,
2322 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2323 ok(!russian_charset,
2324 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2325 break;
2326 case DEFAULT_CHARSET:
2327 ok(ansi_charset > 0,
2328 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2329 ok(symbol_charset > 0,
2330 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2331 ok(russian_charset > 0,
2332 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2333 break;
2336 else
2338 ok(ansi_charset > 0,
2339 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2340 ok(symbol_charset > 0,
2341 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2342 ok(russian_charset > 0,
2343 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2346 memset(&lf, 0, sizeof(lf));
2347 lf.lfCharSet = SYMBOL_CHARSET;
2348 lstrcpy(lf.lfFaceName, font_name);
2349 efd.total = 0;
2350 SetLastError(0xdeadbeef);
2351 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2352 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2353 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2354 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2355 ansi_charset, symbol_charset, russian_charset,
2356 *font_name ? font_name : "<empty>");
2357 if (*font_name && font_charset == ANSI_CHARSET)
2358 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2359 else
2361 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2362 for (i = 0; i < efd.total; i++)
2364 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2365 if (*font_name)
2366 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2367 font_name, efd.lf[i].lfFaceName);
2370 ok(!ansi_charset,
2371 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2372 ok(symbol_charset > 0,
2373 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2374 ok(!russian_charset,
2375 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2378 ReleaseDC(0, hdc);
2381 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2383 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2385 if (type != TRUETYPE_FONTTYPE) return 1;
2387 if (efd->total < MAX_ENUM_FONTS)
2388 efd->lf[efd->total++] = *lf;
2389 else
2390 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2392 return 1;
2395 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2397 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2399 if (type != TRUETYPE_FONTTYPE) return 1;
2401 if (efnd->total < MAX_ENUM_FONTS)
2402 efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2403 else
2404 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2406 return 1;
2409 static void test_EnumFontFamiliesEx_default_charset(void)
2411 struct enum_font_data efd;
2412 LOGFONT gui_font, enum_font;
2413 DWORD ret;
2414 HDC hdc;
2416 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2417 ok(ret, "GetObject failed.\n");
2418 if (!ret)
2419 return;
2421 efd.total = 0;
2423 hdc = GetDC(0);
2424 memset(&enum_font, 0, sizeof(enum_font));
2425 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2426 enum_font.lfCharSet = DEFAULT_CHARSET;
2427 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2428 ReleaseDC(0, hdc);
2430 if (efd.total == 0) {
2431 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2432 return;
2434 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2436 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2437 "(%s) got charset %d expected %d\n",
2438 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2440 return;
2443 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2445 HFONT hfont, hfont_prev;
2446 DWORD ret;
2447 GLYPHMETRICS gm1, gm2;
2448 LOGFONTA lf2 = *lf;
2449 WORD idx;
2451 if(!pGetGlyphIndicesA)
2452 return;
2454 /* negative widths are handled just as positive ones */
2455 lf2.lfWidth = -lf->lfWidth;
2457 SetLastError(0xdeadbeef);
2458 hfont = CreateFontIndirectA(lf);
2459 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2460 check_font("original", lf, hfont);
2462 hfont_prev = SelectObject(hdc, hfont);
2464 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2465 if (ret == GDI_ERROR || idx == 0xffff)
2467 SelectObject(hdc, hfont_prev);
2468 DeleteObject(hfont);
2469 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2470 return;
2473 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2474 memset(&gm1, 0xab, sizeof(gm1));
2475 SetLastError(0xdeadbeef);
2476 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2477 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2479 SelectObject(hdc, hfont_prev);
2480 DeleteObject(hfont);
2482 SetLastError(0xdeadbeef);
2483 hfont = CreateFontIndirectA(&lf2);
2484 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2485 check_font("negative width", &lf2, hfont);
2487 hfont_prev = SelectObject(hdc, hfont);
2489 memset(&gm2, 0xbb, sizeof(gm2));
2490 SetLastError(0xdeadbeef);
2491 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2492 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2494 SelectObject(hdc, hfont_prev);
2495 DeleteObject(hfont);
2497 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2498 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2499 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2500 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2501 gm1.gmCellIncX == gm2.gmCellIncX &&
2502 gm1.gmCellIncY == gm2.gmCellIncY,
2503 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2504 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2505 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2506 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2507 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2510 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2511 #include "pshpack2.h"
2512 typedef struct
2514 USHORT version;
2515 SHORT xAvgCharWidth;
2516 USHORT usWeightClass;
2517 USHORT usWidthClass;
2518 SHORT fsType;
2519 SHORT ySubscriptXSize;
2520 SHORT ySubscriptYSize;
2521 SHORT ySubscriptXOffset;
2522 SHORT ySubscriptYOffset;
2523 SHORT ySuperscriptXSize;
2524 SHORT ySuperscriptYSize;
2525 SHORT ySuperscriptXOffset;
2526 SHORT ySuperscriptYOffset;
2527 SHORT yStrikeoutSize;
2528 SHORT yStrikeoutPosition;
2529 SHORT sFamilyClass;
2530 PANOSE panose;
2531 ULONG ulUnicodeRange1;
2532 ULONG ulUnicodeRange2;
2533 ULONG ulUnicodeRange3;
2534 ULONG ulUnicodeRange4;
2535 CHAR achVendID[4];
2536 USHORT fsSelection;
2537 USHORT usFirstCharIndex;
2538 USHORT usLastCharIndex;
2539 /* According to the Apple spec, original version didn't have the below fields,
2540 * version numbers were taken from the OpenType spec.
2542 /* version 0 (TrueType 1.5) */
2543 USHORT sTypoAscender;
2544 USHORT sTypoDescender;
2545 USHORT sTypoLineGap;
2546 USHORT usWinAscent;
2547 USHORT usWinDescent;
2548 /* version 1 (TrueType 1.66) */
2549 ULONG ulCodePageRange1;
2550 ULONG ulCodePageRange2;
2551 /* version 2 (OpenType 1.2) */
2552 SHORT sxHeight;
2553 SHORT sCapHeight;
2554 USHORT usDefaultChar;
2555 USHORT usBreakChar;
2556 USHORT usMaxContext;
2557 } TT_OS2_V2;
2558 #include "poppack.h"
2560 #ifdef WORDS_BIGENDIAN
2561 #define GET_BE_WORD(x) (x)
2562 #define GET_BE_DWORD(x) (x)
2563 #else
2564 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2565 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2566 #endif
2568 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2569 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2570 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2571 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2572 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2573 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2575 typedef struct
2577 USHORT version;
2578 USHORT num_tables;
2579 } cmap_header;
2581 typedef struct
2583 USHORT plat_id;
2584 USHORT enc_id;
2585 ULONG offset;
2586 } cmap_encoding_record;
2588 typedef struct
2590 USHORT format;
2591 USHORT length;
2592 USHORT language;
2594 BYTE glyph_ids[256];
2595 } cmap_format_0;
2597 typedef struct
2599 USHORT format;
2600 USHORT length;
2601 USHORT language;
2603 USHORT seg_countx2;
2604 USHORT search_range;
2605 USHORT entry_selector;
2606 USHORT range_shift;
2608 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2609 /* Then follows:
2610 USHORT pad;
2611 USHORT start_count[seg_countx2 / 2];
2612 USHORT id_delta[seg_countx2 / 2];
2613 USHORT id_range_offset[seg_countx2 / 2];
2614 USHORT glyph_ids[];
2616 } cmap_format_4;
2618 typedef struct
2620 USHORT end_count;
2621 USHORT start_count;
2622 USHORT id_delta;
2623 USHORT id_range_offset;
2624 } cmap_format_4_seg;
2626 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2628 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2629 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2630 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2631 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2632 os2->panose.bWeight, os2->panose.bProportion);
2635 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2637 int i;
2638 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2640 *first = 256;
2642 for(i = 0; i < 256; i++)
2644 if(cmap->glyph_ids[i] == 0) continue;
2645 *last = i;
2646 if(*first == 256) *first = i;
2648 if(*first == 256) return FALSE;
2649 return TRUE;
2652 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2654 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2655 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2656 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2657 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2658 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2661 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2663 int i;
2664 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2665 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2666 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2668 *first = 0x10000;
2670 for(i = 0; i < seg_count; i++)
2672 DWORD code, index;
2673 cmap_format_4_seg seg;
2675 get_seg4(cmap, i, &seg);
2676 for(code = seg.start_count; code <= seg.end_count; code++)
2678 if(seg.id_range_offset == 0)
2679 index = (seg.id_delta + code) & 0xffff;
2680 else
2682 index = seg.id_range_offset / 2
2683 + code - seg.start_count
2684 + i - seg_count;
2686 /* some fonts have broken last segment */
2687 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2688 index = GET_BE_WORD(glyph_ids[index]);
2689 else
2691 trace("segment %04x/%04x index %04x points to nowhere\n",
2692 seg.start_count, seg.end_count, index);
2693 index = 0;
2695 if(index) index += seg.id_delta;
2697 if(*first == 0x10000)
2698 *last = *first = code;
2699 else if(index)
2700 *last = code;
2704 if(*first == 0x10000) return FALSE;
2705 return TRUE;
2708 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2710 USHORT i;
2711 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2713 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2715 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2716 return (BYTE *)header + GET_BE_DWORD(record->offset);
2717 record++;
2719 return NULL;
2722 typedef enum
2724 cmap_none,
2725 cmap_ms_unicode,
2726 cmap_ms_symbol
2727 } cmap_type;
2729 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2731 LONG size, ret;
2732 cmap_header *header;
2733 void *cmap;
2734 BOOL r = FALSE;
2735 WORD format;
2737 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2738 ok(size != GDI_ERROR, "no cmap table found\n");
2739 if(size == GDI_ERROR) return FALSE;
2741 header = HeapAlloc(GetProcessHeap(), 0, size);
2742 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2743 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2744 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2746 cmap = get_cmap(header, 3, 1);
2747 if(cmap)
2748 *cmap_type = cmap_ms_unicode;
2749 else
2751 cmap = get_cmap(header, 3, 0);
2752 if(cmap) *cmap_type = cmap_ms_symbol;
2754 if(!cmap)
2756 *cmap_type = cmap_none;
2757 goto end;
2760 format = GET_BE_WORD(*(WORD *)cmap);
2761 switch(format)
2763 case 0:
2764 r = get_first_last_from_cmap0(cmap, first, last);
2765 break;
2766 case 4:
2767 r = get_first_last_from_cmap4(cmap, first, last, size);
2768 break;
2769 default:
2770 trace("unhandled cmap format %d\n", format);
2771 break;
2774 end:
2775 HeapFree(GetProcessHeap(), 0, header);
2776 return r;
2779 #define TT_PLATFORM_MICROSOFT 3
2780 #define TT_MS_ID_UNICODE_CS 1
2781 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2782 #define TT_NAME_ID_FONT_FAMILY 1
2783 #define TT_NAME_ID_FONT_SUBFAMILY 2
2784 #define TT_NAME_ID_UNIQUE_ID 3
2785 #define TT_NAME_ID_FULL_NAME 4
2787 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2789 struct sfnt_name_header
2791 USHORT format;
2792 USHORT number_of_record;
2793 USHORT storage_offset;
2794 } *header;
2795 struct sfnt_name
2797 USHORT platform_id;
2798 USHORT encoding_id;
2799 USHORT language_id;
2800 USHORT name_id;
2801 USHORT length;
2802 USHORT offset;
2803 } *entry;
2804 BOOL r = FALSE;
2805 LONG size, offset, length;
2806 LONG c, ret;
2807 WCHAR *name;
2808 BYTE *data;
2809 USHORT i;
2811 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2812 ok(size != GDI_ERROR, "no name table found\n");
2813 if(size == GDI_ERROR) return FALSE;
2815 data = HeapAlloc(GetProcessHeap(), 0, size);
2816 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2817 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2819 header = (void *)data;
2820 header->format = GET_BE_WORD(header->format);
2821 header->number_of_record = GET_BE_WORD(header->number_of_record);
2822 header->storage_offset = GET_BE_WORD(header->storage_offset);
2823 if (header->format != 0)
2825 trace("got format %u\n", header->format);
2826 goto out;
2828 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2830 trace("number records out of range: %d\n", header->number_of_record);
2831 goto out;
2833 if (header->storage_offset >= size)
2835 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2836 goto out;
2839 entry = (void *)&header[1];
2840 for (i = 0; i < header->number_of_record; i++)
2842 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2843 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2844 GET_BE_WORD(entry[i].language_id) != language_id ||
2845 GET_BE_WORD(entry[i].name_id) != name_id)
2847 continue;
2850 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2851 length = GET_BE_WORD(entry[i].length);
2852 if (offset + length > size)
2854 trace("entry %d is out of range\n", i);
2855 break;
2857 if (length >= out_size)
2859 trace("buffer too small for entry %d\n", i);
2860 break;
2863 name = (WCHAR *)(data + offset);
2864 for (c = 0; c < length / 2; c++)
2865 out_buf[c] = GET_BE_WORD(name[c]);
2866 out_buf[c] = 0;
2868 r = TRUE;
2869 break;
2872 out:
2873 HeapFree(GetProcessHeap(), 0, data);
2874 return r;
2877 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2879 HDC hdc;
2880 HFONT hfont, hfont_old;
2881 TEXTMETRICA tmA;
2882 TT_OS2_V2 tt_os2;
2883 LONG size, ret;
2884 const char *font_name = lf->lfFaceName;
2885 DWORD cmap_first = 0, cmap_last = 0;
2886 UINT ascent, descent, cell_height;
2887 cmap_type cmap_type;
2888 BOOL sys_lang_non_english;
2890 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2891 hdc = GetDC(0);
2893 SetLastError(0xdeadbeef);
2894 hfont = CreateFontIndirectA(lf);
2895 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2897 hfont_old = SelectObject(hdc, hfont);
2899 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2900 if (size == GDI_ERROR)
2902 trace("OS/2 chunk was not found\n");
2903 goto end_of_test;
2905 if (size > sizeof(tt_os2))
2907 trace("got too large OS/2 chunk of size %u\n", size);
2908 size = sizeof(tt_os2);
2911 memset(&tt_os2, 0, sizeof(tt_os2));
2912 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2913 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2915 ascent = GET_BE_WORD(tt_os2.usWinAscent);
2916 descent = GET_BE_WORD(tt_os2.usWinDescent);
2917 cell_height = ascent + descent;
2918 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
2919 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
2921 SetLastError(0xdeadbeef);
2922 ret = GetTextMetricsA(hdc, &tmA);
2923 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2925 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2927 skip("Unable to retrieve first and last glyphs from cmap\n");
2929 else
2931 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2932 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2933 UINT os2_first_char, os2_last_char, default_char, break_char;
2934 USHORT version;
2935 TEXTMETRICW tmW;
2937 version = GET_BE_WORD(tt_os2.version);
2939 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2940 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2941 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2942 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2944 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2945 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2946 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2948 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2950 expect_first_W = 0;
2951 switch(GetACP())
2953 case 1257: /* Baltic */
2954 expect_last_W = 0xf8fd;
2955 break;
2956 default:
2957 expect_last_W = 0xf0ff;
2959 expect_break_W = 0x20;
2960 expect_default_W = expect_break_W - 1;
2961 expect_first_A = 0x1e;
2962 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2964 else
2966 expect_first_W = cmap_first;
2967 expect_last_W = min(cmap_last, os2_last_char);
2968 if(os2_first_char <= 1)
2969 expect_break_W = os2_first_char + 2;
2970 else if(os2_first_char > 0xff)
2971 expect_break_W = 0x20;
2972 else
2973 expect_break_W = os2_first_char;
2974 expect_default_W = expect_break_W - 1;
2975 expect_first_A = expect_default_W - 1;
2976 expect_last_A = min(expect_last_W, 0xff);
2978 expect_break_A = expect_break_W;
2979 expect_default_A = expect_default_W;
2981 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2982 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2983 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2984 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2985 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2986 else
2987 ok(tmA.tmFirstChar == expect_first_A ||
2988 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2989 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2990 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2991 ok(tmA.tmLastChar == expect_last_A ||
2992 tmA.tmLastChar == 0xff /* win9x */,
2993 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2994 else
2995 skip("tmLastChar is DBCS lead byte\n");
2996 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2997 font_name, tmA.tmBreakChar, expect_break_A);
2998 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2999 "A: tmDefaultChar for %s got %02x expected %02x\n",
3000 font_name, tmA.tmDefaultChar, expect_default_A);
3003 SetLastError(0xdeadbeef);
3004 ret = GetTextMetricsW(hdc, &tmW);
3005 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3006 "GetTextMetricsW error %u\n", GetLastError());
3007 if (ret)
3009 /* Wine uses the os2 first char */
3010 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3011 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3012 font_name, tmW.tmFirstChar, expect_first_W);
3013 else
3014 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3015 font_name, tmW.tmFirstChar, expect_first_W);
3017 /* Wine uses the os2 last char */
3018 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3019 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3020 font_name, tmW.tmLastChar, expect_last_W);
3021 else
3022 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3023 font_name, tmW.tmLastChar, expect_last_W);
3024 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3025 font_name, tmW.tmBreakChar, expect_break_W);
3026 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3027 "W: tmDefaultChar for %s got %02x expected %02x\n",
3028 font_name, tmW.tmDefaultChar, expect_default_W);
3030 /* Test the aspect ratio while we have tmW */
3031 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3032 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3033 tmW.tmDigitizedAspectX, ret);
3034 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3035 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3036 tmW.tmDigitizedAspectX, ret);
3040 /* test FF_ values */
3041 switch(tt_os2.panose.bFamilyType)
3043 case PAN_ANY:
3044 case PAN_NO_FIT:
3045 case PAN_FAMILY_TEXT_DISPLAY:
3046 case PAN_FAMILY_PICTORIAL:
3047 default:
3048 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3049 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3051 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3052 break;
3054 switch(tt_os2.panose.bSerifStyle)
3056 case PAN_ANY:
3057 case PAN_NO_FIT:
3058 default:
3059 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3060 break;
3062 case PAN_SERIF_COVE:
3063 case PAN_SERIF_OBTUSE_COVE:
3064 case PAN_SERIF_SQUARE_COVE:
3065 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3066 case PAN_SERIF_SQUARE:
3067 case PAN_SERIF_THIN:
3068 case PAN_SERIF_BONE:
3069 case PAN_SERIF_EXAGGERATED:
3070 case PAN_SERIF_TRIANGLE:
3071 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3072 break;
3074 case PAN_SERIF_NORMAL_SANS:
3075 case PAN_SERIF_OBTUSE_SANS:
3076 case PAN_SERIF_PERP_SANS:
3077 case PAN_SERIF_FLARED:
3078 case PAN_SERIF_ROUNDED:
3079 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3080 break;
3082 break;
3084 case PAN_FAMILY_SCRIPT:
3085 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3086 break;
3088 case PAN_FAMILY_DECORATIVE:
3089 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3090 break;
3093 test_negative_width(hdc, lf);
3095 end_of_test:
3096 SelectObject(hdc, hfont_old);
3097 DeleteObject(hfont);
3099 ReleaseDC(0, hdc);
3102 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3104 INT *enumed = (INT *)lParam;
3106 if (type == TRUETYPE_FONTTYPE)
3108 (*enumed)++;
3109 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3111 return 1;
3114 static void test_GetTextMetrics(void)
3116 LOGFONTA lf;
3117 HDC hdc;
3118 INT enumed;
3120 /* Report only once */
3121 if(!pGetGlyphIndicesA)
3122 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3124 hdc = GetDC(0);
3126 memset(&lf, 0, sizeof(lf));
3127 lf.lfCharSet = DEFAULT_CHARSET;
3128 enumed = 0;
3129 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3130 trace("Tested metrics of %d truetype fonts\n", enumed);
3132 ReleaseDC(0, hdc);
3135 static void test_nonexistent_font(void)
3137 static const struct
3139 const char *name;
3140 int charset;
3141 } font_subst[] =
3143 { "Times New Roman Baltic", 186 },
3144 { "Times New Roman CE", 238 },
3145 { "Times New Roman CYR", 204 },
3146 { "Times New Roman Greek", 161 },
3147 { "Times New Roman TUR", 162 }
3149 LOGFONTA lf;
3150 HDC hdc;
3151 HFONT hfont;
3152 CHARSETINFO csi;
3153 INT cs, expected_cs, i;
3154 char buf[LF_FACESIZE];
3156 if (!is_truetype_font_installed("Arial") ||
3157 !is_truetype_font_installed("Times New Roman"))
3159 skip("Arial or Times New Roman not installed\n");
3160 return;
3163 expected_cs = GetACP();
3164 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3166 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3167 return;
3169 expected_cs = csi.ciCharset;
3170 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3172 hdc = GetDC(0);
3174 memset(&lf, 0, sizeof(lf));
3175 lf.lfHeight = 100;
3176 lf.lfWeight = FW_REGULAR;
3177 lf.lfCharSet = ANSI_CHARSET;
3178 lf.lfPitchAndFamily = FF_SWISS;
3179 strcpy(lf.lfFaceName, "Nonexistent font");
3180 hfont = CreateFontIndirectA(&lf);
3181 hfont = SelectObject(hdc, hfont);
3182 GetTextFaceA(hdc, sizeof(buf), buf);
3183 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3184 cs = GetTextCharset(hdc);
3185 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3186 DeleteObject(SelectObject(hdc, hfont));
3188 memset(&lf, 0, sizeof(lf));
3189 lf.lfHeight = -13;
3190 lf.lfWeight = FW_DONTCARE;
3191 strcpy(lf.lfFaceName, "Nonexistent font");
3192 hfont = CreateFontIndirectA(&lf);
3193 hfont = SelectObject(hdc, hfont);
3194 GetTextFaceA(hdc, sizeof(buf), buf);
3195 todo_wine /* Wine uses Arial for all substitutions */
3196 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3197 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3198 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3199 "Got %s\n", buf);
3200 cs = GetTextCharset(hdc);
3201 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3202 DeleteObject(SelectObject(hdc, hfont));
3204 memset(&lf, 0, sizeof(lf));
3205 lf.lfHeight = -13;
3206 lf.lfWeight = FW_REGULAR;
3207 strcpy(lf.lfFaceName, "Nonexistent font");
3208 hfont = CreateFontIndirectA(&lf);
3209 hfont = SelectObject(hdc, hfont);
3210 GetTextFaceA(hdc, sizeof(buf), buf);
3211 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3212 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3213 cs = GetTextCharset(hdc);
3214 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3215 DeleteObject(SelectObject(hdc, hfont));
3217 memset(&lf, 0, sizeof(lf));
3218 lf.lfHeight = -13;
3219 lf.lfWeight = FW_DONTCARE;
3220 strcpy(lf.lfFaceName, "Times New Roman");
3221 hfont = CreateFontIndirectA(&lf);
3222 hfont = SelectObject(hdc, hfont);
3223 GetTextFaceA(hdc, sizeof(buf), buf);
3224 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3225 cs = GetTextCharset(hdc);
3226 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3227 DeleteObject(SelectObject(hdc, hfont));
3229 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3231 memset(&lf, 0, sizeof(lf));
3232 lf.lfHeight = -13;
3233 lf.lfWeight = FW_REGULAR;
3234 strcpy(lf.lfFaceName, font_subst[i].name);
3235 hfont = CreateFontIndirectA(&lf);
3236 hfont = SelectObject(hdc, hfont);
3237 cs = GetTextCharset(hdc);
3238 if (font_subst[i].charset == expected_cs)
3240 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3241 GetTextFaceA(hdc, sizeof(buf), buf);
3242 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3244 else
3246 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3247 GetTextFaceA(hdc, sizeof(buf), buf);
3248 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3249 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3251 DeleteObject(SelectObject(hdc, hfont));
3253 memset(&lf, 0, sizeof(lf));
3254 lf.lfHeight = -13;
3255 lf.lfWeight = FW_DONTCARE;
3256 strcpy(lf.lfFaceName, font_subst[i].name);
3257 hfont = CreateFontIndirectA(&lf);
3258 hfont = SelectObject(hdc, hfont);
3259 GetTextFaceA(hdc, sizeof(buf), buf);
3260 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3261 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3262 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3263 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3264 "got %s for font %s\n", buf, font_subst[i].name);
3265 cs = GetTextCharset(hdc);
3266 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3267 DeleteObject(SelectObject(hdc, hfont));
3270 ReleaseDC(0, hdc);
3273 static void test_GdiRealizationInfo(void)
3275 HDC hdc;
3276 DWORD info[4];
3277 BOOL r;
3278 HFONT hfont, hfont_old;
3279 LOGFONTA lf;
3281 if(!pGdiRealizationInfo)
3283 win_skip("GdiRealizationInfo not available\n");
3284 return;
3287 hdc = GetDC(0);
3289 memset(info, 0xcc, sizeof(info));
3290 r = pGdiRealizationInfo(hdc, info);
3291 ok(r != 0, "ret 0\n");
3292 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3293 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3295 if (!is_truetype_font_installed("Arial"))
3297 skip("skipping GdiRealizationInfo with truetype font\n");
3298 goto end;
3301 memset(&lf, 0, sizeof(lf));
3302 strcpy(lf.lfFaceName, "Arial");
3303 lf.lfHeight = 20;
3304 lf.lfWeight = FW_NORMAL;
3305 hfont = CreateFontIndirectA(&lf);
3306 hfont_old = SelectObject(hdc, hfont);
3308 memset(info, 0xcc, sizeof(info));
3309 r = pGdiRealizationInfo(hdc, info);
3310 ok(r != 0, "ret 0\n");
3311 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3312 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3314 DeleteObject(SelectObject(hdc, hfont_old));
3316 end:
3317 ReleaseDC(0, hdc);
3320 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3321 the nul in the count of characters copied when the face name buffer is not
3322 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3323 always includes it. */
3324 static void test_GetTextFace(void)
3326 static const char faceA[] = "Tahoma";
3327 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3328 LOGFONTA fA = {0};
3329 LOGFONTW fW = {0};
3330 char bufA[LF_FACESIZE];
3331 WCHAR bufW[LF_FACESIZE];
3332 HFONT f, g;
3333 HDC dc;
3334 int n;
3336 if(!is_font_installed("Tahoma"))
3338 skip("Tahoma is not installed so skipping this test\n");
3339 return;
3342 /* 'A' case. */
3343 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3344 f = CreateFontIndirectA(&fA);
3345 ok(f != NULL, "CreateFontIndirectA failed\n");
3347 dc = GetDC(NULL);
3348 g = SelectObject(dc, f);
3349 n = GetTextFaceA(dc, sizeof bufA, bufA);
3350 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3351 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3353 /* Play with the count arg. */
3354 bufA[0] = 'x';
3355 n = GetTextFaceA(dc, 0, bufA);
3356 ok(n == 0, "GetTextFaceA returned %d\n", n);
3357 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3359 bufA[0] = 'x';
3360 n = GetTextFaceA(dc, 1, bufA);
3361 ok(n == 0, "GetTextFaceA returned %d\n", n);
3362 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3364 bufA[0] = 'x'; bufA[1] = 'y';
3365 n = GetTextFaceA(dc, 2, bufA);
3366 ok(n == 1, "GetTextFaceA returned %d\n", n);
3367 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3369 n = GetTextFaceA(dc, 0, NULL);
3370 ok(n == sizeof faceA ||
3371 broken(n == 0), /* win98, winMe */
3372 "GetTextFaceA returned %d\n", n);
3374 DeleteObject(SelectObject(dc, g));
3375 ReleaseDC(NULL, dc);
3377 /* 'W' case. */
3378 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3379 SetLastError(0xdeadbeef);
3380 f = CreateFontIndirectW(&fW);
3381 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3383 win_skip("CreateFontIndirectW is not implemented\n");
3384 return;
3386 ok(f != NULL, "CreateFontIndirectW failed\n");
3388 dc = GetDC(NULL);
3389 g = SelectObject(dc, f);
3390 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3391 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3392 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3394 /* Play with the count arg. */
3395 bufW[0] = 'x';
3396 n = GetTextFaceW(dc, 0, bufW);
3397 ok(n == 0, "GetTextFaceW returned %d\n", n);
3398 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3400 bufW[0] = 'x';
3401 n = GetTextFaceW(dc, 1, bufW);
3402 ok(n == 1, "GetTextFaceW returned %d\n", n);
3403 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3405 bufW[0] = 'x'; bufW[1] = 'y';
3406 n = GetTextFaceW(dc, 2, bufW);
3407 ok(n == 2, "GetTextFaceW returned %d\n", n);
3408 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3410 n = GetTextFaceW(dc, 0, NULL);
3411 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3413 DeleteObject(SelectObject(dc, g));
3414 ReleaseDC(NULL, dc);
3417 static void test_orientation(void)
3419 static const char test_str[11] = "Test String";
3420 HDC hdc;
3421 LOGFONTA lf;
3422 HFONT hfont, old_hfont;
3423 SIZE size;
3425 if (!is_truetype_font_installed("Arial"))
3427 skip("Arial is not installed\n");
3428 return;
3431 hdc = CreateCompatibleDC(0);
3432 memset(&lf, 0, sizeof(lf));
3433 lstrcpyA(lf.lfFaceName, "Arial");
3434 lf.lfHeight = 72;
3435 lf.lfOrientation = lf.lfEscapement = 900;
3436 hfont = create_font("orientation", &lf);
3437 old_hfont = SelectObject(hdc, hfont);
3438 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3439 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3440 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3441 SelectObject(hdc, old_hfont);
3442 DeleteObject(hfont);
3443 DeleteDC(hdc);
3446 static void test_oemcharset(void)
3448 HDC hdc;
3449 LOGFONTA lf, clf;
3450 HFONT hfont, old_hfont;
3451 int charset;
3453 hdc = CreateCompatibleDC(0);
3454 ZeroMemory(&lf, sizeof(lf));
3455 lf.lfHeight = 12;
3456 lf.lfCharSet = OEM_CHARSET;
3457 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3458 lstrcpyA(lf.lfFaceName, "Terminal");
3459 hfont = CreateFontIndirectA(&lf);
3460 old_hfont = SelectObject(hdc, hfont);
3461 charset = GetTextCharset(hdc);
3462 todo_wine
3463 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3464 hfont = SelectObject(hdc, old_hfont);
3465 GetObjectA(hfont, sizeof(clf), &clf);
3466 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3467 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3468 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3469 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3470 DeleteObject(hfont);
3471 DeleteDC(hdc);
3474 static void test_GetGlyphOutline(void)
3476 HDC hdc;
3477 GLYPHMETRICS gm, gm2;
3478 LOGFONTA lf;
3479 HFONT hfont, old_hfont;
3480 INT ret, ret2;
3481 static const struct
3483 UINT cs;
3484 UINT a;
3485 UINT w;
3486 } c[] =
3488 {ANSI_CHARSET, 0x30, 0x30},
3489 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3490 {HANGEUL_CHARSET, 0x8141, 0xac02},
3491 {JOHAB_CHARSET, 0x8446, 0x3135},
3492 {GB2312_CHARSET, 0x8141, 0x4e04},
3493 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3495 UINT i;
3497 if (!is_truetype_font_installed("Tahoma"))
3499 skip("Tahoma is not installed\n");
3500 return;
3503 hdc = CreateCompatibleDC(0);
3504 memset(&lf, 0, sizeof(lf));
3505 lf.lfHeight = 72;
3506 lstrcpyA(lf.lfFaceName, "Tahoma");
3507 SetLastError(0xdeadbeef);
3508 hfont = CreateFontIndirectA(&lf);
3509 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3510 old_hfont = SelectObject(hdc, hfont);
3512 memset(&gm, 0, sizeof(gm));
3513 SetLastError(0xdeadbeef);
3514 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3515 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3517 memset(&gm, 0, sizeof(gm));
3518 SetLastError(0xdeadbeef);
3519 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3520 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3521 ok(GetLastError() == 0xdeadbeef ||
3522 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3523 "expected 0xdeadbeef, got %u\n", GetLastError());
3525 memset(&gm, 0, sizeof(gm));
3526 SetLastError(0xdeadbeef);
3527 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3528 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3529 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3531 memset(&gm, 0, sizeof(gm));
3532 SetLastError(0xdeadbeef);
3533 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3534 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3536 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3537 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3540 /* test for needed buffer size request on space char */
3541 memset(&gm, 0, sizeof(gm));
3542 SetLastError(0xdeadbeef);
3543 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3544 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3545 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3547 /* requesting buffer size for space char + error */
3548 memset(&gm, 0, sizeof(gm));
3549 SetLastError(0xdeadbeef);
3550 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3551 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3553 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3554 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3557 SelectObject(hdc, old_hfont);
3558 DeleteObject(hfont);
3560 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3562 lf.lfFaceName[0] = '\0';
3563 lf.lfCharSet = c[i].cs;
3564 lf.lfPitchAndFamily = 0;
3565 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3567 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3568 continue;
3571 old_hfont = SelectObject(hdc, hfont);
3573 /* expected to ignore superfluous bytes (sigle-byte character) */
3574 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3575 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3576 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3578 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3579 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3580 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3582 /* expected to ignore superfluous bytes (double-byte character) */
3583 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3584 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3585 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3586 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3588 /* expected to match wide-char version results */
3589 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3590 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3592 hfont = SelectObject(hdc, old_hfont);
3593 DeleteObject(hfont);
3596 DeleteDC(hdc);
3599 /* bug #9995: there is a limit to the character width that can be specified */
3600 static void test_GetTextMetrics2(const char *fontname, int font_height)
3602 HFONT of, hf;
3603 HDC hdc;
3604 TEXTMETRICA tm;
3605 BOOL ret;
3606 int ave_width, height, width, ratio, scale;
3608 if (!is_truetype_font_installed( fontname)) {
3609 skip("%s is not installed\n", fontname);
3610 return;
3612 hdc = CreateCompatibleDC(0);
3613 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3614 /* select width = 0 */
3615 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3616 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3617 DEFAULT_QUALITY, VARIABLE_PITCH,
3618 fontname);
3619 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3620 of = SelectObject( hdc, hf);
3621 ret = GetTextMetricsA( hdc, &tm);
3622 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3623 height = tm.tmHeight;
3624 ave_width = tm.tmAveCharWidth;
3625 SelectObject( hdc, of);
3626 DeleteObject( hf);
3628 trace("height %d, ave width %d\n", height, ave_width);
3630 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3632 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3633 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3634 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3635 ok(hf != 0, "CreateFont failed\n");
3636 of = SelectObject(hdc, hf);
3637 ret = GetTextMetrics(hdc, &tm);
3638 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3639 SelectObject(hdc, of);
3640 DeleteObject(hf);
3642 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3643 break;
3646 DeleteDC(hdc);
3648 ratio = width / height;
3649 scale = width / ave_width;
3651 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3652 width, height, ratio, width, ave_width, scale);
3654 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3657 static void test_CreateFontIndirect(void)
3659 LOGFONTA lf, getobj_lf;
3660 int ret, i;
3661 HFONT hfont;
3662 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3664 memset(&lf, 0, sizeof(lf));
3665 lf.lfCharSet = ANSI_CHARSET;
3666 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3667 lf.lfHeight = 16;
3668 lf.lfWidth = 16;
3669 lf.lfQuality = DEFAULT_QUALITY;
3670 lf.lfItalic = FALSE;
3671 lf.lfWeight = FW_DONTCARE;
3673 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3675 lstrcpyA(lf.lfFaceName, TestName[i]);
3676 hfont = CreateFontIndirectA(&lf);
3677 ok(hfont != 0, "CreateFontIndirectA failed\n");
3678 SetLastError(0xdeadbeef);
3679 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3680 ok(ret, "GetObject failed: %d\n", GetLastError());
3681 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3682 ok(lf.lfWeight == getobj_lf.lfWeight ||
3683 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3684 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3685 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3686 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3687 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3688 DeleteObject(hfont);
3692 static void test_CreateFontIndirectEx(void)
3694 ENUMLOGFONTEXDVA lfex;
3695 HFONT hfont;
3697 if (!pCreateFontIndirectExA)
3699 win_skip("CreateFontIndirectExA is not available\n");
3700 return;
3703 if (!is_truetype_font_installed("Arial"))
3705 skip("Arial is not installed\n");
3706 return;
3709 SetLastError(0xdeadbeef);
3710 hfont = pCreateFontIndirectExA(NULL);
3711 ok(hfont == NULL, "got %p\n", hfont);
3712 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3714 memset(&lfex, 0, sizeof(lfex));
3715 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3716 hfont = pCreateFontIndirectExA(&lfex);
3717 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3718 if (hfont)
3719 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3720 DeleteObject(hfont);
3723 static void free_font(void *font)
3725 UnmapViewOfFile(font);
3728 static void *load_font(const char *font_name, DWORD *font_size)
3730 char file_name[MAX_PATH];
3731 HANDLE file, mapping;
3732 void *font;
3734 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3735 strcat(file_name, "\\fonts\\");
3736 strcat(file_name, font_name);
3738 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3739 if (file == INVALID_HANDLE_VALUE) return NULL;
3741 *font_size = GetFileSize(file, NULL);
3743 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3744 if (!mapping)
3746 CloseHandle(file);
3747 return NULL;
3750 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3752 CloseHandle(file);
3753 CloseHandle(mapping);
3754 return font;
3757 static void test_AddFontMemResource(void)
3759 void *font;
3760 DWORD font_size, num_fonts;
3761 HANDLE ret;
3762 BOOL bRet;
3764 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3766 win_skip("AddFontMemResourceEx is not available on this platform\n");
3767 return;
3770 font = load_font("sserife.fon", &font_size);
3771 if (!font)
3773 skip("Unable to locate and load font sserife.fon\n");
3774 return;
3777 SetLastError(0xdeadbeef);
3778 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3779 ok(!ret, "AddFontMemResourceEx should fail\n");
3780 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3781 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3782 GetLastError());
3784 SetLastError(0xdeadbeef);
3785 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3786 ok(!ret, "AddFontMemResourceEx should fail\n");
3787 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3788 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3789 GetLastError());
3791 SetLastError(0xdeadbeef);
3792 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3793 ok(!ret, "AddFontMemResourceEx should fail\n");
3794 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3795 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3796 GetLastError());
3798 SetLastError(0xdeadbeef);
3799 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3800 ok(!ret, "AddFontMemResourceEx should fail\n");
3801 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3802 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3803 GetLastError());
3805 SetLastError(0xdeadbeef);
3806 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3807 ok(!ret, "AddFontMemResourceEx should fail\n");
3808 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3809 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3810 GetLastError());
3812 SetLastError(0xdeadbeef);
3813 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3814 ok(!ret, "AddFontMemResourceEx should fail\n");
3815 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3816 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3817 GetLastError());
3819 num_fonts = 0xdeadbeef;
3820 SetLastError(0xdeadbeef);
3821 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3822 ok(!ret, "AddFontMemResourceEx should fail\n");
3823 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3824 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3825 GetLastError());
3826 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3828 if (0) /* hangs under windows 2000 */
3830 num_fonts = 0xdeadbeef;
3831 SetLastError(0xdeadbeef);
3832 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3833 ok(!ret, "AddFontMemResourceEx should fail\n");
3834 ok(GetLastError() == 0xdeadbeef,
3835 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3836 GetLastError());
3837 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3840 num_fonts = 0xdeadbeef;
3841 SetLastError(0xdeadbeef);
3842 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3843 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3844 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3845 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3847 free_font(font);
3849 SetLastError(0xdeadbeef);
3850 bRet = pRemoveFontMemResourceEx(ret);
3851 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3853 /* test invalid pointer to number of loaded fonts */
3854 font = load_font("sserife.fon", &font_size);
3855 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3857 SetLastError(0xdeadbeef);
3858 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3859 ok(!ret, "AddFontMemResourceEx should fail\n");
3860 ok(GetLastError() == 0xdeadbeef,
3861 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3862 GetLastError());
3864 SetLastError(0xdeadbeef);
3865 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3866 ok(!ret, "AddFontMemResourceEx should fail\n");
3867 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3868 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3869 GetLastError());
3871 free_font(font);
3874 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3876 LOGFONT *lf;
3878 if (type != TRUETYPE_FONTTYPE) return 1;
3880 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3882 lf = (LOGFONT *)lparam;
3883 *lf = *elf;
3884 return 0;
3887 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3889 int ret;
3890 LOGFONT *lf;
3892 if (type != TRUETYPE_FONTTYPE) return 1;
3894 lf = (LOGFONT *)lparam;
3895 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3896 if(ret == 0)
3898 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3899 *lf = *elf;
3900 return 0;
3902 return 1;
3905 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3907 return lparam;
3910 static void test_EnumFonts(void)
3912 int ret;
3913 LOGFONT lf;
3914 HDC hdc;
3916 if (!is_truetype_font_installed("Arial"))
3918 skip("Arial is not installed\n");
3919 return;
3922 /* Windows uses localized font face names, so Arial Bold won't be found */
3923 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3925 skip("User locale is not English, skipping the test\n");
3926 return;
3929 hdc = CreateCompatibleDC(0);
3931 /* check that the enumproc's retval is returned */
3932 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
3933 ok(ret == 0xcafe, "got %08x\n", ret);
3935 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3936 ok(!ret, "font Arial is not enumerated\n");
3937 ret = strcmp(lf.lfFaceName, "Arial");
3938 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3939 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3941 lstrcpy(lf.lfFaceName, "Arial");
3942 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3943 ok(!ret, "font Arial is not enumerated\n");
3944 ret = strcmp(lf.lfFaceName, "Arial");
3945 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3946 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3948 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3949 ok(!ret, "font Arial Bold is not enumerated\n");
3950 ret = strcmp(lf.lfFaceName, "Arial");
3951 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3952 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3954 lstrcpy(lf.lfFaceName, "Arial Bold");
3955 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3956 ok(ret, "font Arial Bold should not be enumerated\n");
3958 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3959 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3960 ret = strcmp(lf.lfFaceName, "Arial");
3961 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3962 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3964 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3965 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3966 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3968 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3969 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3971 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3972 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3973 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3975 DeleteDC(hdc);
3978 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3980 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3981 const char *fullname = (const char *)lParam;
3983 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3985 return 1;
3988 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3990 HDC hdc = GetDC(0);
3991 BOOL ret = FALSE;
3993 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3994 ret = TRUE;
3996 ReleaseDC(0, hdc);
3997 return ret;
4000 static void test_fullname(void)
4002 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4003 WCHAR bufW[LF_FULLFACESIZE];
4004 char bufA[LF_FULLFACESIZE];
4005 HFONT hfont, of;
4006 LOGFONTA lf;
4007 HDC hdc;
4008 int i;
4009 DWORD ret;
4011 hdc = CreateCompatibleDC(0);
4012 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4014 memset(&lf, 0, sizeof(lf));
4015 lf.lfCharSet = ANSI_CHARSET;
4016 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4017 lf.lfHeight = 16;
4018 lf.lfWidth = 16;
4019 lf.lfQuality = DEFAULT_QUALITY;
4020 lf.lfItalic = FALSE;
4021 lf.lfWeight = FW_DONTCARE;
4023 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4025 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4027 skip("%s is not installed\n", TestName[i]);
4028 continue;
4031 lstrcpyA(lf.lfFaceName, TestName[i]);
4032 hfont = CreateFontIndirectA(&lf);
4033 ok(hfont != 0, "CreateFontIndirectA failed\n");
4035 of = SelectObject(hdc, hfont);
4036 bufW[0] = 0;
4037 bufA[0] = 0;
4038 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4039 ok(ret, "face full name could not be read\n");
4040 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4041 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4042 SelectObject(hdc, of);
4043 DeleteObject(hfont);
4045 DeleteDC(hdc);
4048 static void test_fullname2_helper(const char *Family)
4050 char *FamilyName, *FaceName, *StyleName, *otmStr;
4051 struct enum_fullname_data efnd;
4052 WCHAR *bufW;
4053 char *bufA;
4054 HFONT hfont, of;
4055 LOGFONTA lf;
4056 HDC hdc;
4057 int i;
4058 DWORD otm_size, ret, buf_size;
4059 OUTLINETEXTMETRICA *otm;
4061 hdc = CreateCompatibleDC(0);
4062 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4064 memset(&lf, 0, sizeof(lf));
4065 lf.lfCharSet = DEFAULT_CHARSET;
4066 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4067 lf.lfHeight = 16;
4068 lf.lfWidth = 16;
4069 lf.lfQuality = DEFAULT_QUALITY;
4070 lf.lfItalic = FALSE;
4071 lf.lfWeight = FW_DONTCARE;
4072 lstrcpy(lf.lfFaceName, Family);
4073 efnd.total = 0;
4074 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4075 if (efnd.total == 0)
4076 skip("%s is not installed\n", lf.lfFaceName);
4078 for (i = 0; i < efnd.total; i++)
4080 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4081 FaceName = (char *)efnd.elf[i].elfFullName;
4082 StyleName = (char *)efnd.elf[i].elfStyle;
4084 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4086 lstrcpyA(lf.lfFaceName, FaceName);
4087 hfont = CreateFontIndirectA(&lf);
4088 ok(hfont != 0, "CreateFontIndirectA failed\n");
4090 of = SelectObject(hdc, hfont);
4091 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4092 ok(buf_size != GDI_ERROR, "no name table found\n");
4093 if (buf_size == GDI_ERROR) continue;
4095 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4096 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4098 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4099 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4100 memset(otm, 0, otm_size);
4101 ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4102 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4103 if (ret == 0) continue;
4105 bufW[0] = 0;
4106 bufA[0] = 0;
4107 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4108 if (!ret)
4110 trace("no localized FONT_FAMILY found.\n");
4111 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4113 ok(ret, "FAMILY (family name) could not be read\n");
4114 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4115 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4116 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4117 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4119 bufW[0] = 0;
4120 bufA[0] = 0;
4121 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4122 if (!ret)
4124 trace("no localized FULL_NAME found.\n");
4125 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4127 ok(ret, "FULL_NAME (face name) could not be read\n");
4128 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4129 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4130 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4131 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4133 bufW[0] = 0;
4134 bufA[0] = 0;
4135 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4136 ok(ret, "SUBFAMILY (style name) could not be read\n");
4137 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4138 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4139 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4140 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4142 bufW[0] = 0;
4143 bufA[0] = 0;
4144 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4145 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4146 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4147 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4148 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4150 SelectObject(hdc, of);
4151 DeleteObject(hfont);
4153 HeapFree(GetProcessHeap(), 0, otm);
4154 HeapFree(GetProcessHeap(), 0, bufW);
4155 HeapFree(GetProcessHeap(), 0, bufA);
4157 DeleteDC(hdc);
4160 static void test_fullname2(void)
4162 test_fullname2_helper("Lucida Sans");
4165 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4167 char tmp_path[MAX_PATH];
4168 HRSRC rsrc;
4169 void *rsrc_data;
4170 DWORD rsrc_size;
4171 HANDLE hfile;
4172 BOOL ret;
4174 SetLastError(0xdeadbeef);
4175 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4176 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4177 if (!rsrc) return FALSE;
4178 SetLastError(0xdeadbeef);
4179 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4180 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4181 if (!rsrc_data) return FALSE;
4182 SetLastError(0xdeadbeef);
4183 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4184 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4185 if (!rsrc_size) return FALSE;
4187 SetLastError(0xdeadbeef);
4188 ret = GetTempPath(MAX_PATH, tmp_path);
4189 ok(ret, "GetTempPath() error %d\n", GetLastError());
4190 SetLastError(0xdeadbeef);
4191 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4192 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4194 SetLastError(0xdeadbeef);
4195 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4196 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4197 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4199 SetLastError(0xdeadbeef);
4200 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4201 ok(ret, "WriteFile() error %d\n", GetLastError());
4203 CloseHandle(hfile);
4204 return ret;
4207 static void test_CreateScalableFontResource(void)
4209 char ttf_name[MAX_PATH];
4210 char tmp_path[MAX_PATH];
4211 char fot_name[MAX_PATH];
4212 char *file_part;
4213 DWORD ret;
4215 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4217 win_skip("AddFontResourceExA is not available on this platform\n");
4218 return;
4221 if (!write_ttf_file("wine_test.ttf", ttf_name))
4223 skip("Failed to create ttf file for testing\n");
4224 return;
4227 trace("created %s\n", ttf_name);
4229 ret = is_truetype_font_installed("wine_test");
4230 ok(!ret, "font wine_test should not be enumerated\n");
4232 ret = GetTempPath(MAX_PATH, tmp_path);
4233 ok(ret, "GetTempPath() error %d\n", GetLastError());
4234 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4235 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4237 ret = GetFileAttributes(fot_name);
4238 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4240 SetLastError(0xdeadbeef);
4241 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4242 ok(!ret, "CreateScalableFontResource() should fail\n");
4243 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4245 SetLastError(0xdeadbeef);
4246 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4247 ok(!ret, "CreateScalableFontResource() should fail\n");
4248 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4250 file_part = strrchr(ttf_name, '\\');
4251 SetLastError(0xdeadbeef);
4252 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4253 ok(!ret, "CreateScalableFontResource() should fail\n");
4254 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4256 SetLastError(0xdeadbeef);
4257 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4258 ok(!ret, "CreateScalableFontResource() should fail\n");
4259 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4261 SetLastError(0xdeadbeef);
4262 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4263 ok(!ret, "CreateScalableFontResource() should fail\n");
4264 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4266 ret = DeleteFile(fot_name);
4267 ok(ret, "DeleteFile() error %d\n", GetLastError());
4269 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4270 todo_wine
4271 ok(!ret, "RemoveFontResourceEx() should fail\n");
4273 /* test public font resource */
4274 SetLastError(0xdeadbeef);
4275 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4276 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4278 ret = is_truetype_font_installed("wine_test");
4279 ok(!ret, "font wine_test should not be enumerated\n");
4281 SetLastError(0xdeadbeef);
4282 ret = pAddFontResourceExA(fot_name, 0, 0);
4283 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4285 ret = is_truetype_font_installed("wine_test");
4286 ok(ret, "font wine_test should be enumerated\n");
4288 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4289 todo_wine
4290 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4292 SetLastError(0xdeadbeef);
4293 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4294 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4296 ret = is_truetype_font_installed("wine_test");
4297 todo_wine
4298 ok(!ret, "font wine_test should not be enumerated\n");
4300 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4301 if (ret)
4303 /* remove once RemoveFontResource is implemented */
4304 DeleteFile(fot_name);
4305 DeleteFile(ttf_name);
4306 return;
4309 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4310 ok(!ret, "RemoveFontResourceEx() should fail\n");
4312 DeleteFile(fot_name);
4314 /* test hidden font resource */
4315 SetLastError(0xdeadbeef);
4316 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4317 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4319 ret = is_truetype_font_installed("wine_test");
4320 ok(!ret, "font wine_test should not be enumerated\n");
4322 SetLastError(0xdeadbeef);
4323 ret = pAddFontResourceExA(fot_name, 0, 0);
4324 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4326 ret = is_truetype_font_installed("wine_test");
4327 ok(!ret, "font wine_test should not be enumerated\n");
4329 /* XP allows removing a private font added with 0 flags */
4330 SetLastError(0xdeadbeef);
4331 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4332 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4334 ret = is_truetype_font_installed("wine_test");
4335 ok(!ret, "font wine_test should not be enumerated\n");
4337 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4338 ok(!ret, "RemoveFontResourceEx() should fail\n");
4340 DeleteFile(fot_name);
4341 DeleteFile(ttf_name);
4344 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4346 LOGFONTA lf;
4347 HFONT hfont, hfont_prev;
4348 HDC hdc;
4349 char facename[100];
4350 DWORD ret;
4351 static const WCHAR str[] = { 0x2025 };
4353 *installed = is_truetype_font_installed(name);
4355 lf.lfHeight = -18;
4356 lf.lfWidth = 0;
4357 lf.lfEscapement = 0;
4358 lf.lfOrientation = 0;
4359 lf.lfWeight = FW_DONTCARE;
4360 lf.lfItalic = 0;
4361 lf.lfUnderline = 0;
4362 lf.lfStrikeOut = 0;
4363 lf.lfCharSet = DEFAULT_CHARSET;
4364 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4365 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4366 lf.lfQuality = DEFAULT_QUALITY;
4367 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4368 strcpy(lf.lfFaceName, name);
4370 hfont = CreateFontIndirectA(&lf);
4371 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4373 hdc = GetDC(NULL);
4375 hfont_prev = SelectObject(hdc, hfont);
4376 ok(hfont_prev != NULL, "SelectObject failed\n");
4378 ret = GetTextFaceA(hdc, sizeof facename, facename);
4379 ok(ret, "GetTextFaceA failed\n");
4380 *selected = !strcmp(facename, name);
4382 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4383 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4384 if (!*selected)
4385 memset(gm, 0, sizeof *gm);
4387 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4388 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4390 SelectObject(hdc, hfont_prev);
4391 DeleteObject(hfont);
4392 ReleaseDC(NULL, hdc);
4395 static void test_vertical_font(void)
4397 char ttf_name[MAX_PATH];
4398 int num;
4399 BOOL ret, installed, selected;
4400 GLYPHMETRICS gm;
4401 WORD hgi, vgi;
4403 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4405 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4406 return;
4409 if (!write_ttf_file("vertical.ttf", ttf_name))
4411 skip("Failed to create ttf file for testing\n");
4412 return;
4415 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4416 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4418 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4419 ok(installed, "@WineTestVertical is not installed\n");
4420 ok(selected, "@WineTestVertical is not selected\n");
4421 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4422 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4423 gm.gmBlackBoxX, gm.gmBlackBoxY);
4425 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4426 ok(installed, "@@WineTestVertical is not installed\n");
4427 ok(selected, "@@WineTestVertical is not selected\n");
4428 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4429 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4430 gm.gmBlackBoxX, gm.gmBlackBoxY);
4432 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4434 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4435 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4437 DeleteFile(ttf_name);
4440 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4441 DWORD type, LPARAM lParam)
4443 if (lf->lfFaceName[0] == '@') {
4444 return 0;
4446 return 1;
4449 static void test_east_asian_font_selection(void)
4451 HDC hdc;
4452 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4453 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4454 size_t i;
4456 hdc = GetDC(NULL);
4458 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4460 LOGFONTA lf;
4461 HFONT hfont;
4462 char face_name[LF_FACESIZE];
4463 int ret;
4465 memset(&lf, 0, sizeof lf);
4466 lf.lfFaceName[0] = '\0';
4467 lf.lfCharSet = charset[i];
4469 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4471 skip("Vertical font for charset %u is not installed\n", charset[i]);
4472 continue;
4475 hfont = CreateFontIndirectA(&lf);
4476 hfont = SelectObject(hdc, hfont);
4477 memset(face_name, 0, sizeof face_name);
4478 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4479 ok(ret && face_name[0] != '@',
4480 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4481 DeleteObject(SelectObject(hdc, hfont));
4483 memset(&lf, 0, sizeof lf);
4484 strcpy(lf.lfFaceName, "@");
4485 lf.lfCharSet = charset[i];
4486 hfont = CreateFontIndirectA(&lf);
4487 hfont = SelectObject(hdc, hfont);
4488 memset(face_name, 0, sizeof face_name);
4489 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4490 ok(ret && face_name[0] == '@',
4491 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4492 DeleteObject(SelectObject(hdc, hfont));
4494 ReleaseDC(NULL, hdc);
4497 static int get_font_dpi(const LOGFONT *lf)
4499 HDC hdc = CreateCompatibleDC(0);
4500 HFONT hfont;
4501 TEXTMETRIC tm;
4502 int ret;
4504 hfont = CreateFontIndirect(lf);
4505 ok(hfont != 0, "CreateFontIndirect failed\n");
4507 SelectObject(hdc, hfont);
4508 ret = GetTextMetrics(hdc, &tm);
4509 ok(ret, "GetTextMetrics failed\n");
4510 ret = tm.tmDigitizedAspectX;
4512 DeleteDC(hdc);
4513 DeleteObject(hfont);
4515 return ret;
4518 static void test_stock_fonts(void)
4520 static const int font[] =
4522 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4523 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4525 static const struct test_data
4527 int charset, weight, height, dpi;
4528 const char face_name[LF_FACESIZE];
4529 } td[][11] =
4531 { /* ANSI_FIXED_FONT */
4532 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4533 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4534 { 0 }
4536 { /* ANSI_VAR_FONT */
4537 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4538 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4539 { 0 }
4541 { /* SYSTEM_FONT */
4542 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4543 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4544 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4545 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4546 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4547 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4548 { 0 }
4550 { /* DEVICE_DEFAULT_FONT */
4551 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4552 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4553 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4554 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4555 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4556 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4557 { 0 }
4559 { /* DEFAULT_GUI_FONT */
4560 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4561 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4562 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4563 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4564 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4565 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4566 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4567 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4568 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4569 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4570 { 0 }
4573 int i, j;
4575 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4577 HFONT hfont;
4578 LOGFONT lf;
4579 int ret;
4581 hfont = GetStockObject(font[i]);
4582 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4584 ret = GetObject(hfont, sizeof(lf), &lf);
4585 if (ret != sizeof(lf))
4587 /* NT4 */
4588 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4589 continue;
4592 for (j = 0; td[i][j].face_name[0] != 0; j++)
4594 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4596 continue;
4599 ret = get_font_dpi(&lf);
4600 if (ret != td[i][j].dpi)
4602 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4603 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4604 continue;
4607 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4608 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4609 if (td[i][j].face_name[0] == '?')
4611 /* Wine doesn't have this font, skip this case for now.
4612 Actually, the face name is localized on Windows and varies
4613 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4614 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4616 else
4618 ok(!lstrcmp(td[i][j].face_name, lf.lfFaceName), "%d(%d): expected lfFaceName %s, got %s\n", i, j, td[i][j].face_name, lf.lfFaceName);
4620 break;
4625 START_TEST(font)
4627 init();
4629 test_stock_fonts();
4630 test_logfont();
4631 test_bitmap_font();
4632 test_outline_font();
4633 test_bitmap_font_metrics();
4634 test_GdiGetCharDimensions();
4635 test_GetCharABCWidths();
4636 test_text_extents();
4637 test_GetGlyphIndices();
4638 test_GetKerningPairs();
4639 test_GetOutlineTextMetrics();
4640 test_SetTextJustification();
4641 test_font_charset();
4642 test_GetFontUnicodeRanges();
4643 test_nonexistent_font();
4644 test_orientation();
4645 test_height_selection();
4646 test_AddFontMemResource();
4647 test_EnumFonts();
4649 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4650 * I'd like to avoid them in this test.
4652 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4653 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4654 if (is_truetype_font_installed("Arial Black") &&
4655 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4657 test_EnumFontFamilies("", ANSI_CHARSET);
4658 test_EnumFontFamilies("", SYMBOL_CHARSET);
4659 test_EnumFontFamilies("", DEFAULT_CHARSET);
4661 else
4662 skip("Arial Black or Symbol/Wingdings is not installed\n");
4663 test_EnumFontFamiliesEx_default_charset();
4664 test_GetTextMetrics();
4665 test_GdiRealizationInfo();
4666 test_GetTextFace();
4667 test_GetGlyphOutline();
4668 test_GetTextMetrics2("Tahoma", -11);
4669 test_GetTextMetrics2("Tahoma", -55);
4670 test_GetTextMetrics2("Tahoma", -110);
4671 test_GetTextMetrics2("Arial", -11);
4672 test_GetTextMetrics2("Arial", -55);
4673 test_GetTextMetrics2("Arial", -110);
4674 test_CreateFontIndirect();
4675 test_CreateFontIndirectEx();
4676 test_oemcharset();
4677 test_fullname();
4678 test_fullname2();
4679 test_east_asian_font_selection();
4681 /* These tests should be last test until RemoveFontResource
4682 * is properly implemented.
4684 test_vertical_font();
4685 test_CreateScalableFontResource();