gdi32: EnumFontFamilies should enumerate substituted fonts only when directly asked...
[wine.git] / dlls / gdi32 / tests / font.c
blobcce4a1f7ca892c259c2ce565e2d8089b5f8b93c0
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, exact) (abs((a) - (b)) <= ((exact) ? 0 : 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 BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
46 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
47 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
48 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
49 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
50 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
51 LPINT nfit, LPINT dxs, LPSIZE size );
52 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
53 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
54 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
55 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
56 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
57 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
59 static HMODULE hgdi32 = 0;
60 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
61 static WORD system_lang_id;
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
66 #else
67 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
69 #endif
71 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
72 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
73 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
74 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
75 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
76 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
78 static void init(void)
80 hgdi32 = GetModuleHandleA("gdi32.dll");
82 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
83 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
84 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
85 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
86 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
87 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
88 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
89 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
90 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
91 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
92 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
93 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
94 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
95 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
96 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
97 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
98 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
99 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
101 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
104 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
106 if (type != TRUETYPE_FONTTYPE) return 1;
108 return 0;
111 static BOOL is_truetype_font_installed(const char *name)
113 HDC hdc = GetDC(0);
114 BOOL ret = FALSE;
116 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
117 ret = TRUE;
119 ReleaseDC(0, hdc);
120 return ret;
123 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
125 return 0;
128 static BOOL is_font_installed(const char *name)
130 HDC hdc = GetDC(0);
131 BOOL ret = FALSE;
133 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
134 ret = TRUE;
136 ReleaseDC(0, hdc);
137 return ret;
140 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
142 HRSRC rsrc;
143 void *rsrc_data;
145 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
146 if (!rsrc) return NULL;
148 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
149 if (!rsrc_data) return NULL;
151 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
152 if (!*rsrc_size) return NULL;
154 return rsrc_data;
157 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
159 char tmp_path[MAX_PATH];
160 HANDLE hfile;
161 BOOL ret;
163 GetTempPathA(MAX_PATH, tmp_path);
164 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
166 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
167 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
169 ret = WriteFile(hfile, data, *size, size, NULL);
171 CloseHandle(hfile);
172 return ret;
175 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
177 void *rsrc_data;
178 DWORD rsrc_size;
180 rsrc_data = get_res_data( fontname, &rsrc_size );
181 if (!rsrc_data) return FALSE;
183 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
186 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
188 LOGFONTA getobj_lf;
189 int ret, minlen = 0;
191 if (!hfont)
192 return;
194 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
195 /* NT4 tries to be clever and only returns the minimum length */
196 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
197 minlen++;
198 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
199 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
200 ok(lf->lfHeight == getobj_lf.lfHeight ||
201 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
202 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
203 ok(lf->lfWidth == getobj_lf.lfWidth ||
204 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
205 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
206 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
207 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
208 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
209 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
210 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
211 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
212 ok(lf->lfWeight == getobj_lf.lfWeight ||
213 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
214 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
215 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
216 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
217 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
218 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
219 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
220 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
221 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
222 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
223 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
224 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
225 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
228 static HFONT create_font(const char* test, const LOGFONTA* lf)
230 HFONT hfont = CreateFontIndirectA(lf);
231 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
232 if (hfont)
233 check_font(test, lf, hfont);
234 return hfont;
237 static void test_logfont(void)
239 LOGFONTA lf;
240 HFONT hfont;
242 memset(&lf, 0, sizeof lf);
244 lf.lfCharSet = ANSI_CHARSET;
245 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
246 lf.lfWeight = FW_DONTCARE;
247 lf.lfHeight = 16;
248 lf.lfWidth = 16;
249 lf.lfQuality = DEFAULT_QUALITY;
251 lstrcpyA(lf.lfFaceName, "Arial");
252 hfont = create_font("Arial", &lf);
253 DeleteObject(hfont);
255 memset(&lf, 'A', sizeof(lf));
256 hfont = CreateFontIndirectA(&lf);
257 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
259 lf.lfFaceName[LF_FACESIZE - 1] = 0;
260 check_font("AAA...", &lf, hfont);
261 DeleteObject(hfont);
264 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
266 if (type & RASTER_FONTTYPE)
268 LOGFONTA *lf = (LOGFONTA *)lParam;
269 *lf = *elf;
270 return 0; /* stop enumeration */
273 return 1; /* continue enumeration */
276 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
278 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
279 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
280 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
281 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
282 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
283 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
284 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
285 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
286 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
287 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
288 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
289 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
290 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
291 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
292 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
293 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
294 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
295 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
296 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
297 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
300 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
301 LONG lfWidth, const char *test_str,
302 INT test_str_len, const TEXTMETRICA *tm_orig,
303 const SIZE *size_orig, INT width_of_A_orig,
304 INT scale_x, INT scale_y)
306 LOGFONTA lf;
307 OUTLINETEXTMETRICA otm;
308 TEXTMETRICA tm;
309 SIZE size;
310 INT width_of_A, cx, cy;
311 UINT ret;
313 if (!hfont)
314 return;
316 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
318 GetObjectA(hfont, sizeof(lf), &lf);
320 if (GetOutlineTextMetricsA(hdc, 0, NULL))
322 otm.otmSize = sizeof(otm) / 2;
323 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
324 ok(ret == sizeof(otm)/2 /* XP */ ||
325 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
327 memset(&otm, 0x1, sizeof(otm));
328 otm.otmSize = sizeof(otm);
329 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
330 ok(ret == sizeof(otm) /* XP */ ||
331 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
333 memset(&tm, 0x2, sizeof(tm));
334 ret = GetTextMetricsA(hdc, &tm);
335 ok(ret, "GetTextMetricsA failed\n");
336 /* the structure size is aligned */
337 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
339 ok(0, "tm != otm\n");
340 compare_tm(&tm, &otm.otmTextMetrics);
343 tm = otm.otmTextMetrics;
344 if (0) /* these metrics are scaled too, but with rounding errors */
346 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
347 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
349 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
350 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
351 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
352 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
353 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
354 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
356 else
358 ret = GetTextMetricsA(hdc, &tm);
359 ok(ret, "GetTextMetricsA failed\n");
362 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
363 cy = tm.tmHeight / tm_orig->tmHeight;
364 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
365 lfHeight, scale_x, scale_y, cx, cy);
366 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
367 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
368 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
369 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
370 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
372 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
373 if (lf.lfHeight)
375 if (lf.lfWidth)
376 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
378 else
379 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
381 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
383 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
384 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
386 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
388 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);
391 /* Test how GDI scales bitmap font metrics */
392 static void test_bitmap_font(void)
394 static const char test_str[11] = "Test String";
395 HDC hdc;
396 LOGFONTA bitmap_lf;
397 HFONT hfont, old_hfont;
398 TEXTMETRICA tm_orig;
399 SIZE size_orig;
400 INT ret, i, width_orig, height_orig, scale, lfWidth;
402 hdc = CreateCompatibleDC(0);
404 /* "System" has only 1 pixel size defined, otherwise the test breaks */
405 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
406 if (ret)
408 ReleaseDC(0, hdc);
409 trace("no bitmap fonts were found, skipping the test\n");
410 return;
413 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
415 height_orig = bitmap_lf.lfHeight;
416 lfWidth = bitmap_lf.lfWidth;
418 hfont = create_font("bitmap", &bitmap_lf);
419 old_hfont = SelectObject(hdc, hfont);
420 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
421 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
422 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
423 SelectObject(hdc, old_hfont);
424 DeleteObject(hfont);
426 bitmap_lf.lfHeight = 0;
427 bitmap_lf.lfWidth = 4;
428 hfont = create_font("bitmap", &bitmap_lf);
429 old_hfont = SelectObject(hdc, hfont);
430 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
431 SelectObject(hdc, old_hfont);
432 DeleteObject(hfont);
434 bitmap_lf.lfHeight = height_orig;
435 bitmap_lf.lfWidth = lfWidth;
437 /* test fractional scaling */
438 for (i = 1; i <= height_orig * 6; i++)
440 INT nearest_height;
442 bitmap_lf.lfHeight = i;
443 hfont = create_font("fractional", &bitmap_lf);
444 scale = (i + height_orig - 1) / height_orig;
445 nearest_height = scale * height_orig;
446 /* Only jump to the next height if the difference <= 25% original height */
447 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
448 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
449 so we'll not test this particular height. */
450 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
451 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
452 old_hfont = SelectObject(hdc, hfont);
453 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
454 SelectObject(hdc, old_hfont);
455 DeleteObject(hfont);
458 /* test integer scaling 3x2 */
459 bitmap_lf.lfHeight = height_orig * 2;
460 bitmap_lf.lfWidth *= 3;
461 hfont = create_font("3x2", &bitmap_lf);
462 old_hfont = SelectObject(hdc, hfont);
463 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
464 SelectObject(hdc, old_hfont);
465 DeleteObject(hfont);
467 /* test integer scaling 3x3 */
468 bitmap_lf.lfHeight = height_orig * 3;
469 bitmap_lf.lfWidth = 0;
470 hfont = create_font("3x3", &bitmap_lf);
471 old_hfont = SelectObject(hdc, hfont);
472 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
473 SelectObject(hdc, old_hfont);
474 DeleteObject(hfont);
476 DeleteDC(hdc);
479 /* Test how GDI scales outline font metrics */
480 static void test_outline_font(void)
482 static const char test_str[11] = "Test String";
483 HDC hdc, hdc_2;
484 LOGFONTA lf;
485 HFONT hfont, old_hfont, old_hfont_2;
486 OUTLINETEXTMETRICA otm;
487 SIZE size_orig;
488 INT width_orig, height_orig, lfWidth;
489 XFORM xform;
490 GLYPHMETRICS gm;
491 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
492 POINT pt;
493 INT ret;
495 if (!is_truetype_font_installed("Arial"))
497 skip("Arial is not installed\n");
498 return;
501 hdc = CreateCompatibleDC(0);
503 memset(&lf, 0, sizeof(lf));
504 strcpy(lf.lfFaceName, "Arial");
505 lf.lfHeight = 72;
506 hfont = create_font("outline", &lf);
507 old_hfont = SelectObject(hdc, hfont);
508 otm.otmSize = sizeof(otm);
509 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
510 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
511 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
513 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
514 SelectObject(hdc, old_hfont);
515 DeleteObject(hfont);
517 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
518 lf.lfHeight = otm.otmEMSquare;
519 lf.lfHeight = -lf.lfHeight;
520 hfont = create_font("outline", &lf);
521 old_hfont = SelectObject(hdc, hfont);
522 otm.otmSize = sizeof(otm);
523 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
524 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
525 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
526 SelectObject(hdc, old_hfont);
527 DeleteObject(hfont);
529 height_orig = otm.otmTextMetrics.tmHeight;
530 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
532 /* test integer scaling 3x2 */
533 lf.lfHeight = height_orig * 2;
534 lf.lfWidth = lfWidth * 3;
535 hfont = create_font("3x2", &lf);
536 old_hfont = SelectObject(hdc, hfont);
537 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
538 SelectObject(hdc, old_hfont);
539 DeleteObject(hfont);
541 /* test integer scaling 3x3 */
542 lf.lfHeight = height_orig * 3;
543 lf.lfWidth = lfWidth * 3;
544 hfont = create_font("3x3", &lf);
545 old_hfont = SelectObject(hdc, hfont);
546 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
547 SelectObject(hdc, old_hfont);
548 DeleteObject(hfont);
550 /* test integer scaling 1x1 */
551 lf.lfHeight = height_orig * 1;
552 lf.lfWidth = lfWidth * 1;
553 hfont = create_font("1x1", &lf);
554 old_hfont = SelectObject(hdc, hfont);
555 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 SelectObject(hdc, old_hfont);
557 DeleteObject(hfont);
559 /* test integer scaling 1x1 */
560 lf.lfHeight = height_orig;
561 lf.lfWidth = 0;
562 hfont = create_font("1x1", &lf);
563 old_hfont = SelectObject(hdc, hfont);
564 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
566 /* with an identity matrix */
567 memset(&gm, 0, sizeof(gm));
568 SetLastError(0xdeadbeef);
569 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
570 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
571 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
572 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
573 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
574 /* with a custom matrix */
575 memset(&gm, 0, sizeof(gm));
576 SetLastError(0xdeadbeef);
577 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
578 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
580 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
581 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
585 * another DC.
587 hdc_2 = CreateCompatibleDC(0);
588 old_hfont_2 = SelectObject(hdc_2, hfont);
589 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
591 SetMapMode(hdc, MM_ANISOTROPIC);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc, 100, 100, NULL);
601 SetViewportExtEx(hdc, 50, 100, NULL);
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc, 100, 200, NULL);
611 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc, MM_TEXT);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 SelectObject(hdc_2, old_hfont_2);
622 DeleteDC(hdc_2);
624 if (!SetGraphicsMode(hdc, GM_ADVANCED))
626 SelectObject(hdc, old_hfont);
627 DeleteObject(hfont);
628 DeleteDC(hdc);
629 skip("GM_ADVANCED is not supported on this platform\n");
630 return;
633 xform.eM11 = 20.0f;
634 xform.eM12 = 0.0f;
635 xform.eM21 = 0.0f;
636 xform.eM22 = 20.0f;
637 xform.eDx = 0.0f;
638 xform.eDy = 0.0f;
640 SetLastError(0xdeadbeef);
641 ret = SetWorldTransform(hdc, &xform);
642 ok(ret, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
646 /* with an identity matrix */
647 memset(&gm, 0, sizeof(gm));
648 SetLastError(0xdeadbeef);
649 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
650 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
651 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
652 pt.x = width_orig; pt.y = 0;
653 LPtoDP(hdc, &pt, 1);
654 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
655 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
656 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
657 /* with a custom matrix */
658 memset(&gm, 0, sizeof(gm));
659 SetLastError(0xdeadbeef);
660 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
661 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
662 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
663 pt.x = width_orig; pt.y = 0;
664 LPtoDP(hdc, &pt, 1);
665 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
666 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
667 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
669 SetLastError(0xdeadbeef);
670 ret = SetMapMode(hdc, MM_LOMETRIC);
671 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
673 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
675 /* with an identity matrix */
676 memset(&gm, 0, sizeof(gm));
677 SetLastError(0xdeadbeef);
678 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
679 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
680 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
681 pt.x = width_orig; pt.y = 0;
682 LPtoDP(hdc, &pt, 1);
683 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
684 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
685 /* with a custom matrix */
686 memset(&gm, 0, sizeof(gm));
687 SetLastError(0xdeadbeef);
688 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
689 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
690 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
691 pt.x = width_orig; pt.y = 0;
692 LPtoDP(hdc, &pt, 1);
693 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
694 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
696 SetLastError(0xdeadbeef);
697 ret = SetMapMode(hdc, MM_TEXT);
698 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
700 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
702 /* with an identity matrix */
703 memset(&gm, 0, sizeof(gm));
704 SetLastError(0xdeadbeef);
705 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
706 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
708 pt.x = width_orig; pt.y = 0;
709 LPtoDP(hdc, &pt, 1);
710 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
711 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
712 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
713 /* with a custom matrix */
714 memset(&gm, 0, sizeof(gm));
715 SetLastError(0xdeadbeef);
716 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
717 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
718 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
719 pt.x = width_orig; pt.y = 0;
720 LPtoDP(hdc, &pt, 1);
721 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
722 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
723 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
725 SelectObject(hdc, old_hfont);
726 DeleteObject(hfont);
727 DeleteDC(hdc);
730 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
732 LOGFONTA *lf = (LOGFONTA *)lParam;
734 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
736 *lf = *elf;
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL is_CJK(void)
744 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const struct font_data
752 const char face_name[LF_FACESIZE];
753 int weight, height, ascent, descent, int_leading, ext_leading;
754 int ave_char_width, max_char_width, dpi;
755 BYTE first_char, last_char, def_char, break_char;
756 DWORD ansi_bitfield;
757 WORD skip_lang_id;
758 int scaled_height;
759 } fd[] =
761 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
762 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
763 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
764 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
765 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
766 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
767 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
768 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
769 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 16 },
770 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
772 { "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 },
773 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
774 { "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 },
775 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
776 { "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 },
777 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
778 { "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 },
779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
780 { "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 },
781 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
783 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
784 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
785 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
786 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
787 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
788 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
789 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
790 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
791 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
792 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
793 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
794 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
795 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
796 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
797 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
798 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
800 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
801 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
802 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
803 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
804 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
805 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
806 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
807 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
808 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
809 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
813 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
814 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
815 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
816 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
817 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
818 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
819 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
820 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
822 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
823 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
824 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
826 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
827 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
828 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
831 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
833 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
834 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
835 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
836 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
837 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
838 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
839 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
840 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
841 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
843 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
844 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
845 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
847 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
848 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
849 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
851 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
852 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
853 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
855 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
856 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
858 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
859 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
860 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
861 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
862 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
863 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
864 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
865 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
866 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
867 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
868 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
869 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
870 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
871 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
872 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
873 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
874 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
875 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
876 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
877 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
878 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
880 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
881 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
882 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
883 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
884 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
885 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
886 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
887 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
888 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
889 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
890 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
891 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
893 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
894 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
895 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
897 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
899 /* FIXME: add "Terminal" */
901 static const int font_log_pixels[] = { 96, 120 };
902 HDC hdc;
903 LOGFONTA lf;
904 HFONT hfont, old_hfont;
905 TEXTMETRICA tm;
906 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
907 char face_name[LF_FACESIZE];
908 CHARSETINFO csi;
910 trace("system language id %04x\n", system_lang_id);
912 expected_cs = GetACP();
913 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
915 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
916 return;
918 expected_cs = csi.ciCharset;
919 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
921 hdc = CreateCompatibleDC(0);
922 assert(hdc);
924 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
925 GetDeviceCaps(hdc, LOGPIXELSY));
927 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
928 diff = 32768;
929 font_res = 0;
930 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
932 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
933 if (new_diff < diff)
935 diff = new_diff;
936 font_res = font_log_pixels[i];
939 trace("best font resolution is %d\n", font_res);
941 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
943 int bit, height;
945 memset(&lf, 0, sizeof(lf));
947 height = fd[i].height & ~FH_SCALE;
948 lf.lfHeight = height;
949 strcpy(lf.lfFaceName, fd[i].face_name);
951 for(bit = 0; bit < 32; bit++)
953 GLYPHMETRICS gm;
954 DWORD fs[2];
955 BOOL bRet;
957 fs[0] = 1L << bit;
958 fs[1] = 0;
959 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
960 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
962 lf.lfCharSet = csi.ciCharset;
963 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
964 if (fd[i].height & FH_SCALE)
965 ok(ret, "scaled font height %d should not be enumerated\n", height);
966 else
968 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
970 if (ret) /* FIXME: Remove once Wine is fixed */
971 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
972 else
973 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
976 if (ret && !(fd[i].height & FH_SCALE))
977 continue;
979 hfont = create_font(lf.lfFaceName, &lf);
980 old_hfont = SelectObject(hdc, hfont);
982 SetLastError(0xdeadbeef);
983 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
984 ok(ret, "GetTextFace error %u\n", GetLastError());
986 if (strcmp(face_name, fd[i].face_name) != 0)
988 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
989 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
990 SelectObject(hdc, old_hfont);
991 DeleteObject(hfont);
992 continue;
995 memset(&gm, 0, sizeof(gm));
996 SetLastError(0xdeadbeef);
997 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
998 todo_wine {
999 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1000 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1003 bRet = GetTextMetricsA(hdc, &tm);
1004 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1006 SetLastError(0xdeadbeef);
1007 ret = GetTextCharset(hdc);
1008 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1009 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1010 else
1011 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1013 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1014 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1016 if(fd[i].dpi == tm.tmDigitizedAspectX)
1018 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1019 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
1021 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1022 if (fd[i].height & FH_SCALE)
1023 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);
1024 else
1025 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);
1026 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1027 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1028 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);
1029 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);
1030 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);
1031 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1032 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1033 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1034 make default char test fail */
1035 if (tm.tmCharSet == lf.lfCharSet)
1036 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1037 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1038 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);
1040 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1041 that make the max width bigger */
1042 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1043 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);
1045 else
1046 skip("Skipping font metrics test for system langid 0x%x\n",
1047 system_lang_id);
1049 SelectObject(hdc, old_hfont);
1050 DeleteObject(hfont);
1054 DeleteDC(hdc);
1057 static void test_GdiGetCharDimensions(void)
1059 HDC hdc;
1060 TEXTMETRICW tm;
1061 LONG ret;
1062 SIZE size;
1063 LONG avgwidth, height;
1064 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1066 if (!pGdiGetCharDimensions)
1068 win_skip("GdiGetCharDimensions not available on this platform\n");
1069 return;
1072 hdc = CreateCompatibleDC(NULL);
1074 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1075 avgwidth = ((size.cx / 26) + 1) / 2;
1077 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1078 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1079 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1081 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1082 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1084 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1085 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1087 height = 0;
1088 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1089 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1090 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1092 DeleteDC(hdc);
1095 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1096 const TEXTMETRICA *lpntme,
1097 DWORD FontType, LPARAM lParam)
1099 if (FontType & TRUETYPE_FONTTYPE)
1101 HFONT hfont;
1103 hfont = CreateFontIndirectA(lpelfe);
1104 if (hfont)
1106 *(HFONT *)lParam = hfont;
1107 return 0;
1111 return 1;
1114 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1116 ABC abc[1];
1117 ABCFLOAT abcf[1];
1118 BOOL ret = FALSE;
1120 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1121 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1122 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1123 if (todo) todo_wine ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1124 else ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1125 if (todo) todo_wine ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1126 else ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1128 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1129 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1130 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1131 if (todo) todo_wine ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1132 else ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1133 if (todo) todo_wine ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1134 else ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's should be unchanged\n", description);
1136 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1137 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1138 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1139 if (todo) todo_wine ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1140 else ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's should be unchanged\n", description);
1141 if (todo) todo_wine ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1142 else ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1145 static void test_GetCharABCWidths(void)
1147 static const WCHAR str[] = {'i',0};
1148 BOOL ret;
1149 HDC hdc;
1150 LOGFONTA lf;
1151 HFONT hfont;
1152 ABC abc[1];
1153 ABC abcw[1];
1154 ABCFLOAT abcf[1];
1155 WORD glyphs[1];
1156 DWORD nb;
1157 HWND hwnd;
1158 static const struct
1160 UINT first;
1161 UINT last;
1162 } range[] =
1164 {0xff, 0xff},
1165 {0x100, 0x100},
1166 {0xff, 0x100},
1167 {0x1ff, 0xff00},
1168 {0xffff, 0xffff},
1169 {0x10000, 0x10000},
1170 {0xffff, 0x10000},
1171 {0xffffff, 0xffffff},
1172 {0x1000000, 0x1000000},
1173 {0xffffff, 0x1000000},
1174 {0xffffffff, 0xffffffff},
1175 {0x00, 0xff}
1177 static const struct
1179 UINT cs;
1180 UINT a;
1181 UINT w;
1182 BOOL r[sizeof range / sizeof range[0]];
1183 } c[] =
1185 {ANSI_CHARSET, 0x30, 0x30,
1186 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1187 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1188 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1189 {HANGEUL_CHARSET, 0x8141, 0xac02,
1190 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1191 {GB2312_CHARSET, 0x8141, 0x4e04,
1192 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1193 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1194 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1196 UINT i;
1198 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1200 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1201 return;
1204 memset(&lf, 0, sizeof(lf));
1205 strcpy(lf.lfFaceName, "System");
1206 lf.lfHeight = 20;
1208 hfont = CreateFontIndirectA(&lf);
1209 hdc = GetDC(0);
1210 hfont = SelectObject(hdc, hfont);
1212 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1213 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1215 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1216 ok(!ret, "GetCharABCWidthsI should have failed\n");
1218 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1219 ok(!ret, "GetCharABCWidthsI should have failed\n");
1221 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1222 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1224 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1225 ok(!ret, "GetCharABCWidthsW should have failed\n");
1227 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1228 ok(!ret, "GetCharABCWidthsW should have failed\n");
1230 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1231 ok(!ret, "GetCharABCWidthsW should have failed\n");
1233 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1234 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1236 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1237 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1239 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1240 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1242 hfont = SelectObject(hdc, hfont);
1243 DeleteObject(hfont);
1245 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1247 ABC a[2], w[2];
1248 ABC full[256];
1249 UINT code = 0x41, j;
1251 lf.lfFaceName[0] = '\0';
1252 lf.lfCharSet = c[i].cs;
1253 lf.lfPitchAndFamily = 0;
1254 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1256 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1257 continue;
1260 memset(a, 0, sizeof a);
1261 memset(w, 0, sizeof w);
1262 hfont = SelectObject(hdc, hfont);
1263 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1264 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1265 memcmp(a, w, sizeof a) == 0,
1266 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1268 memset(a, 0xbb, sizeof a);
1269 ret = pGetCharABCWidthsA(hdc, code, code, a);
1270 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1271 memset(full, 0xcc, sizeof full);
1272 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1273 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1274 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1275 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1277 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1279 memset(full, 0xdd, sizeof full);
1280 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1281 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1282 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1283 if (ret)
1285 UINT last = range[j].last - range[j].first;
1286 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1287 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1288 "GetCharABCWidthsA %x should match. codepage = %u\n",
1289 range[j].last, c[i].cs);
1293 hfont = SelectObject(hdc, hfont);
1294 DeleteObject(hfont);
1297 memset(&lf, 0, sizeof(lf));
1298 strcpy(lf.lfFaceName, "Tahoma");
1299 lf.lfHeight = 200;
1300 hfont = CreateFontIndirectA(&lf);
1302 /* test empty glyph's metrics */
1303 hfont = SelectObject(hdc, hfont);
1304 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1305 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1306 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1307 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1308 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1309 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1311 /* 1) prepare unrotated font metrics */
1312 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1313 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1314 DeleteObject(SelectObject(hdc, hfont));
1316 /* 2) get rotated font metrics */
1317 lf.lfEscapement = lf.lfOrientation = 900;
1318 hfont = CreateFontIndirectA(&lf);
1319 hfont = SelectObject(hdc, hfont);
1320 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1321 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1323 /* 3) compare ABC results */
1324 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1325 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1326 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1327 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1328 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1329 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1331 DeleteObject(SelectObject(hdc, hfont));
1332 ReleaseDC(NULL, hdc);
1334 trace("ABC sign test for a variety of transforms:\n");
1335 memset(&lf, 0, sizeof(lf));
1336 strcpy(lf.lfFaceName, "Tahoma");
1337 lf.lfHeight = 20;
1338 hfont = CreateFontIndirectA(&lf);
1339 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1340 0, 0, 0, NULL);
1341 hdc = GetDC(hwnd);
1342 SetMapMode(hdc, MM_ANISOTROPIC);
1343 SelectObject(hdc, hfont);
1345 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1346 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1348 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1349 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1350 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1351 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1352 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1353 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1355 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1356 SetWindowExtEx(hdc, -1, -1, NULL);
1357 SetGraphicsMode(hdc, GM_COMPATIBLE);
1358 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1359 SetGraphicsMode(hdc, GM_ADVANCED);
1360 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1361 SetWindowExtEx(hdc, 1, 1, NULL);
1362 SetGraphicsMode(hdc, GM_COMPATIBLE);
1363 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1364 SetGraphicsMode(hdc, GM_ADVANCED);
1365 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1367 ReleaseDC(hwnd, hdc);
1368 DestroyWindow(hwnd);
1370 trace("RTL layout\n");
1371 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1372 0, 0, 0, NULL);
1373 hdc = GetDC(hwnd);
1374 SetMapMode(hdc, MM_ANISOTROPIC);
1375 SelectObject(hdc, hfont);
1377 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1378 SetWindowExtEx(hdc, -1, -1, NULL);
1379 SetGraphicsMode(hdc, GM_COMPATIBLE);
1380 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1381 SetGraphicsMode(hdc, GM_ADVANCED);
1382 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1383 SetWindowExtEx(hdc, 1, 1, NULL);
1384 SetGraphicsMode(hdc, GM_COMPATIBLE);
1385 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1386 SetGraphicsMode(hdc, GM_ADVANCED);
1387 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1389 ReleaseDC(hwnd, hdc);
1390 DestroyWindow(hwnd);
1391 DeleteObject(hfont);
1394 static void test_text_extents(void)
1396 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1397 LPINT extents;
1398 INT i, len, fit1, fit2, extents2[3];
1399 LOGFONTA lf;
1400 TEXTMETRICA tm;
1401 HDC hdc;
1402 HFONT hfont;
1403 SIZE sz;
1404 SIZE sz1, sz2;
1405 BOOL ret;
1407 memset(&lf, 0, sizeof(lf));
1408 strcpy(lf.lfFaceName, "Arial");
1409 lf.lfHeight = 20;
1411 hfont = CreateFontIndirectA(&lf);
1412 hdc = GetDC(0);
1413 hfont = SelectObject(hdc, hfont);
1414 GetTextMetricsA(hdc, &tm);
1415 GetTextExtentPointA(hdc, "o", 1, &sz);
1416 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1418 SetLastError(0xdeadbeef);
1419 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1420 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1422 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1423 hfont = SelectObject(hdc, hfont);
1424 DeleteObject(hfont);
1425 ReleaseDC(0, hdc);
1426 return;
1429 len = lstrlenW(wt);
1430 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1431 extents[0] = 1; /* So that the increasing sequence test will fail
1432 if the extents array is untouched. */
1433 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1434 GetTextExtentPointW(hdc, wt, len, &sz2);
1435 ok(sz1.cy == sz2.cy,
1436 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1437 /* Because of the '\n' in the string GetTextExtentExPoint and
1438 GetTextExtentPoint return different widths under Win2k, but
1439 under WinXP they return the same width. So we don't test that
1440 here. */
1442 for (i = 1; i < len; ++i)
1443 ok(extents[i-1] <= extents[i],
1444 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1446 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1447 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1448 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1449 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1450 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1451 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1452 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1453 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1455 ok(extents[0] == extents[2] && extents[1] == extents[3],
1456 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1457 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1458 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1459 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1461 /* extents functions fail with -ve counts (the interesting case being -1) */
1462 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1463 ok(ret == FALSE, "got %d\n", ret);
1464 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1465 ok(ret == FALSE, "got %d\n", ret);
1466 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1467 ok(ret == FALSE, "got %d\n", ret);
1469 /* max_extent = 0 succeeds and returns zero */
1470 fit1 = fit2 = -215;
1471 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1472 ok(ret == TRUE ||
1473 broken(ret == FALSE), /* NT4, 2k */
1474 "got %d\n", ret);
1475 ok(fit1 == 0 ||
1476 broken(fit1 == -215), /* NT4, 2k */
1477 "fit = %d\n", fit1);
1478 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1479 ok(ret == TRUE, "got %d\n", ret);
1480 ok(fit2 == 0, "fit = %d\n", fit2);
1482 /* max_extent = -1 is interpreted as a very large width that will
1483 * definitely fit our three characters */
1484 fit1 = fit2 = -215;
1485 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1486 ok(ret == TRUE, "got %d\n", ret);
1487 ok(fit1 == 3, "fit = %d\n", fit1);
1488 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1489 ok(ret == TRUE, "got %d\n", ret);
1490 ok(fit2 == 3, "fit = %d\n", fit2);
1492 /* max_extent = -2 is interpreted similarly, but the Ansi version
1493 * rejects it while the Unicode one accepts it */
1494 fit1 = fit2 = -215;
1495 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1496 ok(ret == FALSE, "got %d\n", ret);
1497 ok(fit1 == -215, "fit = %d\n", fit1);
1498 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1499 ok(ret == TRUE, "got %d\n", ret);
1500 ok(fit2 == 3, "fit = %d\n", fit2);
1502 hfont = SelectObject(hdc, hfont);
1503 DeleteObject(hfont);
1505 /* non-MM_TEXT mapping mode */
1506 lf.lfHeight = 2000;
1507 hfont = CreateFontIndirectA(&lf);
1508 hfont = SelectObject(hdc, hfont);
1510 SetMapMode( hdc, MM_HIMETRIC );
1511 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1512 ok(ret, "got %d\n", ret);
1513 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1515 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1516 ok(ret, "got %d\n", ret);
1517 ok(fit1 == 2, "got %d\n", fit1);
1518 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1519 for(i = 0; i < 2; i++)
1520 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1522 hfont = SelectObject(hdc, hfont);
1523 DeleteObject(hfont);
1524 HeapFree(GetProcessHeap(), 0, extents);
1525 ReleaseDC(NULL, hdc);
1528 static void test_GetGlyphIndices(void)
1530 HDC hdc;
1531 HFONT hfont;
1532 DWORD charcount;
1533 LOGFONTA lf;
1534 DWORD flags = 0;
1535 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1536 WORD glyphs[(sizeof(testtext)/2)-1];
1537 TEXTMETRICA textm;
1538 HFONT hOldFont;
1540 if (!pGetGlyphIndicesW) {
1541 win_skip("GetGlyphIndicesW not available on platform\n");
1542 return;
1545 hdc = GetDC(0);
1547 memset(&lf, 0, sizeof(lf));
1548 strcpy(lf.lfFaceName, "System");
1549 lf.lfHeight = 16;
1550 lf.lfCharSet = ANSI_CHARSET;
1552 hfont = CreateFontIndirectA(&lf);
1553 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1554 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1555 if (textm.tmCharSet == ANSI_CHARSET)
1557 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1558 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1559 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1560 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1561 flags = 0;
1562 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1563 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1564 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1565 textm.tmDefaultChar, glyphs[4]);
1567 else
1568 /* FIXME: Write tests for non-ANSI charsets. */
1569 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1571 if(!is_font_installed("Tahoma"))
1573 skip("Tahoma is not installed so skipping this test\n");
1574 return;
1576 memset(&lf, 0, sizeof(lf));
1577 strcpy(lf.lfFaceName, "Tahoma");
1578 lf.lfHeight = 20;
1580 hfont = CreateFontIndirectA(&lf);
1581 hOldFont = SelectObject(hdc, hfont);
1582 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1583 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1584 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1585 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1586 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1587 flags = 0;
1588 testtext[0] = textm.tmDefaultChar;
1589 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1590 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1591 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1592 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1593 DeleteObject(SelectObject(hdc, hOldFont));
1596 static void test_GetKerningPairs(void)
1598 static const struct kerning_data
1600 const char face_name[LF_FACESIZE];
1601 LONG height;
1602 /* some interesting fields from OUTLINETEXTMETRIC */
1603 LONG tmHeight, tmAscent, tmDescent;
1604 UINT otmEMSquare;
1605 INT otmAscent;
1606 INT otmDescent;
1607 UINT otmLineGap;
1608 UINT otmsCapEmHeight;
1609 UINT otmsXHeight;
1610 INT otmMacAscent;
1611 INT otmMacDescent;
1612 UINT otmMacLineGap;
1613 UINT otmusMinimumPPEM;
1614 /* small subset of kerning pairs to test */
1615 DWORD total_kern_pairs;
1616 const KERNINGPAIR kern_pair[26];
1617 } kd[] =
1619 {"Arial", 12, 12, 9, 3,
1620 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1623 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1624 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1625 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1626 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1627 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1628 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1629 {933,970,+1},{933,972,-1}
1632 {"Arial", -34, 39, 32, 7,
1633 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1636 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1637 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1638 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1639 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1640 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1641 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1642 {933,970,+2},{933,972,-3}
1645 { "Arial", 120, 120, 97, 23,
1646 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1649 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1650 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1651 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1652 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1653 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1654 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1655 {933,970,+6},{933,972,-10}
1658 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1659 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1660 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1663 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1664 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1665 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1666 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1667 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1668 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1669 {933,970,+54},{933,972,-83}
1672 #endif
1674 LOGFONTA lf;
1675 HFONT hfont, hfont_old;
1676 KERNINGPAIR *kern_pair;
1677 HDC hdc;
1678 DWORD total_kern_pairs, ret, i, n, matches;
1680 hdc = GetDC(0);
1682 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1683 * which may render this test unusable, so we're trying to avoid that.
1685 SetLastError(0xdeadbeef);
1686 GetKerningPairsW(hdc, 0, NULL);
1687 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1689 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1690 ReleaseDC(0, hdc);
1691 return;
1694 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1696 OUTLINETEXTMETRICW otm;
1697 UINT uiRet;
1699 if (!is_font_installed(kd[i].face_name))
1701 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1702 continue;
1705 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1707 memset(&lf, 0, sizeof(lf));
1708 strcpy(lf.lfFaceName, kd[i].face_name);
1709 lf.lfHeight = kd[i].height;
1710 hfont = CreateFontIndirectA(&lf);
1711 assert(hfont != 0);
1713 hfont_old = SelectObject(hdc, hfont);
1715 SetLastError(0xdeadbeef);
1716 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1717 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1718 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1720 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1721 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1722 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1723 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1724 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1725 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1727 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1728 kd[i].otmEMSquare, otm.otmEMSquare);
1729 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1730 kd[i].otmAscent, otm.otmAscent);
1731 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1732 kd[i].otmDescent, otm.otmDescent);
1733 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1734 kd[i].otmLineGap, otm.otmLineGap);
1735 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1736 kd[i].otmMacDescent, otm.otmMacDescent);
1737 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1738 kd[i].otmMacAscent, otm.otmMacAscent);
1739 todo_wine {
1740 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1741 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1742 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1743 kd[i].otmsXHeight, otm.otmsXHeight);
1744 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1745 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1746 kd[i].otmMacLineGap, otm.otmMacLineGap);
1747 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1748 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1751 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1752 trace("total_kern_pairs %u\n", total_kern_pairs);
1753 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1755 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1756 * passes on XP.
1758 SetLastError(0xdeadbeef);
1759 ret = GetKerningPairsW(hdc, 0, kern_pair);
1760 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1761 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1762 ok(ret == 0, "got %u, expected 0\n", ret);
1764 ret = GetKerningPairsW(hdc, 100, NULL);
1765 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1767 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1768 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1770 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1771 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1773 matches = 0;
1775 for (n = 0; n < ret; n++)
1777 DWORD j;
1778 /* Disabled to limit console spam */
1779 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1780 trace("{'%c','%c',%d},\n",
1781 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1782 for (j = 0; j < kd[i].total_kern_pairs; j++)
1784 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1785 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1787 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1788 "pair %d:%d got %d, expected %d\n",
1789 kern_pair[n].wFirst, kern_pair[n].wSecond,
1790 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1791 matches++;
1796 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1797 matches, kd[i].total_kern_pairs);
1799 HeapFree(GetProcessHeap(), 0, kern_pair);
1801 SelectObject(hdc, hfont_old);
1802 DeleteObject(hfont);
1805 ReleaseDC(0, hdc);
1808 struct font_data
1810 const char face_name[LF_FACESIZE];
1811 int requested_height;
1812 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1813 BOOL exact;
1816 static void test_height( HDC hdc, const struct font_data *fd )
1818 LOGFONTA lf;
1819 HFONT hfont, old_hfont;
1820 TEXTMETRICA tm;
1821 INT ret, i;
1823 for (i = 0; fd[i].face_name[0]; i++)
1825 if (!is_truetype_font_installed(fd[i].face_name))
1827 skip("%s is not installed\n", fd[i].face_name);
1828 continue;
1831 memset(&lf, 0, sizeof(lf));
1832 lf.lfHeight = fd[i].requested_height;
1833 lf.lfWeight = fd[i].weight;
1834 strcpy(lf.lfFaceName, fd[i].face_name);
1836 hfont = CreateFontIndirectA(&lf);
1837 assert(hfont);
1839 old_hfont = SelectObject(hdc, hfont);
1840 ret = GetTextMetricsA(hdc, &tm);
1841 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1842 if(fd[i].dpi == tm.tmDigitizedAspectX)
1844 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);
1845 ok(match_off_by_1(tm.tmHeight, fd[i].height, fd[i].exact), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1846 ok(match_off_by_1(tm.tmAscent, fd[i].ascent, fd[i].exact), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1847 ok(match_off_by_1(tm.tmDescent, fd[i].descent, fd[i].exact), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1848 ok(match_off_by_1(tm.tmInternalLeading, fd[i].int_leading, fd[i].exact), "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1849 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);
1852 SelectObject(hdc, old_hfont);
1853 /* force GDI to use new font, otherwise Windows leaks the font reference */
1854 GetTextMetricsA(hdc, &tm);
1855 DeleteObject(hfont);
1859 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1861 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1862 DWORD *table = (DWORD *)ttf + 3;
1864 for (i = 0; i < num_tables; i++)
1866 if (table[0] == tag)
1867 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1868 table += 4;
1870 return NULL;
1873 static void test_height_selection_vdmx( HDC hdc )
1875 static const struct font_data charset_0[] = /* doesn't use VDMX */
1877 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1878 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1879 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1880 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1881 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1882 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1883 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1884 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1885 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1886 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1887 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1888 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1889 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1890 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1891 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1892 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1893 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1894 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1895 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1896 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1897 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1898 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1899 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1900 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1901 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1902 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1903 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1904 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1905 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1906 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1907 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1908 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1909 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1910 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1911 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1912 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1913 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1914 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1915 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1916 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1917 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1918 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1919 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1920 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1921 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1922 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1923 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1924 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1925 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1926 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1927 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1928 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1929 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1932 static const struct font_data charset_1[] = /* Uses VDMX */
1934 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1935 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1936 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1937 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1938 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1939 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1940 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1941 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1942 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1943 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1944 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1945 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1946 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1947 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1948 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1949 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1950 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1951 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1952 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1953 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1954 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1955 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1956 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1957 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
1958 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
1959 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
1960 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1961 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1962 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1963 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1964 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1965 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1966 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1967 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1968 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1969 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1970 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1971 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1972 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1973 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1974 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1975 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
1976 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
1977 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
1978 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
1979 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
1980 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
1981 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
1982 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
1983 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
1984 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
1985 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
1986 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1989 static const struct vdmx_data
1991 WORD version;
1992 BYTE bCharSet;
1993 const struct font_data *fd;
1994 } data[] =
1996 { 0, 0, charset_0 },
1997 { 0, 1, charset_1 },
1998 { 1, 0, charset_0 },
1999 { 1, 1, charset_1 }
2001 int i;
2002 DWORD size, num;
2003 WORD *vdmx_header;
2004 BYTE *ratio_rec;
2005 char ttf_name[MAX_PATH];
2006 void *res, *copy;
2007 BOOL ret;
2009 if (!pAddFontResourceExA)
2011 win_skip("AddFontResourceExA unavailable\n");
2012 return;
2015 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2017 res = get_res_data( "wine_vdmx.ttf", &size );
2019 copy = HeapAlloc( GetProcessHeap(), 0, size );
2020 memcpy( copy, res, size );
2021 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2022 vdmx_header[0] = GET_BE_WORD( data[i].version );
2023 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2024 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2025 ratio_rec = (BYTE *)&vdmx_header[3];
2026 ratio_rec[0] = data[i].bCharSet;
2028 write_tmp_file( copy, &size, ttf_name );
2029 HeapFree( GetProcessHeap(), 0, copy );
2031 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2032 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2033 if (!num) win_skip("Unable to add ttf font resource\n");
2034 else
2036 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2037 test_height( hdc, data[i].fd );
2038 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2040 ret = DeleteFileA( ttf_name );
2041 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2042 "DeleteFile error %d\n", GetLastError());
2046 static void test_height_selection(void)
2048 static const struct font_data tahoma[] =
2050 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2051 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2052 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2053 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2054 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2055 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2056 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2057 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2058 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2059 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2060 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2062 HDC hdc = CreateCompatibleDC(0);
2063 assert(hdc);
2065 test_height( hdc, tahoma );
2066 test_height_selection_vdmx( hdc );
2068 DeleteDC(hdc);
2071 static void test_GetOutlineTextMetrics(void)
2073 OUTLINETEXTMETRICA *otm;
2074 LOGFONTA lf;
2075 HFONT hfont, hfont_old;
2076 HDC hdc;
2077 DWORD ret, otm_size;
2078 LPSTR unset_ptr;
2080 if (!is_font_installed("Arial"))
2082 skip("Arial is not installed\n");
2083 return;
2086 hdc = GetDC(0);
2088 memset(&lf, 0, sizeof(lf));
2089 strcpy(lf.lfFaceName, "Arial");
2090 lf.lfHeight = -13;
2091 lf.lfWeight = FW_NORMAL;
2092 lf.lfPitchAndFamily = DEFAULT_PITCH;
2093 lf.lfQuality = PROOF_QUALITY;
2094 hfont = CreateFontIndirectA(&lf);
2095 assert(hfont != 0);
2097 hfont_old = SelectObject(hdc, hfont);
2098 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2099 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2101 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2103 memset(otm, 0xAA, otm_size);
2104 SetLastError(0xdeadbeef);
2105 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2106 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2107 ok(ret == 1 /* Win9x */ ||
2108 ret == otm->otmSize /* XP*/,
2109 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2110 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2112 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2113 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2114 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2115 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2118 memset(otm, 0xAA, otm_size);
2119 SetLastError(0xdeadbeef);
2120 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2121 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2122 ok(ret == 1 /* Win9x */ ||
2123 ret == otm->otmSize /* XP*/,
2124 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2125 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2127 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2128 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2129 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2130 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2133 /* ask about truncated data */
2134 memset(otm, 0xAA, otm_size);
2135 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2136 SetLastError(0xdeadbeef);
2137 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2138 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2139 ok(ret == 1 /* Win9x */ ||
2140 ret == otm->otmSize /* XP*/,
2141 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2142 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2144 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2145 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2146 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2148 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2150 HeapFree(GetProcessHeap(), 0, otm);
2152 SelectObject(hdc, hfont_old);
2153 DeleteObject(hfont);
2155 ReleaseDC(0, hdc);
2158 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2160 INT y,
2161 breakCount,
2162 areaWidth = clientArea->right - clientArea->left,
2163 nErrors = 0, e;
2164 const char *pFirstChar, *pLastChar;
2165 SIZE size;
2166 TEXTMETRICA tm;
2167 struct err
2169 const char *start;
2170 int len;
2171 int GetTextExtentExPointWWidth;
2172 } error[20];
2174 GetTextMetricsA(hdc, &tm);
2175 y = clientArea->top;
2176 do {
2177 breakCount = 0;
2178 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2179 pFirstChar = str;
2181 do {
2182 pLastChar = str;
2184 /* if not at the end of the string, ... */
2185 if (*str == '\0') break;
2186 /* ... add the next word to the current extent */
2187 while (*str != '\0' && *str++ != tm.tmBreakChar);
2188 breakCount++;
2189 SetTextJustification(hdc, 0, 0);
2190 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2191 } while ((int) size.cx < areaWidth);
2193 /* ignore trailing break chars */
2194 breakCount--;
2195 while (*(pLastChar - 1) == tm.tmBreakChar)
2197 pLastChar--;
2198 breakCount--;
2201 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2203 SetTextJustification(hdc, 0, 0);
2204 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2206 /* do not justify the last extent */
2207 if (*str != '\0' && breakCount > 0)
2209 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2210 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2211 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2213 error[nErrors].start = pFirstChar;
2214 error[nErrors].len = pLastChar - pFirstChar;
2215 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2216 nErrors++;
2220 y += size.cy;
2221 str = pLastChar;
2222 } while (*str && y < clientArea->bottom);
2224 for (e = 0; e < nErrors; e++)
2226 /* The width returned by GetTextExtentPoint32() is exactly the same
2227 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2228 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2229 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2230 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2234 static void test_SetTextJustification(void)
2236 HDC hdc;
2237 RECT clientArea;
2238 LOGFONTA lf;
2239 HFONT hfont;
2240 HWND hwnd;
2241 SIZE size, expect;
2242 int i;
2243 WORD indices[2];
2244 static const char testText[] =
2245 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2246 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2247 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2248 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2249 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2250 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2251 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2253 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2254 GetClientRect( hwnd, &clientArea );
2255 hdc = GetDC( hwnd );
2257 if (!is_font_installed("Times New Roman"))
2259 skip("Times New Roman is not installed\n");
2260 return;
2263 memset(&lf, 0, sizeof lf);
2264 lf.lfCharSet = ANSI_CHARSET;
2265 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2266 lf.lfWeight = FW_DONTCARE;
2267 lf.lfHeight = 20;
2268 lf.lfQuality = DEFAULT_QUALITY;
2269 lstrcpyA(lf.lfFaceName, "Times New Roman");
2270 hfont = create_font("Times New Roman", &lf);
2271 SelectObject(hdc, hfont);
2273 testJustification(hdc, testText, &clientArea);
2275 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2276 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2278 SetTextJustification(hdc, 0, 0);
2279 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2280 GetTextExtentPoint32A(hdc, " ", 3, &size);
2281 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2282 SetTextJustification(hdc, 4, 1);
2283 GetTextExtentPoint32A(hdc, " ", 1, &size);
2284 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2285 SetTextJustification(hdc, 9, 2);
2286 GetTextExtentPoint32A(hdc, " ", 2, &size);
2287 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2288 SetTextJustification(hdc, 7, 3);
2289 GetTextExtentPoint32A(hdc, " ", 3, &size);
2290 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2291 SetTextJustification(hdc, 7, 3);
2292 SetTextCharacterExtra(hdc, 2 );
2293 GetTextExtentPoint32A(hdc, " ", 3, &size);
2294 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2295 SetTextJustification(hdc, 0, 0);
2296 SetTextCharacterExtra(hdc, 0);
2297 size.cx = size.cy = 1234;
2298 GetTextExtentPoint32A(hdc, " ", 0, &size);
2299 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2300 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2301 SetTextJustification(hdc, 5, 1);
2302 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2303 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2304 SetTextJustification(hdc, 0, 0);
2306 SetMapMode( hdc, MM_ANISOTROPIC );
2307 SetWindowExtEx( hdc, 2, 2, NULL );
2308 GetClientRect( hwnd, &clientArea );
2309 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2310 testJustification(hdc, testText, &clientArea);
2312 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2313 for (i = 0; i < 10; i++)
2315 SetTextCharacterExtra(hdc, i);
2316 GetTextExtentPoint32A(hdc, "A", 1, &size);
2317 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2319 SetTextCharacterExtra(hdc, 0);
2320 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2321 for (i = 0; i < 10; i++)
2323 SetTextCharacterExtra(hdc, i);
2324 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2325 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2327 SetTextCharacterExtra(hdc, 0);
2329 SetViewportExtEx( hdc, 3, 3, NULL );
2330 GetClientRect( hwnd, &clientArea );
2331 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2332 testJustification(hdc, testText, &clientArea);
2334 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2335 for (i = 0; i < 10; i++)
2337 SetTextCharacterExtra(hdc, i);
2338 GetTextExtentPoint32A(hdc, "A", 1, &size);
2339 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2342 done:
2343 DeleteObject(hfont);
2344 ReleaseDC(hwnd, hdc);
2345 DestroyWindow(hwnd);
2348 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2350 HDC hdc;
2351 LOGFONTA lf;
2352 HFONT hfont, hfont_old;
2353 CHARSETINFO csi;
2354 FONTSIGNATURE fs;
2355 INT cs;
2356 DWORD i, ret;
2357 char name[64];
2359 assert(count <= 128);
2361 memset(&lf, 0, sizeof(lf));
2363 lf.lfCharSet = charset;
2364 lf.lfHeight = 10;
2365 lstrcpyA(lf.lfFaceName, "Arial");
2366 SetLastError(0xdeadbeef);
2367 hfont = CreateFontIndirectA(&lf);
2368 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2370 hdc = GetDC(0);
2371 hfont_old = SelectObject(hdc, hfont);
2373 cs = GetTextCharsetInfo(hdc, &fs, 0);
2374 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2376 SetLastError(0xdeadbeef);
2377 ret = GetTextFaceA(hdc, sizeof(name), name);
2378 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2380 if (charset == SYMBOL_CHARSET)
2382 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2383 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
2385 else
2387 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2388 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2391 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2393 trace("Can't find codepage for charset %d\n", cs);
2394 ReleaseDC(0, hdc);
2395 return FALSE;
2397 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2399 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2401 skip("Font code page %d, looking for code page %d\n",
2402 pGdiGetCodePage(hdc), code_page);
2403 ReleaseDC(0, hdc);
2404 return FALSE;
2407 if (unicode)
2409 char ansi_buf[128];
2410 WCHAR unicode_buf[128];
2412 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2414 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2416 SetLastError(0xdeadbeef);
2417 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2418 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2419 count, ret, GetLastError());
2421 else
2423 char ansi_buf[128];
2425 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2427 SetLastError(0xdeadbeef);
2428 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2429 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2430 count, ret, GetLastError());
2433 SelectObject(hdc, hfont_old);
2434 DeleteObject(hfont);
2436 ReleaseDC(0, hdc);
2438 return TRUE;
2441 static void test_font_charset(void)
2443 static struct charset_data
2445 INT charset;
2446 UINT code_page;
2447 WORD font_idxA[128], font_idxW[128];
2448 } cd[] =
2450 { ANSI_CHARSET, 1252 },
2451 { RUSSIAN_CHARSET, 1251 },
2452 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2454 int i;
2456 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2458 win_skip("Skipping the font charset test on a Win9x platform\n");
2459 return;
2462 if (!is_font_installed("Arial"))
2464 skip("Arial is not installed\n");
2465 return;
2468 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2470 if (cd[i].charset == SYMBOL_CHARSET)
2472 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2474 skip("Symbol or Wingdings is not installed\n");
2475 break;
2478 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2479 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2480 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2483 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2484 if (i > 2)
2486 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2487 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2489 else
2490 skip("Symbol or Wingdings is not installed\n");
2493 static void test_GdiGetCodePage(void)
2495 static const struct _matching_data
2497 UINT current_codepage;
2498 LPCSTR lfFaceName;
2499 UCHAR lfCharSet;
2500 UINT expected_codepage;
2501 } matching_data[] = {
2502 {1251, "Arial", ANSI_CHARSET, 1252},
2503 {1251, "Tahoma", ANSI_CHARSET, 1252},
2505 {1252, "Arial", ANSI_CHARSET, 1252},
2506 {1252, "Tahoma", ANSI_CHARSET, 1252},
2508 {1253, "Arial", ANSI_CHARSET, 1252},
2509 {1253, "Tahoma", ANSI_CHARSET, 1252},
2511 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2512 { 932, "Tahoma", ANSI_CHARSET, 1252},
2513 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2515 { 936, "Arial", ANSI_CHARSET, 936},
2516 { 936, "Tahoma", ANSI_CHARSET, 936},
2517 { 936, "Simsun", ANSI_CHARSET, 936},
2519 { 949, "Arial", ANSI_CHARSET, 949},
2520 { 949, "Tahoma", ANSI_CHARSET, 949},
2521 { 949, "Gulim", ANSI_CHARSET, 949},
2523 { 950, "Arial", ANSI_CHARSET, 950},
2524 { 950, "Tahoma", ANSI_CHARSET, 950},
2525 { 950, "PMingLiU", ANSI_CHARSET, 950},
2527 HDC hdc;
2528 LOGFONTA lf;
2529 HFONT hfont;
2530 UINT charset, acp;
2531 DWORD codepage;
2532 int i;
2534 if (!pGdiGetCodePage)
2536 skip("GdiGetCodePage not available on this platform\n");
2537 return;
2540 acp = GetACP();
2542 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2544 /* only test data matched current locale codepage */
2545 if (matching_data[i].current_codepage != acp)
2546 continue;
2548 if (!is_font_installed(matching_data[i].lfFaceName))
2550 skip("%s is not installed\n", matching_data[i].lfFaceName);
2551 continue;
2554 hdc = GetDC(0);
2556 memset(&lf, 0, sizeof(lf));
2557 lf.lfHeight = -16;
2558 lf.lfCharSet = matching_data[i].lfCharSet;
2559 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2560 hfont = CreateFontIndirectA(&lf);
2561 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2563 hfont = SelectObject(hdc, hfont);
2564 charset = GetTextCharset(hdc);
2565 codepage = pGdiGetCodePage(hdc);
2566 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2567 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2568 ok(codepage == matching_data[i].expected_codepage,
2569 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2571 hfont = SelectObject(hdc, hfont);
2572 DeleteObject(hfont);
2574 /* CLIP_DFA_DISABLE turns off the font association */
2575 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2576 hfont = CreateFontIndirectA(&lf);
2577 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2579 hfont = SelectObject(hdc, hfont);
2580 charset = GetTextCharset(hdc);
2581 codepage = pGdiGetCodePage(hdc);
2582 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2583 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2584 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2586 hfont = SelectObject(hdc, hfont);
2587 DeleteObject(hfont);
2589 ReleaseDC(NULL, hdc);
2593 static void test_GetFontUnicodeRanges(void)
2595 LOGFONTA lf;
2596 HDC hdc;
2597 HFONT hfont, hfont_old;
2598 DWORD size;
2599 GLYPHSET *gs;
2600 DWORD i;
2602 if (!pGetFontUnicodeRanges)
2604 win_skip("GetFontUnicodeRanges not available before W2K\n");
2605 return;
2608 memset(&lf, 0, sizeof(lf));
2609 lstrcpyA(lf.lfFaceName, "Arial");
2610 hfont = create_font("Arial", &lf);
2612 hdc = GetDC(0);
2613 hfont_old = SelectObject(hdc, hfont);
2615 size = pGetFontUnicodeRanges(NULL, NULL);
2616 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2618 size = pGetFontUnicodeRanges(hdc, NULL);
2619 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2621 gs = HeapAlloc(GetProcessHeap(), 0, size);
2623 size = pGetFontUnicodeRanges(hdc, gs);
2624 ok(size, "GetFontUnicodeRanges failed\n");
2626 if (0) /* Disabled to limit console spam */
2627 for (i = 0; i < gs->cRanges; i++)
2628 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2629 trace("found %u ranges\n", gs->cRanges);
2631 HeapFree(GetProcessHeap(), 0, gs);
2633 SelectObject(hdc, hfont_old);
2634 DeleteObject(hfont);
2635 ReleaseDC(NULL, hdc);
2638 #define MAX_ENUM_FONTS 4096
2640 struct enum_font_data
2642 int total;
2643 LOGFONTA lf[MAX_ENUM_FONTS];
2646 struct enum_fullname_data
2648 int total;
2649 ENUMLOGFONTA elf[MAX_ENUM_FONTS];
2652 struct enum_font_dataW
2654 int total;
2655 LOGFONTW lf[MAX_ENUM_FONTS];
2658 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2660 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2661 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2663 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2664 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2666 if (type != TRUETYPE_FONTTYPE) return 1;
2668 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2670 if (0) /* Disabled to limit console spam */
2671 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2672 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2673 if (efd->total < MAX_ENUM_FONTS)
2674 efd->lf[efd->total++] = *lf;
2675 else
2676 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2678 return 1;
2681 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2683 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2684 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2686 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2687 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2689 if (type != TRUETYPE_FONTTYPE) return 1;
2691 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2693 if (0) /* Disabled to limit console spam */
2694 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2695 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2696 if (efd->total < MAX_ENUM_FONTS)
2697 efd->lf[efd->total++] = *lf;
2698 else
2699 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2701 return 1;
2704 static void get_charset_stats(struct enum_font_data *efd,
2705 int *ansi_charset, int *symbol_charset,
2706 int *russian_charset)
2708 int i;
2710 *ansi_charset = 0;
2711 *symbol_charset = 0;
2712 *russian_charset = 0;
2714 for (i = 0; i < efd->total; i++)
2716 switch (efd->lf[i].lfCharSet)
2718 case ANSI_CHARSET:
2719 (*ansi_charset)++;
2720 break;
2721 case SYMBOL_CHARSET:
2722 (*symbol_charset)++;
2723 break;
2724 case RUSSIAN_CHARSET:
2725 (*russian_charset)++;
2726 break;
2731 static void get_charset_statsW(struct enum_font_dataW *efd,
2732 int *ansi_charset, int *symbol_charset,
2733 int *russian_charset)
2735 int i;
2737 *ansi_charset = 0;
2738 *symbol_charset = 0;
2739 *russian_charset = 0;
2741 for (i = 0; i < efd->total; i++)
2743 switch (efd->lf[i].lfCharSet)
2745 case ANSI_CHARSET:
2746 (*ansi_charset)++;
2747 break;
2748 case SYMBOL_CHARSET:
2749 (*symbol_charset)++;
2750 break;
2751 case RUSSIAN_CHARSET:
2752 (*russian_charset)++;
2753 break;
2758 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2760 struct enum_font_data efd;
2761 struct enum_font_dataW efdw;
2762 LOGFONTA lf;
2763 HDC hdc;
2764 int i, ret, ansi_charset, symbol_charset, russian_charset;
2766 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2768 if (*font_name && !is_truetype_font_installed(font_name))
2770 skip("%s is not installed\n", font_name);
2771 return;
2774 hdc = GetDC(0);
2776 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2777 * while EnumFontFamiliesEx doesn't.
2779 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2782 * Use EnumFontFamiliesW since win98 crashes when the
2783 * second parameter is NULL using EnumFontFamilies
2785 efdw.total = 0;
2786 SetLastError(0xdeadbeef);
2787 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2788 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2789 if(ret)
2791 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2792 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2793 ansi_charset, symbol_charset, russian_charset);
2794 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2795 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2796 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2797 ok(russian_charset > 0 ||
2798 broken(russian_charset == 0), /* NT4 */
2799 "NULL family should enumerate RUSSIAN_CHARSET\n");
2802 efdw.total = 0;
2803 SetLastError(0xdeadbeef);
2804 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2805 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2806 if(ret)
2808 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2809 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2810 ansi_charset, symbol_charset, russian_charset);
2811 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2812 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2813 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2814 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2818 efd.total = 0;
2819 SetLastError(0xdeadbeef);
2820 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2821 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2822 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2823 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2824 ansi_charset, symbol_charset, russian_charset,
2825 *font_name ? font_name : "<empty>");
2826 if (*font_name)
2827 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2828 else
2829 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2830 for (i = 0; i < efd.total; i++)
2832 /* FIXME: remove completely once Wine is fixed */
2833 if (efd.lf[i].lfCharSet != font_charset)
2835 todo_wine
2836 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2838 else
2839 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2840 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2841 font_name, efd.lf[i].lfFaceName);
2844 memset(&lf, 0, sizeof(lf));
2845 lf.lfCharSet = ANSI_CHARSET;
2846 strcpy(lf.lfFaceName, font_name);
2847 efd.total = 0;
2848 SetLastError(0xdeadbeef);
2849 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2850 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2851 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2852 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2853 ansi_charset, symbol_charset, russian_charset,
2854 *font_name ? font_name : "<empty>");
2855 if (font_charset == SYMBOL_CHARSET)
2857 if (*font_name)
2858 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2859 else
2860 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2862 else
2864 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2865 for (i = 0; i < efd.total; i++)
2867 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2868 if (*font_name)
2869 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2870 font_name, efd.lf[i].lfFaceName);
2874 /* DEFAULT_CHARSET should enumerate all available charsets */
2875 memset(&lf, 0, sizeof(lf));
2876 lf.lfCharSet = DEFAULT_CHARSET;
2877 strcpy(lf.lfFaceName, font_name);
2878 efd.total = 0;
2879 SetLastError(0xdeadbeef);
2880 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2881 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2882 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2883 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2884 ansi_charset, symbol_charset, russian_charset,
2885 *font_name ? font_name : "<empty>");
2886 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2887 for (i = 0; i < efd.total; i++)
2889 if (*font_name)
2890 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2891 font_name, efd.lf[i].lfFaceName);
2893 if (*font_name)
2895 switch (font_charset)
2897 case ANSI_CHARSET:
2898 ok(ansi_charset > 0,
2899 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2900 ok(!symbol_charset,
2901 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2902 ok(russian_charset > 0,
2903 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2904 break;
2905 case SYMBOL_CHARSET:
2906 ok(!ansi_charset,
2907 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2908 ok(symbol_charset,
2909 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2910 ok(!russian_charset,
2911 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2912 break;
2913 case DEFAULT_CHARSET:
2914 ok(ansi_charset > 0,
2915 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2916 ok(symbol_charset > 0,
2917 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2918 ok(russian_charset > 0,
2919 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2920 break;
2923 else
2925 ok(ansi_charset > 0,
2926 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2927 ok(symbol_charset > 0,
2928 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2929 ok(russian_charset > 0,
2930 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2933 memset(&lf, 0, sizeof(lf));
2934 lf.lfCharSet = SYMBOL_CHARSET;
2935 strcpy(lf.lfFaceName, font_name);
2936 efd.total = 0;
2937 SetLastError(0xdeadbeef);
2938 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2939 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2940 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2941 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2942 ansi_charset, symbol_charset, russian_charset,
2943 *font_name ? font_name : "<empty>");
2944 if (*font_name && font_charset == ANSI_CHARSET)
2945 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2946 else
2948 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2949 for (i = 0; i < efd.total; i++)
2951 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2952 if (*font_name)
2953 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2954 font_name, efd.lf[i].lfFaceName);
2957 ok(!ansi_charset,
2958 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2959 ok(symbol_charset > 0,
2960 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2961 ok(!russian_charset,
2962 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2965 ReleaseDC(0, hdc);
2968 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2970 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
2971 LOGFONTA *target = (LOGFONTA *)lParam;
2972 const DWORD valid_bits = 0x003f01ff;
2973 CHARSETINFO csi;
2974 DWORD fs;
2976 if (type != TRUETYPE_FONTTYPE) return TRUE;
2978 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
2979 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
2980 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
2981 *target = *lf;
2982 return FALSE;
2986 return TRUE;
2989 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
2991 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2993 if (type != TRUETYPE_FONTTYPE) return 1;
2995 if (efd->total < MAX_ENUM_FONTS)
2996 efd->lf[efd->total++] = *lf;
2997 else
2998 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
3000 return 1;
3003 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3005 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3007 if (type != TRUETYPE_FONTTYPE) return 1;
3009 if (efnd->total < MAX_ENUM_FONTS)
3010 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3011 else
3012 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
3014 return 1;
3017 static void test_EnumFontFamiliesEx_default_charset(void)
3019 struct enum_font_data efd;
3020 LOGFONTA target, enum_font;
3021 UINT acp;
3022 HDC hdc;
3023 CHARSETINFO csi;
3025 acp = GetACP();
3026 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3027 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3028 return;
3031 hdc = GetDC(0);
3032 memset(&enum_font, 0, sizeof(enum_font));
3033 enum_font.lfCharSet = csi.ciCharset;
3034 target.lfFaceName[0] = '\0';
3035 target.lfCharSet = csi.ciCharset;
3036 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3037 if (target.lfFaceName[0] == '\0') {
3038 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3039 return;
3041 if (acp == 874 || acp == 1255 || acp == 1256) {
3042 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3043 target.lfCharSet = ANSI_CHARSET;
3046 efd.total = 0;
3047 memset(&enum_font, 0, sizeof(enum_font));
3048 strcpy(enum_font.lfFaceName, target.lfFaceName);
3049 enum_font.lfCharSet = DEFAULT_CHARSET;
3050 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3051 ReleaseDC(0, hdc);
3053 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3054 if (efd.total < 2) {
3055 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3056 return;
3059 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3060 "(%s) got charset %d expected %d\n",
3061 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3063 return;
3066 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3068 HFONT hfont, hfont_prev;
3069 DWORD ret;
3070 GLYPHMETRICS gm1, gm2;
3071 LOGFONTA lf2 = *lf;
3072 WORD idx;
3074 if(!pGetGlyphIndicesA)
3075 return;
3077 /* negative widths are handled just as positive ones */
3078 lf2.lfWidth = -lf->lfWidth;
3080 SetLastError(0xdeadbeef);
3081 hfont = CreateFontIndirectA(lf);
3082 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3083 check_font("original", lf, hfont);
3085 hfont_prev = SelectObject(hdc, hfont);
3087 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3088 if (ret == GDI_ERROR || idx == 0xffff)
3090 SelectObject(hdc, hfont_prev);
3091 DeleteObject(hfont);
3092 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3093 return;
3096 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3097 memset(&gm1, 0xab, sizeof(gm1));
3098 SetLastError(0xdeadbeef);
3099 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3100 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3102 SelectObject(hdc, hfont_prev);
3103 DeleteObject(hfont);
3105 SetLastError(0xdeadbeef);
3106 hfont = CreateFontIndirectA(&lf2);
3107 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3108 check_font("negative width", &lf2, hfont);
3110 hfont_prev = SelectObject(hdc, hfont);
3112 memset(&gm2, 0xbb, sizeof(gm2));
3113 SetLastError(0xdeadbeef);
3114 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3115 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3117 SelectObject(hdc, hfont_prev);
3118 DeleteObject(hfont);
3120 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3121 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3122 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3123 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3124 gm1.gmCellIncX == gm2.gmCellIncX &&
3125 gm1.gmCellIncY == gm2.gmCellIncY,
3126 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3127 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3128 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3129 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3130 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3133 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3134 #include "pshpack2.h"
3135 typedef struct
3137 USHORT version;
3138 SHORT xAvgCharWidth;
3139 USHORT usWeightClass;
3140 USHORT usWidthClass;
3141 SHORT fsType;
3142 SHORT ySubscriptXSize;
3143 SHORT ySubscriptYSize;
3144 SHORT ySubscriptXOffset;
3145 SHORT ySubscriptYOffset;
3146 SHORT ySuperscriptXSize;
3147 SHORT ySuperscriptYSize;
3148 SHORT ySuperscriptXOffset;
3149 SHORT ySuperscriptYOffset;
3150 SHORT yStrikeoutSize;
3151 SHORT yStrikeoutPosition;
3152 SHORT sFamilyClass;
3153 PANOSE panose;
3154 ULONG ulUnicodeRange1;
3155 ULONG ulUnicodeRange2;
3156 ULONG ulUnicodeRange3;
3157 ULONG ulUnicodeRange4;
3158 CHAR achVendID[4];
3159 USHORT fsSelection;
3160 USHORT usFirstCharIndex;
3161 USHORT usLastCharIndex;
3162 /* According to the Apple spec, original version didn't have the below fields,
3163 * version numbers were taken from the OpenType spec.
3165 /* version 0 (TrueType 1.5) */
3166 USHORT sTypoAscender;
3167 USHORT sTypoDescender;
3168 USHORT sTypoLineGap;
3169 USHORT usWinAscent;
3170 USHORT usWinDescent;
3171 /* version 1 (TrueType 1.66) */
3172 ULONG ulCodePageRange1;
3173 ULONG ulCodePageRange2;
3174 /* version 2 (OpenType 1.2) */
3175 SHORT sxHeight;
3176 SHORT sCapHeight;
3177 USHORT usDefaultChar;
3178 USHORT usBreakChar;
3179 USHORT usMaxContext;
3180 } TT_OS2_V2;
3181 #include "poppack.h"
3183 typedef struct
3185 USHORT version;
3186 USHORT num_tables;
3187 } cmap_header;
3189 typedef struct
3191 USHORT plat_id;
3192 USHORT enc_id;
3193 ULONG offset;
3194 } cmap_encoding_record;
3196 typedef struct
3198 USHORT format;
3199 USHORT length;
3200 USHORT language;
3202 BYTE glyph_ids[256];
3203 } cmap_format_0;
3205 typedef struct
3207 USHORT format;
3208 USHORT length;
3209 USHORT language;
3211 USHORT seg_countx2;
3212 USHORT search_range;
3213 USHORT entry_selector;
3214 USHORT range_shift;
3216 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3217 /* Then follows:
3218 USHORT pad;
3219 USHORT start_count[seg_countx2 / 2];
3220 USHORT id_delta[seg_countx2 / 2];
3221 USHORT id_range_offset[seg_countx2 / 2];
3222 USHORT glyph_ids[];
3224 } cmap_format_4;
3226 typedef struct
3228 USHORT end_count;
3229 USHORT start_count;
3230 USHORT id_delta;
3231 USHORT id_range_offset;
3232 } cmap_format_4_seg;
3234 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
3236 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3237 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3238 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3239 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3240 os2->panose.bWeight, os2->panose.bProportion);
3243 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3245 int i;
3246 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3248 *first = 256;
3250 for(i = 0; i < 256; i++)
3252 if(cmap->glyph_ids[i] == 0) continue;
3253 *last = i;
3254 if(*first == 256) *first = i;
3256 if(*first == 256) return FALSE;
3257 return TRUE;
3260 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3262 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3263 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3264 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3265 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3266 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3269 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3271 int i;
3272 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3273 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3275 *first = 0x10000;
3277 for(i = 0; i < seg_count; i++)
3279 cmap_format_4_seg seg;
3281 get_seg4(cmap, i, &seg);
3283 if(seg.start_count > 0xfffe) break;
3285 if(*first == 0x10000) *first = seg.start_count;
3287 *last = min(seg.end_count, 0xfffe);
3290 if(*first == 0x10000) return FALSE;
3291 return TRUE;
3294 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3296 USHORT i;
3297 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3299 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3301 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3302 return (BYTE *)header + GET_BE_DWORD(record->offset);
3303 record++;
3305 return NULL;
3308 typedef enum
3310 cmap_none,
3311 cmap_ms_unicode,
3312 cmap_ms_symbol
3313 } cmap_type;
3315 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3317 LONG size, ret;
3318 cmap_header *header;
3319 void *cmap;
3320 BOOL r = FALSE;
3321 WORD format;
3323 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3324 ok(size != GDI_ERROR, "no cmap table found\n");
3325 if(size == GDI_ERROR) return FALSE;
3327 header = HeapAlloc(GetProcessHeap(), 0, size);
3328 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3329 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3330 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3332 cmap = get_cmap(header, 3, 1);
3333 if(cmap)
3334 *cmap_type = cmap_ms_unicode;
3335 else
3337 cmap = get_cmap(header, 3, 0);
3338 if(cmap) *cmap_type = cmap_ms_symbol;
3340 if(!cmap)
3342 *cmap_type = cmap_none;
3343 goto end;
3346 format = GET_BE_WORD(*(WORD *)cmap);
3347 switch(format)
3349 case 0:
3350 r = get_first_last_from_cmap0(cmap, first, last);
3351 break;
3352 case 4:
3353 r = get_first_last_from_cmap4(cmap, first, last, size);
3354 break;
3355 default:
3356 trace("unhandled cmap format %d\n", format);
3357 break;
3360 end:
3361 HeapFree(GetProcessHeap(), 0, header);
3362 return r;
3365 #define TT_PLATFORM_APPLE_UNICODE 0
3366 #define TT_PLATFORM_MACINTOSH 1
3367 #define TT_PLATFORM_MICROSOFT 3
3368 #define TT_APPLE_ID_DEFAULT 0
3369 #define TT_APPLE_ID_ISO_10646 2
3370 #define TT_APPLE_ID_UNICODE_2_0 3
3371 #define TT_MS_ID_SYMBOL_CS 0
3372 #define TT_MS_ID_UNICODE_CS 1
3373 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3374 #define TT_NAME_ID_FONT_FAMILY 1
3375 #define TT_NAME_ID_FONT_SUBFAMILY 2
3376 #define TT_NAME_ID_UNIQUE_ID 3
3377 #define TT_NAME_ID_FULL_NAME 4
3378 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3380 typedef struct sfnt_name
3382 USHORT platform_id;
3383 USHORT encoding_id;
3384 USHORT language_id;
3385 USHORT name_id;
3386 USHORT length;
3387 USHORT offset;
3388 } sfnt_name;
3390 static const LANGID mac_langid_table[] =
3392 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3393 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3394 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3395 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3396 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3397 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3398 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3399 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3400 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3401 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3402 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3403 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3404 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3405 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3406 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3407 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3408 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3409 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3410 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3411 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3412 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3413 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3414 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3415 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3416 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3417 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3418 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3419 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3420 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3421 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3422 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3423 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3424 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3425 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3426 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3427 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3428 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3429 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3430 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3431 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3432 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3433 0, /* TT_MAC_LANGID_YIDDISH */
3434 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3435 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3436 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3437 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3438 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3439 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3440 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3441 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3442 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3443 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3444 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3445 0, /* TT_MAC_LANGID_MOLDAVIAN */
3446 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3447 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3448 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3449 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3450 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3451 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3452 0, /* TT_MAC_LANGID_KURDISH */
3453 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3454 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3455 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3456 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3457 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3458 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3459 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3460 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3461 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3462 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3463 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3464 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3465 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3466 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3467 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3468 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3469 0, /* TT_MAC_LANGID_BURMESE */
3470 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3471 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3472 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3473 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3474 0, /* TT_MAC_LANGID_TAGALOG */
3475 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3476 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3477 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3478 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3479 0, /* TT_MAC_LANGID_GALLA */
3480 0, /* TT_MAC_LANGID_SOMALI */
3481 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3482 0, /* TT_MAC_LANGID_RUANDA */
3483 0, /* TT_MAC_LANGID_RUNDI */
3484 0, /* TT_MAC_LANGID_CHEWA */
3485 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3486 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3487 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3489 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3490 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3491 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3492 0, /* TT_MAC_LANGID_LATIN */
3493 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3494 0, /* TT_MAC_LANGID_GUARANI */
3495 0, /* TT_MAC_LANGID_AYMARA */
3496 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3497 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3498 0, /* TT_MAC_LANGID_DZONGKHA */
3499 0, /* TT_MAC_LANGID_JAVANESE */
3500 0, /* TT_MAC_LANGID_SUNDANESE */
3501 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3502 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3503 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3504 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3505 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3506 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3507 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3508 0, /* TT_MAC_LANGID_TONGAN */
3509 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3510 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3511 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3514 static inline WORD get_mac_code_page( const sfnt_name *name )
3516 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3517 return 10000 + GET_BE_WORD(name->encoding_id);
3520 static int match_name_table_language( const sfnt_name *name, LANGID lang )
3522 LANGID name_lang;
3523 int res = 0;
3525 switch (GET_BE_WORD(name->platform_id))
3527 case TT_PLATFORM_MICROSOFT:
3528 res += 5; /* prefer the Microsoft name */
3529 switch (GET_BE_WORD(name->encoding_id))
3531 case TT_MS_ID_UNICODE_CS:
3532 case TT_MS_ID_SYMBOL_CS:
3533 name_lang = GET_BE_WORD(name->language_id);
3534 break;
3535 default:
3536 return 0;
3538 break;
3539 case TT_PLATFORM_MACINTOSH:
3540 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3541 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3542 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3543 break;
3544 case TT_PLATFORM_APPLE_UNICODE:
3545 res += 2; /* prefer Unicode encodings */
3546 switch (GET_BE_WORD(name->encoding_id))
3548 case TT_APPLE_ID_DEFAULT:
3549 case TT_APPLE_ID_ISO_10646:
3550 case TT_APPLE_ID_UNICODE_2_0:
3551 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3552 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3553 break;
3554 default:
3555 return 0;
3557 break;
3558 default:
3559 return 0;
3561 if (name_lang == lang) res += 30;
3562 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3563 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3564 return res;
3567 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3569 struct sfnt_name_header
3571 USHORT format;
3572 USHORT number_of_record;
3573 USHORT storage_offset;
3574 } *header;
3575 sfnt_name *entry;
3576 BOOL r = FALSE;
3577 LONG size, offset, length;
3578 LONG c, ret;
3579 WCHAR *name;
3580 BYTE *data;
3581 USHORT i;
3582 int res, best_lang = 0, best_index = -1;
3584 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3585 ok(size != GDI_ERROR, "no name table found\n");
3586 if(size == GDI_ERROR) return FALSE;
3588 data = HeapAlloc(GetProcessHeap(), 0, size);
3589 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3590 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3592 header = (void *)data;
3593 header->format = GET_BE_WORD(header->format);
3594 header->number_of_record = GET_BE_WORD(header->number_of_record);
3595 header->storage_offset = GET_BE_WORD(header->storage_offset);
3596 if (header->format != 0)
3598 trace("got format %u\n", header->format);
3599 goto out;
3601 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3603 trace("number records out of range: %d\n", header->number_of_record);
3604 goto out;
3606 if (header->storage_offset >= size)
3608 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3609 goto out;
3612 entry = (void *)&header[1];
3613 for (i = 0; i < header->number_of_record; i++)
3615 if (GET_BE_WORD(entry[i].name_id) != name_id) continue;
3616 res = match_name_table_language( &entry[i], language_id);
3617 if (res > best_lang)
3619 best_lang = res;
3620 best_index = i;
3624 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset);
3625 length = GET_BE_WORD(entry[best_index].length);
3626 if (offset + length > size)
3628 trace("entry %d is out of range\n", best_index);
3629 goto out;
3631 if (length >= out_size)
3633 trace("buffer too small for entry %d\n", best_index);
3634 goto out;
3637 name = (WCHAR *)(data + offset);
3638 for (c = 0; c < length / 2; c++)
3639 out_buf[c] = GET_BE_WORD(name[c]);
3640 out_buf[c] = 0;
3642 r = TRUE;
3644 out:
3645 HeapFree(GetProcessHeap(), 0, data);
3646 return r;
3649 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3651 HDC hdc;
3652 HFONT hfont, hfont_old;
3653 TEXTMETRICA tmA;
3654 TT_OS2_V2 tt_os2;
3655 LONG size, ret;
3656 const char *font_name = lf->lfFaceName;
3657 DWORD cmap_first = 0, cmap_last = 0;
3658 UINT ascent, descent, cell_height;
3659 cmap_type cmap_type;
3660 BOOL sys_lang_non_english;
3662 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3663 hdc = GetDC(0);
3665 SetLastError(0xdeadbeef);
3666 hfont = CreateFontIndirectA(lf);
3667 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3669 hfont_old = SelectObject(hdc, hfont);
3671 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3672 if (size == GDI_ERROR)
3674 trace("OS/2 chunk was not found\n");
3675 goto end_of_test;
3677 if (size > sizeof(tt_os2))
3679 trace("got too large OS/2 chunk of size %u\n", size);
3680 size = sizeof(tt_os2);
3683 memset(&tt_os2, 0, sizeof(tt_os2));
3684 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3685 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3687 SetLastError(0xdeadbeef);
3688 ret = GetTextMetricsA(hdc, &tmA);
3689 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3691 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3693 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3695 else
3697 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3698 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3699 UINT os2_first_char, os2_last_char, default_char, break_char;
3700 USHORT version;
3701 TEXTMETRICW tmW;
3703 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3704 descent = GET_BE_WORD(tt_os2.usWinDescent);
3705 cell_height = ascent + descent;
3706 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3707 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3709 version = GET_BE_WORD(tt_os2.version);
3711 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3712 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3713 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3714 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3716 if (winetest_debug > 1)
3717 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3718 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3719 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3721 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3723 expect_first_W = 0;
3724 switch(GetACP())
3726 case 1255: /* Hebrew */
3727 expect_last_W = 0xf896;
3728 break;
3729 case 1257: /* Baltic */
3730 expect_last_W = 0xf8fd;
3731 break;
3732 default:
3733 expect_last_W = 0xf0ff;
3735 expect_break_W = 0x20;
3736 expect_default_W = expect_break_W - 1;
3737 expect_first_A = 0x1e;
3738 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3740 else
3742 expect_first_W = cmap_first;
3743 expect_last_W = cmap_last;
3744 if(os2_first_char <= 1)
3745 expect_break_W = os2_first_char + 2;
3746 else if(os2_first_char > 0xff)
3747 expect_break_W = 0x20;
3748 else
3749 expect_break_W = os2_first_char;
3750 expect_default_W = expect_break_W - 1;
3751 expect_first_A = expect_default_W - 1;
3752 expect_last_A = min(expect_last_W, 0xff);
3754 expect_break_A = expect_break_W;
3755 expect_default_A = expect_default_W;
3757 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3758 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3759 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3760 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3761 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3762 else
3763 ok(tmA.tmFirstChar == expect_first_A ||
3764 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3765 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3766 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3767 ok(tmA.tmLastChar == expect_last_A ||
3768 tmA.tmLastChar == 0xff /* win9x */,
3769 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3770 else
3771 skip("tmLastChar is DBCS lead byte\n");
3772 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3773 font_name, tmA.tmBreakChar, expect_break_A);
3774 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3775 "A: tmDefaultChar for %s got %02x expected %02x\n",
3776 font_name, tmA.tmDefaultChar, expect_default_A);
3779 SetLastError(0xdeadbeef);
3780 ret = GetTextMetricsW(hdc, &tmW);
3781 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3782 "GetTextMetricsW error %u\n", GetLastError());
3783 if (ret)
3785 /* Wine uses the os2 first char */
3786 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3787 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3788 font_name, tmW.tmFirstChar, expect_first_W);
3789 else
3790 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3791 font_name, tmW.tmFirstChar, expect_first_W);
3793 /* Wine uses the os2 last char */
3794 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3795 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3796 font_name, tmW.tmLastChar, expect_last_W);
3797 else
3798 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3799 font_name, tmW.tmLastChar, expect_last_W);
3800 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3801 font_name, tmW.tmBreakChar, expect_break_W);
3802 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3803 "W: tmDefaultChar for %s got %02x expected %02x\n",
3804 font_name, tmW.tmDefaultChar, expect_default_W);
3806 /* Test the aspect ratio while we have tmW */
3807 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3808 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3809 tmW.tmDigitizedAspectX, ret);
3810 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3811 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3812 tmW.tmDigitizedAspectX, ret);
3816 /* test FF_ values */
3817 switch(tt_os2.panose.bFamilyType)
3819 case PAN_ANY:
3820 case PAN_NO_FIT:
3821 case PAN_FAMILY_TEXT_DISPLAY:
3822 case PAN_FAMILY_PICTORIAL:
3823 default:
3824 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3825 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3827 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3828 break;
3830 switch(tt_os2.panose.bSerifStyle)
3832 case PAN_ANY:
3833 case PAN_NO_FIT:
3834 default:
3835 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3836 break;
3838 case PAN_SERIF_COVE:
3839 case PAN_SERIF_OBTUSE_COVE:
3840 case PAN_SERIF_SQUARE_COVE:
3841 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3842 case PAN_SERIF_SQUARE:
3843 case PAN_SERIF_THIN:
3844 case PAN_SERIF_BONE:
3845 case PAN_SERIF_EXAGGERATED:
3846 case PAN_SERIF_TRIANGLE:
3847 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3848 break;
3850 case PAN_SERIF_NORMAL_SANS:
3851 case PAN_SERIF_OBTUSE_SANS:
3852 case PAN_SERIF_PERP_SANS:
3853 case PAN_SERIF_FLARED:
3854 case PAN_SERIF_ROUNDED:
3855 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3856 break;
3858 break;
3860 case PAN_FAMILY_SCRIPT:
3861 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3862 break;
3864 case PAN_FAMILY_DECORATIVE:
3865 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3866 break;
3869 test_negative_width(hdc, lf);
3871 end_of_test:
3872 SelectObject(hdc, hfont_old);
3873 DeleteObject(hfont);
3875 ReleaseDC(0, hdc);
3878 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3880 INT *enumed = (INT *)lParam;
3882 if (type == TRUETYPE_FONTTYPE)
3884 (*enumed)++;
3885 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
3887 return 1;
3890 static void test_GetTextMetrics(void)
3892 LOGFONTA lf;
3893 HDC hdc;
3894 INT enumed;
3896 /* Report only once */
3897 if(!pGetGlyphIndicesA)
3898 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3900 hdc = GetDC(0);
3902 memset(&lf, 0, sizeof(lf));
3903 lf.lfCharSet = DEFAULT_CHARSET;
3904 enumed = 0;
3905 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3906 trace("Tested metrics of %d truetype fonts\n", enumed);
3908 ReleaseDC(0, hdc);
3911 static void test_nonexistent_font(void)
3913 static const struct
3915 const char *name;
3916 int charset;
3917 } font_subst[] =
3919 { "Times New Roman Baltic", 186 },
3920 { "Times New Roman CE", 238 },
3921 { "Times New Roman CYR", 204 },
3922 { "Times New Roman Greek", 161 },
3923 { "Times New Roman TUR", 162 }
3925 static const struct
3927 const char *name;
3928 int charset;
3929 } shell_subst[] =
3931 { "MS Shell Dlg", 186 },
3932 { "MS Shell Dlg", 238 },
3933 { "MS Shell Dlg", 204 },
3934 { "MS Shell Dlg", 161 },
3935 { "MS Shell Dlg", 162 }
3937 LOGFONTA lf;
3938 HDC hdc;
3939 HFONT hfont;
3940 CHARSETINFO csi;
3941 INT cs, expected_cs, i, ret;
3942 char buf[LF_FACESIZE];
3944 expected_cs = GetACP();
3945 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3947 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3948 return;
3950 expected_cs = csi.ciCharset;
3951 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3953 hdc = CreateCompatibleDC(0);
3955 for (i = 0; i < sizeof(shell_subst)/sizeof(shell_subst[0]); i++)
3957 ret = is_font_installed(shell_subst[i].name);
3958 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
3959 ret = is_truetype_font_installed(shell_subst[i].name);
3960 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
3962 memset(&lf, 0, sizeof(lf));
3963 lf.lfHeight = -13;
3964 lf.lfWeight = FW_REGULAR;
3965 strcpy(lf.lfFaceName, shell_subst[i].name);
3966 hfont = CreateFontIndirectA(&lf);
3967 hfont = SelectObject(hdc, hfont);
3968 GetTextFaceA(hdc, sizeof(buf), buf);
3969 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
3970 cs = GetTextCharset(hdc);
3971 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name);
3973 DeleteObject(SelectObject(hdc, hfont));
3975 memset(&lf, 0, sizeof(lf));
3976 lf.lfHeight = -13;
3977 lf.lfWeight = FW_DONTCARE;
3978 strcpy(lf.lfFaceName, shell_subst[i].name);
3979 hfont = CreateFontIndirectA(&lf);
3980 hfont = SelectObject(hdc, hfont);
3981 GetTextFaceA(hdc, sizeof(buf), buf);
3982 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
3983 cs = GetTextCharset(hdc);
3984 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name);
3985 DeleteObject(SelectObject(hdc, hfont));
3988 if (!is_truetype_font_installed("Arial") ||
3989 !is_truetype_font_installed("Times New Roman"))
3991 DeleteDC(hdc);
3992 skip("Arial or Times New Roman not installed\n");
3993 return;
3996 memset(&lf, 0, sizeof(lf));
3997 lf.lfHeight = 100;
3998 lf.lfWeight = FW_REGULAR;
3999 lf.lfCharSet = ANSI_CHARSET;
4000 lf.lfPitchAndFamily = FF_SWISS;
4001 strcpy(lf.lfFaceName, "Nonexistent font");
4002 hfont = CreateFontIndirectA(&lf);
4003 hfont = SelectObject(hdc, hfont);
4004 GetTextFaceA(hdc, sizeof(buf), buf);
4005 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4006 cs = GetTextCharset(hdc);
4007 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4008 DeleteObject(SelectObject(hdc, hfont));
4010 memset(&lf, 0, sizeof(lf));
4011 lf.lfHeight = -13;
4012 lf.lfWeight = FW_DONTCARE;
4013 strcpy(lf.lfFaceName, "Nonexistent font");
4014 hfont = CreateFontIndirectA(&lf);
4015 hfont = SelectObject(hdc, hfont);
4016 GetTextFaceA(hdc, sizeof(buf), buf);
4017 todo_wine /* Wine uses Arial for all substitutions */
4018 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
4019 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
4020 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4021 "Got %s\n", buf);
4022 cs = GetTextCharset(hdc);
4023 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
4024 DeleteObject(SelectObject(hdc, hfont));
4026 memset(&lf, 0, sizeof(lf));
4027 lf.lfHeight = -13;
4028 lf.lfWeight = FW_REGULAR;
4029 strcpy(lf.lfFaceName, "Nonexistent font");
4030 hfont = CreateFontIndirectA(&lf);
4031 hfont = SelectObject(hdc, hfont);
4032 GetTextFaceA(hdc, sizeof(buf), buf);
4033 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4034 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
4035 cs = GetTextCharset(hdc);
4036 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4037 DeleteObject(SelectObject(hdc, hfont));
4039 memset(&lf, 0, sizeof(lf));
4040 lf.lfHeight = -13;
4041 lf.lfWeight = FW_DONTCARE;
4042 strcpy(lf.lfFaceName, "Times New Roman");
4043 hfont = CreateFontIndirectA(&lf);
4044 hfont = SelectObject(hdc, hfont);
4045 GetTextFaceA(hdc, sizeof(buf), buf);
4046 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
4047 cs = GetTextCharset(hdc);
4048 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4049 DeleteObject(SelectObject(hdc, hfont));
4051 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
4053 ret = is_font_installed(font_subst[i].name);
4054 todo_wine
4055 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4056 "%s should be enumerated\n", font_subst[i].name);
4057 ret = is_truetype_font_installed(font_subst[i].name);
4058 todo_wine
4059 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4060 "%s should be enumerated\n", font_subst[i].name);
4062 memset(&lf, 0, sizeof(lf));
4063 lf.lfHeight = -13;
4064 lf.lfWeight = FW_REGULAR;
4065 strcpy(lf.lfFaceName, font_subst[i].name);
4066 hfont = CreateFontIndirectA(&lf);
4067 hfont = SelectObject(hdc, hfont);
4068 cs = GetTextCharset(hdc);
4069 if (font_subst[i].charset == expected_cs)
4071 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4072 GetTextFaceA(hdc, sizeof(buf), buf);
4073 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
4075 else
4077 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
4078 GetTextFaceA(hdc, sizeof(buf), buf);
4079 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4080 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
4082 DeleteObject(SelectObject(hdc, hfont));
4084 memset(&lf, 0, sizeof(lf));
4085 lf.lfHeight = -13;
4086 lf.lfWeight = FW_DONTCARE;
4087 strcpy(lf.lfFaceName, font_subst[i].name);
4088 hfont = CreateFontIndirectA(&lf);
4089 hfont = SelectObject(hdc, hfont);
4090 GetTextFaceA(hdc, sizeof(buf), buf);
4091 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
4092 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
4093 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
4094 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4095 "got %s for font %s\n", buf, font_subst[i].name);
4096 cs = GetTextCharset(hdc);
4097 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4098 DeleteObject(SelectObject(hdc, hfont));
4101 DeleteDC(hdc);
4104 static void test_GdiRealizationInfo(void)
4106 HDC hdc;
4107 DWORD info[4];
4108 BOOL r;
4109 HFONT hfont, hfont_old;
4110 LOGFONTA lf;
4112 if(!pGdiRealizationInfo)
4114 win_skip("GdiRealizationInfo not available\n");
4115 return;
4118 hdc = GetDC(0);
4120 memset(info, 0xcc, sizeof(info));
4121 r = pGdiRealizationInfo(hdc, info);
4122 ok(r != 0, "ret 0\n");
4123 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
4124 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4126 if (!is_truetype_font_installed("Arial"))
4128 skip("skipping GdiRealizationInfo with truetype font\n");
4129 goto end;
4132 memset(&lf, 0, sizeof(lf));
4133 strcpy(lf.lfFaceName, "Arial");
4134 lf.lfHeight = 20;
4135 lf.lfWeight = FW_NORMAL;
4136 hfont = CreateFontIndirectA(&lf);
4137 hfont_old = SelectObject(hdc, hfont);
4139 memset(info, 0xcc, sizeof(info));
4140 r = pGdiRealizationInfo(hdc, info);
4141 ok(r != 0, "ret 0\n");
4142 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
4143 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4145 DeleteObject(SelectObject(hdc, hfont_old));
4147 end:
4148 ReleaseDC(0, hdc);
4151 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4152 the nul in the count of characters copied when the face name buffer is not
4153 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4154 always includes it. */
4155 static void test_GetTextFace(void)
4157 static const char faceA[] = "Tahoma";
4158 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
4159 LOGFONTA fA = {0};
4160 LOGFONTW fW = {0};
4161 char bufA[LF_FACESIZE];
4162 WCHAR bufW[LF_FACESIZE];
4163 HFONT f, g;
4164 HDC dc;
4165 int n;
4167 if(!is_font_installed("Tahoma"))
4169 skip("Tahoma is not installed so skipping this test\n");
4170 return;
4173 /* 'A' case. */
4174 memcpy(fA.lfFaceName, faceA, sizeof faceA);
4175 f = CreateFontIndirectA(&fA);
4176 ok(f != NULL, "CreateFontIndirectA failed\n");
4178 dc = GetDC(NULL);
4179 g = SelectObject(dc, f);
4180 n = GetTextFaceA(dc, sizeof bufA, bufA);
4181 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
4182 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
4184 /* Play with the count arg. */
4185 bufA[0] = 'x';
4186 n = GetTextFaceA(dc, 0, bufA);
4187 ok(n == 0, "GetTextFaceA returned %d\n", n);
4188 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4190 bufA[0] = 'x';
4191 n = GetTextFaceA(dc, 1, bufA);
4192 ok(n == 0, "GetTextFaceA returned %d\n", n);
4193 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4195 bufA[0] = 'x'; bufA[1] = 'y';
4196 n = GetTextFaceA(dc, 2, bufA);
4197 ok(n == 1, "GetTextFaceA returned %d\n", n);
4198 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
4200 n = GetTextFaceA(dc, 0, NULL);
4201 ok(n == sizeof faceA ||
4202 broken(n == 0), /* win98, winMe */
4203 "GetTextFaceA returned %d\n", n);
4205 DeleteObject(SelectObject(dc, g));
4206 ReleaseDC(NULL, dc);
4208 /* 'W' case. */
4209 memcpy(fW.lfFaceName, faceW, sizeof faceW);
4210 SetLastError(0xdeadbeef);
4211 f = CreateFontIndirectW(&fW);
4212 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
4214 win_skip("CreateFontIndirectW is not implemented\n");
4215 return;
4217 ok(f != NULL, "CreateFontIndirectW failed\n");
4219 dc = GetDC(NULL);
4220 g = SelectObject(dc, f);
4221 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
4222 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4223 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
4225 /* Play with the count arg. */
4226 bufW[0] = 'x';
4227 n = GetTextFaceW(dc, 0, bufW);
4228 ok(n == 0, "GetTextFaceW returned %d\n", n);
4229 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4231 bufW[0] = 'x';
4232 n = GetTextFaceW(dc, 1, bufW);
4233 ok(n == 1, "GetTextFaceW returned %d\n", n);
4234 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4236 bufW[0] = 'x'; bufW[1] = 'y';
4237 n = GetTextFaceW(dc, 2, bufW);
4238 ok(n == 2, "GetTextFaceW returned %d\n", n);
4239 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4241 n = GetTextFaceW(dc, 0, NULL);
4242 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4244 DeleteObject(SelectObject(dc, g));
4245 ReleaseDC(NULL, dc);
4248 static void test_orientation(void)
4250 static const char test_str[11] = "Test String";
4251 HDC hdc;
4252 LOGFONTA lf;
4253 HFONT hfont, old_hfont;
4254 SIZE size;
4256 if (!is_truetype_font_installed("Arial"))
4258 skip("Arial is not installed\n");
4259 return;
4262 hdc = CreateCompatibleDC(0);
4263 memset(&lf, 0, sizeof(lf));
4264 lstrcpyA(lf.lfFaceName, "Arial");
4265 lf.lfHeight = 72;
4266 lf.lfOrientation = lf.lfEscapement = 900;
4267 hfont = create_font("orientation", &lf);
4268 old_hfont = SelectObject(hdc, hfont);
4269 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4270 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4271 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4272 SelectObject(hdc, old_hfont);
4273 DeleteObject(hfont);
4274 DeleteDC(hdc);
4277 static void test_oemcharset(void)
4279 HDC hdc;
4280 LOGFONTA lf, clf;
4281 HFONT hfont, old_hfont;
4282 int charset;
4284 hdc = CreateCompatibleDC(0);
4285 ZeroMemory(&lf, sizeof(lf));
4286 lf.lfHeight = 12;
4287 lf.lfCharSet = OEM_CHARSET;
4288 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4289 lstrcpyA(lf.lfFaceName, "Terminal");
4290 hfont = CreateFontIndirectA(&lf);
4291 old_hfont = SelectObject(hdc, hfont);
4292 charset = GetTextCharset(hdc);
4293 todo_wine
4294 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4295 hfont = SelectObject(hdc, old_hfont);
4296 GetObjectA(hfont, sizeof(clf), &clf);
4297 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4298 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4299 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4300 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4301 DeleteObject(hfont);
4302 DeleteDC(hdc);
4305 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4306 const TEXTMETRICA *lpntme,
4307 DWORD FontType, LPARAM lParam)
4309 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4310 CHARSETINFO csi;
4311 LOGFONTA lf = *lpelfe;
4312 HFONT hfont;
4313 DWORD found_subset;
4315 /* skip bitmap, proportional or vertical font */
4316 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4317 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4318 lf.lfFaceName[0] == '@')
4319 return 1;
4321 /* skip linked font */
4322 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4323 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4324 return 1;
4326 /* skip linked font, like SimSun-ExtB */
4327 switch (lpelfe->lfCharSet) {
4328 case SHIFTJIS_CHARSET:
4329 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4330 break;
4331 case GB2312_CHARSET:
4332 case CHINESEBIG5_CHARSET:
4333 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4334 break;
4335 case HANGEUL_CHARSET:
4336 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4337 break;
4338 default:
4339 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4340 break;
4342 if (!found_subset)
4343 return 1;
4345 /* test with an odd height */
4346 lf.lfHeight = -19;
4347 lf.lfWidth = 0;
4348 hfont = CreateFontIndirectA(&lf);
4349 if (hfont)
4351 *(HFONT *)lParam = hfont;
4352 return 0;
4354 return 1;
4357 static void test_GetGlyphOutline(void)
4359 HDC hdc;
4360 GLYPHMETRICS gm, gm2;
4361 LOGFONTA lf;
4362 HFONT hfont, old_hfont;
4363 INT ret, ret2;
4364 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4365 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4366 static const struct
4368 UINT cs;
4369 UINT a;
4370 UINT w;
4371 } c[] =
4373 {ANSI_CHARSET, 0x30, 0x30},
4374 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4375 {HANGEUL_CHARSET, 0x8141, 0xac02},
4376 {GB2312_CHARSET, 0x8141, 0x4e04},
4377 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4379 UINT i;
4381 if (!is_truetype_font_installed("Tahoma"))
4383 skip("Tahoma is not installed\n");
4384 return;
4387 hdc = CreateCompatibleDC(0);
4388 memset(&lf, 0, sizeof(lf));
4389 lf.lfHeight = 72;
4390 lstrcpyA(lf.lfFaceName, "Tahoma");
4391 SetLastError(0xdeadbeef);
4392 hfont = CreateFontIndirectA(&lf);
4393 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4394 old_hfont = SelectObject(hdc, hfont);
4396 memset(&gm, 0, sizeof(gm));
4397 SetLastError(0xdeadbeef);
4398 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4399 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4401 memset(&gm, 0, sizeof(gm));
4402 SetLastError(0xdeadbeef);
4403 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4404 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4405 ok(GetLastError() == 0xdeadbeef ||
4406 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4407 "expected 0xdeadbeef, got %u\n", GetLastError());
4409 memset(&gm, 0, sizeof(gm));
4410 SetLastError(0xdeadbeef);
4411 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4412 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4413 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4415 memset(&gm, 0, sizeof(gm));
4416 SetLastError(0xdeadbeef);
4417 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4418 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4420 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4421 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4424 /* test for needed buffer size request on space char */
4425 memset(&gm, 0, sizeof(gm));
4426 SetLastError(0xdeadbeef);
4427 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4428 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4430 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4431 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX);
4432 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY);
4435 /* requesting buffer size for space char + error */
4436 memset(&gm, 0, sizeof(gm));
4437 SetLastError(0xdeadbeef);
4438 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4439 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4441 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4442 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4443 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX);
4444 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY);
4447 /* test GetGlyphOutline with a buffer too small */
4448 SetLastError(0xdeadbeef);
4449 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat);
4450 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4451 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4453 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4455 DWORD dummy;
4457 memset(&gm, 0xab, sizeof(gm));
4458 SetLastError(0xdeadbeef);
4459 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4460 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4462 if (fmt[i] == GGO_METRICS)
4463 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4464 else
4465 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4466 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4467 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4470 memset(&gm, 0xab, sizeof(gm));
4471 SetLastError(0xdeadbeef);
4472 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4473 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4475 if (fmt[i] == GGO_METRICS)
4476 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4477 else
4478 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4479 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4480 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4483 memset(&gm, 0xab, sizeof(gm));
4484 SetLastError(0xdeadbeef);
4485 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4486 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4488 if (fmt[i] == GGO_METRICS)
4489 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4490 else
4491 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4492 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4493 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4496 memset(&gm, 0xab, sizeof(gm));
4497 SetLastError(0xdeadbeef);
4498 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4499 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4501 if (fmt[i] == GGO_METRICS) {
4502 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4503 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4504 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4506 else
4508 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4509 memset(&gm2, 0xab, sizeof(gm2));
4510 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4511 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4516 SelectObject(hdc, old_hfont);
4517 DeleteObject(hfont);
4519 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4521 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4522 TEXTMETRICA tm;
4524 lf.lfFaceName[0] = '\0';
4525 lf.lfCharSet = c[i].cs;
4526 lf.lfPitchAndFamily = 0;
4527 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4529 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4530 continue;
4533 old_hfont = SelectObject(hdc, hfont);
4535 /* expected to ignore superfluous bytes (sigle-byte character) */
4536 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4537 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4538 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4540 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4541 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4542 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4544 /* expected to ignore superfluous bytes (double-byte character) */
4545 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4546 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4547 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4548 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4550 /* expected to match wide-char version results */
4551 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4552 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4554 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4556 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4557 continue;
4559 DeleteObject(SelectObject(hdc, hfont));
4560 if (c[i].a <= 0xff)
4562 DeleteObject(SelectObject(hdc, old_hfont));
4563 continue;
4566 ret = GetObjectA(hfont, sizeof lf, &lf);
4567 ok(ret > 0, "GetObject error %u\n", GetLastError());
4569 ret = GetTextMetricsA(hdc, &tm);
4570 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4571 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4572 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4573 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4574 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4575 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4576 "expected %d, got %d (%s:%d)\n",
4577 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4579 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4580 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4581 ok(gm2.gmCellIncY == -lf.lfHeight,
4582 "expected %d, got %d (%s:%d)\n",
4583 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4585 lf.lfItalic = TRUE;
4586 hfont = CreateFontIndirectA(&lf);
4587 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4588 DeleteObject(SelectObject(hdc, hfont));
4589 ret = GetTextMetricsA(hdc, &tm);
4590 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4591 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4592 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4593 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4594 "expected %d, got %d (%s:%d)\n",
4595 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4597 lf.lfItalic = FALSE;
4598 lf.lfEscapement = lf.lfOrientation = 2700;
4599 hfont = CreateFontIndirectA(&lf);
4600 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4601 DeleteObject(SelectObject(hdc, hfont));
4602 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4603 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4604 ok(gm2.gmCellIncY == -lf.lfHeight,
4605 "expected %d, got %d (%s:%d)\n",
4606 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4608 hfont = SelectObject(hdc, old_hfont);
4609 DeleteObject(hfont);
4612 DeleteDC(hdc);
4615 /* bug #9995: there is a limit to the character width that can be specified */
4616 static void test_GetTextMetrics2(const char *fontname, int font_height)
4618 HFONT of, hf;
4619 HDC hdc;
4620 TEXTMETRICA tm;
4621 BOOL ret;
4622 int ave_width, height, width, ratio, scale;
4624 if (!is_truetype_font_installed( fontname)) {
4625 skip("%s is not installed\n", fontname);
4626 return;
4628 hdc = CreateCompatibleDC(0);
4629 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4630 /* select width = 0 */
4631 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4632 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4633 DEFAULT_QUALITY, VARIABLE_PITCH,
4634 fontname);
4635 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4636 of = SelectObject( hdc, hf);
4637 ret = GetTextMetricsA( hdc, &tm);
4638 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4639 height = tm.tmHeight;
4640 ave_width = tm.tmAveCharWidth;
4641 SelectObject( hdc, of);
4642 DeleteObject( hf);
4644 trace("height %d, ave width %d\n", height, ave_width);
4646 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4648 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4649 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4650 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4651 ok(hf != 0, "CreateFont failed\n");
4652 of = SelectObject(hdc, hf);
4653 ret = GetTextMetricsA(hdc, &tm);
4654 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4655 SelectObject(hdc, of);
4656 DeleteObject(hf);
4658 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4659 break;
4662 DeleteDC(hdc);
4664 ratio = width / height;
4665 scale = width / ave_width;
4667 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4668 width, height, ratio, width, ave_width, scale);
4670 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4673 static void test_CreateFontIndirect(void)
4675 LOGFONTA lf, getobj_lf;
4676 int ret, i;
4677 HFONT hfont;
4678 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4680 memset(&lf, 0, sizeof(lf));
4681 lf.lfCharSet = ANSI_CHARSET;
4682 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4683 lf.lfHeight = 16;
4684 lf.lfWidth = 16;
4685 lf.lfQuality = DEFAULT_QUALITY;
4686 lf.lfItalic = FALSE;
4687 lf.lfWeight = FW_DONTCARE;
4689 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4691 lstrcpyA(lf.lfFaceName, TestName[i]);
4692 hfont = CreateFontIndirectA(&lf);
4693 ok(hfont != 0, "CreateFontIndirectA failed\n");
4694 SetLastError(0xdeadbeef);
4695 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4696 ok(ret, "GetObject failed: %d\n", GetLastError());
4697 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4698 ok(lf.lfWeight == getobj_lf.lfWeight ||
4699 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4700 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4701 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4702 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4703 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4704 DeleteObject(hfont);
4708 static void test_CreateFontIndirectEx(void)
4710 ENUMLOGFONTEXDVA lfex;
4711 HFONT hfont;
4713 if (!pCreateFontIndirectExA)
4715 win_skip("CreateFontIndirectExA is not available\n");
4716 return;
4719 if (!is_truetype_font_installed("Arial"))
4721 skip("Arial is not installed\n");
4722 return;
4725 SetLastError(0xdeadbeef);
4726 hfont = pCreateFontIndirectExA(NULL);
4727 ok(hfont == NULL, "got %p\n", hfont);
4728 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4730 memset(&lfex, 0, sizeof(lfex));
4731 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
4732 hfont = pCreateFontIndirectExA(&lfex);
4733 ok(hfont != 0, "CreateFontIndirectEx failed\n");
4734 if (hfont)
4735 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
4736 DeleteObject(hfont);
4739 static void free_font(void *font)
4741 UnmapViewOfFile(font);
4744 static void *load_font(const char *font_name, DWORD *font_size)
4746 char file_name[MAX_PATH];
4747 HANDLE file, mapping;
4748 void *font;
4750 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
4751 strcat(file_name, "\\fonts\\");
4752 strcat(file_name, font_name);
4754 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4755 if (file == INVALID_HANDLE_VALUE) return NULL;
4757 *font_size = GetFileSize(file, NULL);
4759 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4760 if (!mapping)
4762 CloseHandle(file);
4763 return NULL;
4766 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4768 CloseHandle(file);
4769 CloseHandle(mapping);
4770 return font;
4773 static void test_AddFontMemResource(void)
4775 void *font;
4776 DWORD font_size, num_fonts;
4777 HANDLE ret;
4778 BOOL bRet;
4780 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4782 win_skip("AddFontMemResourceEx is not available on this platform\n");
4783 return;
4786 font = load_font("sserife.fon", &font_size);
4787 if (!font)
4789 skip("Unable to locate and load font sserife.fon\n");
4790 return;
4793 SetLastError(0xdeadbeef);
4794 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4795 ok(!ret, "AddFontMemResourceEx should fail\n");
4796 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4797 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4798 GetLastError());
4800 SetLastError(0xdeadbeef);
4801 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4802 ok(!ret, "AddFontMemResourceEx should fail\n");
4803 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4804 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4805 GetLastError());
4807 SetLastError(0xdeadbeef);
4808 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4809 ok(!ret, "AddFontMemResourceEx should fail\n");
4810 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4811 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4812 GetLastError());
4814 SetLastError(0xdeadbeef);
4815 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4816 ok(!ret, "AddFontMemResourceEx should fail\n");
4817 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4818 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4819 GetLastError());
4821 SetLastError(0xdeadbeef);
4822 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4823 ok(!ret, "AddFontMemResourceEx should fail\n");
4824 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4825 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4826 GetLastError());
4828 SetLastError(0xdeadbeef);
4829 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4830 ok(!ret, "AddFontMemResourceEx should fail\n");
4831 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4832 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4833 GetLastError());
4835 num_fonts = 0xdeadbeef;
4836 SetLastError(0xdeadbeef);
4837 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4838 ok(!ret, "AddFontMemResourceEx should fail\n");
4839 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4840 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4841 GetLastError());
4842 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4844 if (0) /* hangs under windows 2000 */
4846 num_fonts = 0xdeadbeef;
4847 SetLastError(0xdeadbeef);
4848 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4849 ok(!ret, "AddFontMemResourceEx should fail\n");
4850 ok(GetLastError() == 0xdeadbeef,
4851 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4852 GetLastError());
4853 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4856 num_fonts = 0xdeadbeef;
4857 SetLastError(0xdeadbeef);
4858 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4859 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4860 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4861 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4863 free_font(font);
4865 SetLastError(0xdeadbeef);
4866 bRet = pRemoveFontMemResourceEx(ret);
4867 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4869 /* test invalid pointer to number of loaded fonts */
4870 font = load_font("sserife.fon", &font_size);
4871 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4873 SetLastError(0xdeadbeef);
4874 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4875 ok(!ret, "AddFontMemResourceEx should fail\n");
4876 ok(GetLastError() == 0xdeadbeef,
4877 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4878 GetLastError());
4880 SetLastError(0xdeadbeef);
4881 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4882 ok(!ret, "AddFontMemResourceEx should fail\n");
4883 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4884 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4885 GetLastError());
4887 free_font(font);
4890 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4892 LOGFONTA *lf;
4894 if (type != TRUETYPE_FONTTYPE) return 1;
4896 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4898 lf = (LOGFONTA *)lparam;
4899 *lf = *elf;
4900 return 0;
4903 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4905 int ret;
4906 LOGFONTA *lf;
4908 if (type != TRUETYPE_FONTTYPE) return 1;
4910 lf = (LOGFONTA *)lparam;
4911 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
4912 if(ret == 0)
4914 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4915 *lf = *elf;
4916 return 0;
4918 return 1;
4921 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4923 return lparam;
4926 static void test_EnumFonts(void)
4928 int ret;
4929 LOGFONTA lf;
4930 HDC hdc;
4932 if (!is_truetype_font_installed("Arial"))
4934 skip("Arial is not installed\n");
4935 return;
4938 /* Windows uses localized font face names, so Arial Bold won't be found */
4939 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4941 skip("User locale is not English, skipping the test\n");
4942 return;
4945 hdc = CreateCompatibleDC(0);
4947 /* check that the enumproc's retval is returned */
4948 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4949 ok(ret == 0xcafe, "got %08x\n", ret);
4951 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4952 ok(!ret, "font Arial is not enumerated\n");
4953 ret = strcmp(lf.lfFaceName, "Arial");
4954 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4955 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4957 strcpy(lf.lfFaceName, "Arial");
4958 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4959 ok(!ret, "font Arial is not enumerated\n");
4960 ret = strcmp(lf.lfFaceName, "Arial");
4961 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4962 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4964 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4965 ok(!ret, "font Arial Bold is not enumerated\n");
4966 ret = strcmp(lf.lfFaceName, "Arial");
4967 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4968 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4970 strcpy(lf.lfFaceName, "Arial Bold");
4971 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4972 ok(ret, "font Arial Bold should not be enumerated\n");
4974 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4975 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4976 ret = strcmp(lf.lfFaceName, "Arial");
4977 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4978 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4980 strcpy(lf.lfFaceName, "Arial Bold Italic");
4981 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4982 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4984 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4985 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4987 strcpy(lf.lfFaceName, "Arial Italic Bold");
4988 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4989 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4991 DeleteDC(hdc);
4994 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4996 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
4998 if (0) /* Disabled to limit console spam */
4999 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5000 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5002 if (type != TRUETYPE_FONTTYPE) return 1;
5003 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1;
5005 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5006 return 0;
5009 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5011 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5013 if (0) /* Disabled to limit console spam */
5014 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5015 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5017 if (type != TRUETYPE_FONTTYPE) return 1;
5018 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1;
5020 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5021 return 0;
5024 static void test_EnumFonts_subst(void)
5026 int ret;
5027 LOGFONTA lf;
5028 HDC hdc;
5029 struct enum_fullname_data efnd;
5031 ret = is_font_installed("MS Shell Dlg");
5032 ok(ret, "MS Shell Dlg should be enumerated\n");
5033 ret = is_truetype_font_installed("MS Shell Dlg");
5034 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n");
5036 ret = is_font_installed("MS Shell Dlg 2");
5037 ok(ret, "MS Shell Dlg 2 should be enumerated\n");
5038 ret = is_truetype_font_installed("MS Shell Dlg 2");
5039 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5041 hdc = CreateCompatibleDC(0);
5043 memset(&efnd, 0, sizeof(efnd));
5044 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5045 ok(ret, "MS Shell Dlg should not be enumerated\n");
5046 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n");
5048 memset(&lf, 0, sizeof(lf));
5049 lf.lfCharSet = DEFAULT_CHARSET;
5051 memset(&efnd, 0, sizeof(efnd));
5052 strcpy(lf.lfFaceName, "MS Shell Dlg");
5053 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5054 ok(!ret, "MS Shell Dlg should be enumerated\n");
5055 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n");
5056 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
5057 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5058 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg");
5059 ok(ret, "did not expect MS Shell Dlg\n");
5061 memset(&efnd, 0, sizeof(efnd));
5062 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5063 ok(ret, "MS Shell Dlg 2 should not be enumerated\n");
5064 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n");
5066 memset(&efnd, 0, sizeof(efnd));
5067 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
5068 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5069 ok(!ret, "MS Shell Dlg 2 should be enumerated\n");
5070 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n");
5071 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
5072 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5073 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
5074 ok(ret, "did not expect MS Shell Dlg 2\n");
5076 DeleteDC(hdc);
5079 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5081 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
5082 const char *fullname = (const char *)lParam;
5084 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
5086 return 1;
5089 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
5091 HDC hdc = GetDC(0);
5092 BOOL ret = FALSE;
5094 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
5095 ret = TRUE;
5097 ReleaseDC(0, hdc);
5098 return ret;
5101 static void test_fullname(void)
5103 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5104 WCHAR bufW[LF_FULLFACESIZE];
5105 char bufA[LF_FULLFACESIZE];
5106 HFONT hfont, of;
5107 LOGFONTA lf;
5108 HDC hdc;
5109 int i;
5110 DWORD ret;
5112 hdc = CreateCompatibleDC(0);
5113 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5115 memset(&lf, 0, sizeof(lf));
5116 lf.lfCharSet = ANSI_CHARSET;
5117 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5118 lf.lfHeight = 16;
5119 lf.lfWidth = 16;
5120 lf.lfQuality = DEFAULT_QUALITY;
5121 lf.lfItalic = FALSE;
5122 lf.lfWeight = FW_DONTCARE;
5124 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
5126 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
5128 skip("%s is not installed\n", TestName[i]);
5129 continue;
5132 lstrcpyA(lf.lfFaceName, TestName[i]);
5133 hfont = CreateFontIndirectA(&lf);
5134 ok(hfont != 0, "CreateFontIndirectA failed\n");
5136 of = SelectObject(hdc, hfont);
5137 bufW[0] = 0;
5138 bufA[0] = 0;
5139 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
5140 ok(ret, "face full name could not be read\n");
5141 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
5142 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
5143 SelectObject(hdc, of);
5144 DeleteObject(hfont);
5146 DeleteDC(hdc);
5149 static WCHAR *prepend_at(WCHAR *family)
5151 if (!family)
5152 return NULL;
5154 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
5155 family[0] = '@';
5156 return family;
5159 static void test_fullname2_helper(const char *Family)
5161 char *FamilyName, *FaceName, *StyleName, *otmStr;
5162 struct enum_fullname_data efnd;
5163 WCHAR *bufW;
5164 char *bufA;
5165 HFONT hfont, of;
5166 LOGFONTA lf;
5167 HDC hdc;
5168 int i;
5169 DWORD otm_size, ret, buf_size;
5170 OUTLINETEXTMETRICA *otm;
5171 BOOL want_vertical, get_vertical;
5172 want_vertical = ( Family[0] == '@' );
5174 hdc = CreateCompatibleDC(0);
5175 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5177 memset(&lf, 0, sizeof(lf));
5178 lf.lfCharSet = DEFAULT_CHARSET;
5179 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5180 lf.lfHeight = 16;
5181 lf.lfWidth = 16;
5182 lf.lfQuality = DEFAULT_QUALITY;
5183 lf.lfItalic = FALSE;
5184 lf.lfWeight = FW_DONTCARE;
5185 strcpy(lf.lfFaceName, Family);
5186 efnd.total = 0;
5187 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
5188 if (efnd.total == 0)
5189 skip("%s is not installed\n", lf.lfFaceName);
5191 for (i = 0; i < efnd.total; i++)
5193 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
5194 FaceName = (char *)efnd.elf[i].elfFullName;
5195 StyleName = (char *)efnd.elf[i].elfStyle;
5197 get_vertical = ( FamilyName[0] == '@' );
5198 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
5200 lstrcpyA(lf.lfFaceName, FaceName);
5201 hfont = CreateFontIndirectA(&lf);
5202 ok(hfont != 0, "CreateFontIndirectA failed\n");
5204 of = SelectObject(hdc, hfont);
5205 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
5206 ok(buf_size != GDI_ERROR, "no name table found\n");
5207 if (buf_size == GDI_ERROR) continue;
5209 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
5210 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
5212 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5213 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5214 memset(otm, 0, otm_size);
5215 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
5216 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
5217 if (ret == 0) continue;
5219 bufW[0] = 0;
5220 bufA[0] = 0;
5221 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
5222 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5223 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
5224 if (want_vertical) bufW = prepend_at(bufW);
5225 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5226 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
5227 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
5228 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
5230 bufW[0] = 0;
5231 bufA[0] = 0;
5232 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
5233 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5234 ok(ret, "FULL_NAME (face name) could not be read\n");
5235 if (want_vertical) bufW = prepend_at(bufW);
5236 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5237 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
5238 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
5239 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
5241 bufW[0] = 0;
5242 bufA[0] = 0;
5243 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
5244 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5245 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
5246 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5247 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
5248 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
5249 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
5251 bufW[0] = 0;
5252 bufA[0] = 0;
5253 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
5254 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5255 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
5256 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5257 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
5258 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
5260 SelectObject(hdc, of);
5261 DeleteObject(hfont);
5263 HeapFree(GetProcessHeap(), 0, otm);
5264 HeapFree(GetProcessHeap(), 0, bufW);
5265 HeapFree(GetProcessHeap(), 0, bufA);
5267 DeleteDC(hdc);
5270 static void test_fullname2(void)
5272 test_fullname2_helper("Arial");
5273 test_fullname2_helper("DejaVu Sans");
5274 test_fullname2_helper("Lucida Sans");
5275 test_fullname2_helper("Tahoma");
5276 test_fullname2_helper("Webdings");
5277 test_fullname2_helper("Wingdings");
5278 test_fullname2_helper("SimSun");
5279 test_fullname2_helper("NSimSun");
5280 test_fullname2_helper("MingLiu");
5281 test_fullname2_helper("PMingLiu");
5282 test_fullname2_helper("WenQuanYi Micro Hei");
5283 test_fullname2_helper("MS UI Gothic");
5284 test_fullname2_helper("Ume UI Gothic");
5285 test_fullname2_helper("MS Gothic");
5286 test_fullname2_helper("Ume Gothic");
5287 test_fullname2_helper("MS PGothic");
5288 test_fullname2_helper("Ume P Gothic");
5289 test_fullname2_helper("Gulim");
5290 test_fullname2_helper("Batang");
5291 test_fullname2_helper("UnBatang");
5292 test_fullname2_helper("UnDotum");
5293 test_fullname2_helper("@SimSun");
5294 test_fullname2_helper("@NSimSun");
5295 test_fullname2_helper("@MingLiu");
5296 test_fullname2_helper("@PMingLiu");
5297 test_fullname2_helper("@WenQuanYi Micro Hei");
5298 test_fullname2_helper("@MS UI Gothic");
5299 test_fullname2_helper("@Ume UI Gothic");
5300 test_fullname2_helper("@MS Gothic");
5301 test_fullname2_helper("@Ume Gothic");
5302 test_fullname2_helper("@MS PGothic");
5303 test_fullname2_helper("@Ume P Gothic");
5304 test_fullname2_helper("@Gulim");
5305 test_fullname2_helper("@Batang");
5306 test_fullname2_helper("@UnBatang");
5307 test_fullname2_helper("@UnDotum");
5311 static void test_GetGlyphOutline_empty_contour(void)
5313 HDC hdc;
5314 LOGFONTA lf;
5315 HFONT hfont, hfont_prev;
5316 TTPOLYGONHEADER *header;
5317 GLYPHMETRICS gm;
5318 char buf[1024];
5319 DWORD ret;
5321 memset(&lf, 0, sizeof(lf));
5322 lf.lfHeight = 72;
5323 lstrcpyA(lf.lfFaceName, "wine_test");
5325 hfont = CreateFontIndirectA(&lf);
5326 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5328 hdc = GetDC(NULL);
5330 hfont_prev = SelectObject(hdc, hfont);
5331 ok(hfont_prev != NULL, "SelectObject failed\n");
5333 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5334 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5336 header = (TTPOLYGONHEADER*)buf;
5337 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5338 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5339 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5340 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5341 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5342 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5343 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5344 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5346 SelectObject(hdc, hfont_prev);
5347 DeleteObject(hfont);
5348 ReleaseDC(NULL, hdc);
5351 static void test_GetGlyphOutline_metric_clipping(void)
5353 HDC hdc;
5354 LOGFONTA lf;
5355 HFONT hfont, hfont_prev;
5356 GLYPHMETRICS gm;
5357 TEXTMETRICA tm;
5358 TEXTMETRICW tmW;
5359 DWORD ret;
5361 memset(&lf, 0, sizeof(lf));
5362 lf.lfHeight = 72;
5363 lstrcpyA(lf.lfFaceName, "wine_test");
5365 SetLastError(0xdeadbeef);
5366 hfont = CreateFontIndirectA(&lf);
5367 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5369 hdc = GetDC(NULL);
5371 hfont_prev = SelectObject(hdc, hfont);
5372 ok(hfont_prev != NULL, "SelectObject failed\n");
5374 SetLastError(0xdeadbeef);
5375 ret = GetTextMetricsA(hdc, &tm);
5376 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5378 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5379 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5380 "Glyph top(%d) exceeds ascent(%d)\n",
5381 gm.gmptGlyphOrigin.y, tm.tmAscent);
5382 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5383 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5384 "Glyph bottom(%d) exceeds descent(%d)\n",
5385 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5387 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5388 GetTextMetricsW(hdc, &tmW);
5389 todo_wine
5390 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5392 SelectObject(hdc, hfont_prev);
5393 DeleteObject(hfont);
5394 ReleaseDC(NULL, hdc);
5397 static void test_CreateScalableFontResource(void)
5399 char ttf_name[MAX_PATH];
5400 char tmp_path[MAX_PATH];
5401 char fot_name[MAX_PATH];
5402 char *file_part;
5403 DWORD ret;
5404 int i;
5406 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5408 win_skip("AddFontResourceExA is not available on this platform\n");
5409 return;
5412 if (!write_ttf_file("wine_test.ttf", ttf_name))
5414 skip("Failed to create ttf file for testing\n");
5415 return;
5418 trace("created %s\n", ttf_name);
5420 ret = is_truetype_font_installed("wine_test");
5421 ok(!ret, "font wine_test should not be enumerated\n");
5423 ret = GetTempPathA(MAX_PATH, tmp_path);
5424 ok(ret, "GetTempPath() error %d\n", GetLastError());
5425 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5426 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5428 ret = GetFileAttributesA(fot_name);
5429 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5431 SetLastError(0xdeadbeef);
5432 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5433 ok(!ret, "CreateScalableFontResource() should fail\n");
5434 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5436 SetLastError(0xdeadbeef);
5437 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5438 ok(!ret, "CreateScalableFontResource() should fail\n");
5439 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5441 file_part = strrchr(ttf_name, '\\');
5442 SetLastError(0xdeadbeef);
5443 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5444 ok(!ret, "CreateScalableFontResource() should fail\n");
5445 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5447 SetLastError(0xdeadbeef);
5448 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5449 ok(!ret, "CreateScalableFontResource() should fail\n");
5450 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5452 SetLastError(0xdeadbeef);
5453 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5454 ok(!ret, "CreateScalableFontResource() should fail\n");
5455 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5457 ret = DeleteFileA(fot_name);
5458 ok(ret, "DeleteFile() error %d\n", GetLastError());
5460 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5461 ok(!ret, "RemoveFontResourceEx() should fail\n");
5463 /* test public font resource */
5464 SetLastError(0xdeadbeef);
5465 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5466 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5468 ret = is_truetype_font_installed("wine_test");
5469 ok(!ret, "font wine_test should not be enumerated\n");
5471 SetLastError(0xdeadbeef);
5472 ret = pAddFontResourceExA(fot_name, 0, 0);
5473 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5475 ret = is_truetype_font_installed("wine_test");
5476 ok(ret, "font wine_test should be enumerated\n");
5478 test_GetGlyphOutline_empty_contour();
5479 test_GetGlyphOutline_metric_clipping();
5481 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5482 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5484 SetLastError(0xdeadbeef);
5485 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5486 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5488 ret = is_truetype_font_installed("wine_test");
5489 ok(!ret, "font wine_test should not be enumerated\n");
5491 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5492 ok(!ret, "RemoveFontResourceEx() should fail\n");
5494 /* test refcounting */
5495 for (i = 0; i < 5; i++)
5497 SetLastError(0xdeadbeef);
5498 ret = pAddFontResourceExA(fot_name, 0, 0);
5499 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5501 for (i = 0; i < 5; i++)
5503 SetLastError(0xdeadbeef);
5504 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5505 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5507 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5508 ok(!ret, "RemoveFontResourceEx() should fail\n");
5510 DeleteFileA(fot_name);
5512 /* test hidden font resource */
5513 SetLastError(0xdeadbeef);
5514 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5515 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5517 ret = is_truetype_font_installed("wine_test");
5518 ok(!ret, "font wine_test should not be enumerated\n");
5520 SetLastError(0xdeadbeef);
5521 ret = pAddFontResourceExA(fot_name, 0, 0);
5522 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5524 ret = is_truetype_font_installed("wine_test");
5525 todo_wine
5526 ok(!ret, "font wine_test should not be enumerated\n");
5528 /* XP allows removing a private font added with 0 flags */
5529 SetLastError(0xdeadbeef);
5530 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5531 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5533 ret = is_truetype_font_installed("wine_test");
5534 ok(!ret, "font wine_test should not be enumerated\n");
5536 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5537 ok(!ret, "RemoveFontResourceEx() should fail\n");
5539 DeleteFileA(fot_name);
5540 DeleteFileA(ttf_name);
5543 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5545 LOGFONTA lf;
5546 HFONT hfont, hfont_prev;
5547 HDC hdc;
5548 char facename[100];
5549 DWORD ret;
5550 static const WCHAR str[] = { 0x2025 };
5552 *installed = is_truetype_font_installed(name);
5554 lf.lfHeight = -18;
5555 lf.lfWidth = 0;
5556 lf.lfEscapement = 0;
5557 lf.lfOrientation = 0;
5558 lf.lfWeight = FW_DONTCARE;
5559 lf.lfItalic = 0;
5560 lf.lfUnderline = 0;
5561 lf.lfStrikeOut = 0;
5562 lf.lfCharSet = DEFAULT_CHARSET;
5563 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5564 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5565 lf.lfQuality = DEFAULT_QUALITY;
5566 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5567 strcpy(lf.lfFaceName, name);
5569 hfont = CreateFontIndirectA(&lf);
5570 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5572 hdc = GetDC(NULL);
5574 hfont_prev = SelectObject(hdc, hfont);
5575 ok(hfont_prev != NULL, "SelectObject failed\n");
5577 ret = GetTextFaceA(hdc, sizeof facename, facename);
5578 ok(ret, "GetTextFaceA failed\n");
5579 *selected = !strcmp(facename, name);
5581 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5582 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5583 if (!*selected)
5584 memset(gm, 0, sizeof *gm);
5586 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5587 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5589 SelectObject(hdc, hfont_prev);
5590 DeleteObject(hfont);
5591 ReleaseDC(NULL, hdc);
5594 static void check_vertical_metrics(const char *face)
5596 LOGFONTA lf;
5597 HFONT hfont, hfont_prev;
5598 HDC hdc;
5599 DWORD ret;
5600 GLYPHMETRICS rgm, vgm;
5601 const UINT code = 0x5EAD, height = 1000;
5602 WORD idx;
5603 ABC abc;
5604 OUTLINETEXTMETRICA otm;
5605 USHORT numOfLongVerMetrics;
5607 hdc = GetDC(NULL);
5609 memset(&lf, 0, sizeof(lf));
5610 strcpy(lf.lfFaceName, face);
5611 lf.lfHeight = -height;
5612 lf.lfCharSet = DEFAULT_CHARSET;
5613 lf.lfEscapement = lf.lfOrientation = 900;
5614 hfont = CreateFontIndirectA(&lf);
5615 hfont_prev = SelectObject(hdc, hfont);
5616 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5617 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5618 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5619 ok(ret, "GetCharABCWidthsW failed\n");
5620 DeleteObject(SelectObject(hdc, hfont_prev));
5622 memset(&lf, 0, sizeof(lf));
5623 strcpy(lf.lfFaceName, "@");
5624 strcat(lf.lfFaceName, face);
5625 lf.lfHeight = -height;
5626 lf.lfCharSet = DEFAULT_CHARSET;
5627 hfont = CreateFontIndirectA(&lf);
5628 hfont_prev = SelectObject(hdc, hfont);
5629 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5630 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5632 memset(&otm, 0, sizeof(otm));
5633 otm.otmSize = sizeof(otm);
5634 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5635 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5637 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5638 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5639 int offset;
5640 SHORT topSideBearing;
5642 if (!pGetGlyphIndicesW) {
5643 win_skip("GetGlyphIndices is not available on this platform\n");
5645 else {
5646 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5647 ok(ret != 0, "GetGlyphIndicesW failed\n");
5648 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5649 if (numOfLongVerMetrics > idx)
5650 offset = idx * 2 + 1;
5651 else
5652 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5653 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5654 &topSideBearing, sizeof(SHORT));
5655 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5656 topSideBearing = GET_BE_WORD(topSideBearing);
5657 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5658 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5659 "expected %d, got %d\n",
5660 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5663 else
5665 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5666 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5667 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5670 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
5671 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
5672 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5673 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
5675 DeleteObject(SelectObject(hdc, hfont_prev));
5676 ReleaseDC(NULL, hdc);
5679 static void test_vertical_font(void)
5681 char ttf_name[MAX_PATH];
5682 int num, i;
5683 BOOL ret, installed, selected;
5684 GLYPHMETRICS gm;
5685 WORD hgi, vgi;
5686 const char* face_list[] = {
5687 "@WineTestVertical", /* has vmtx table */
5688 "@Ume Gothic", /* doesn't have vmtx table */
5689 "@MS UI Gothic", /* has vmtx table, available on native */
5692 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
5694 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5695 return;
5698 if (!write_ttf_file("vertical.ttf", ttf_name))
5700 skip("Failed to create ttf file for testing\n");
5701 return;
5704 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
5705 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5707 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
5708 ok(installed, "WineTestVertical is not installed\n");
5709 ok(selected, "WineTestVertical is not selected\n");
5710 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5711 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5712 gm.gmBlackBoxX, gm.gmBlackBoxY);
5714 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
5715 ok(installed, "@WineTestVertical is not installed\n");
5716 ok(selected, "@WineTestVertical is not selected\n");
5717 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5718 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5719 gm.gmBlackBoxX, gm.gmBlackBoxY);
5721 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
5723 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
5724 const char* face = face_list[i];
5725 if (!is_truetype_font_installed(face)) {
5726 skip("%s is not installed\n", face);
5727 continue;
5729 trace("Testing %s...\n", face);
5730 check_vertical_metrics(&face[1]);
5733 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
5734 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5736 DeleteFileA(ttf_name);
5739 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
5740 DWORD type, LPARAM lParam)
5742 if (lf->lfFaceName[0] == '@') {
5743 return 0;
5745 return 1;
5748 static void test_east_asian_font_selection(void)
5750 HDC hdc;
5751 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
5752 GB2312_CHARSET, CHINESEBIG5_CHARSET };
5753 size_t i;
5755 hdc = GetDC(NULL);
5757 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
5759 LOGFONTA lf;
5760 HFONT hfont;
5761 char face_name[LF_FACESIZE];
5762 int ret;
5764 memset(&lf, 0, sizeof lf);
5765 lf.lfFaceName[0] = '\0';
5766 lf.lfCharSet = charset[i];
5768 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
5770 skip("Vertical font for charset %u is not installed\n", charset[i]);
5771 continue;
5774 hfont = CreateFontIndirectA(&lf);
5775 hfont = SelectObject(hdc, hfont);
5776 memset(face_name, 0, sizeof face_name);
5777 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5778 ok(ret && face_name[0] != '@',
5779 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
5780 DeleteObject(SelectObject(hdc, hfont));
5782 memset(&lf, 0, sizeof lf);
5783 strcpy(lf.lfFaceName, "@");
5784 lf.lfCharSet = charset[i];
5785 hfont = CreateFontIndirectA(&lf);
5786 hfont = SelectObject(hdc, hfont);
5787 memset(face_name, 0, sizeof face_name);
5788 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5789 ok(ret && face_name[0] == '@',
5790 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
5791 DeleteObject(SelectObject(hdc, hfont));
5793 ReleaseDC(NULL, hdc);
5796 static int get_font_dpi(const LOGFONTA *lf, int *height)
5798 HDC hdc = CreateCompatibleDC(0);
5799 HFONT hfont;
5800 TEXTMETRICA tm;
5801 int ret;
5803 hfont = CreateFontIndirectA(lf);
5804 ok(hfont != 0, "CreateFontIndirect failed\n");
5806 SelectObject(hdc, hfont);
5807 ret = GetTextMetricsA(hdc, &tm);
5808 ok(ret, "GetTextMetrics failed\n");
5809 ret = tm.tmDigitizedAspectX;
5810 if (height) *height = tm.tmHeight;
5812 DeleteDC(hdc);
5813 DeleteObject(hfont);
5815 return ret;
5818 static void test_stock_fonts(void)
5820 static const int font[] =
5822 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
5823 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5825 static const struct test_data
5827 int charset, weight, height, height_pixels, dpi;
5828 const char face_name[LF_FACESIZE];
5829 WORD lang_id;
5830 } td[][12] =
5832 { /* ANSI_FIXED_FONT */
5833 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
5834 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
5835 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
5836 { 0 }
5838 { /* ANSI_VAR_FONT */
5839 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
5840 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
5841 { 0 }
5843 { /* SYSTEM_FONT */
5844 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5845 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5846 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5847 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5848 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5849 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5850 { 0 }
5852 { /* DEVICE_DEFAULT_FONT */
5853 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5854 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5855 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5856 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5857 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5858 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5859 { 0 }
5861 { /* DEFAULT_GUI_FONT */
5862 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5863 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
5864 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
5865 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
5866 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
5867 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
5868 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
5869 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
5870 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
5871 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5872 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
5873 { 0 }
5876 int i, j;
5878 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
5880 HFONT hfont;
5881 LOGFONTA lf;
5882 int ret, height;
5884 hfont = GetStockObject(font[i]);
5885 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
5887 ret = GetObjectA(hfont, sizeof(lf), &lf);
5888 if (ret != sizeof(lf))
5890 /* NT4 */
5891 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
5892 continue;
5895 for (j = 0; td[i][j].face_name[0] != 0; j++)
5897 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) ||
5898 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) ||
5899 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name)))
5901 continue;
5904 ret = get_font_dpi(&lf, &height);
5905 if (ret != td[i][j].dpi)
5907 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5908 i, j, lf.lfFaceName, ret, td[i][j].dpi);
5909 continue;
5912 /* FIXME: Remove once Wine is fixed */
5913 if (td[i][j].dpi != 96 &&
5914 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5915 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
5916 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5917 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
5918 todo_wine
5919 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5920 else
5921 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5923 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
5924 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
5925 if (td[i][j].face_name[0] == '?')
5927 /* Wine doesn't have this font, skip this case for now.
5928 Actually, the face name is localized on Windows and varies
5929 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5930 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
5932 else
5934 ok(!strcmp(td[i][j].face_name, lf.lfFaceName), "%d(%d): expected lfFaceName %s, got %s\n", i, j, td[i][j].face_name, lf.lfFaceName);
5936 break;
5941 static void test_max_height(void)
5943 HDC hdc;
5944 LOGFONTA lf;
5945 HFONT hfont, hfont_old;
5946 TEXTMETRICA tm1, tm;
5947 BOOL r;
5948 LONG invalid_height[] = { -65536, -123456, 123456 };
5949 size_t i;
5951 memset(&tm1, 0, sizeof(tm1));
5952 memset(&lf, 0, sizeof(lf));
5953 strcpy(lf.lfFaceName, "Tahoma");
5954 lf.lfHeight = -1;
5956 hdc = GetDC(NULL);
5958 /* get 1 ppem value */
5959 hfont = CreateFontIndirectA(&lf);
5960 hfont_old = SelectObject(hdc, hfont);
5961 r = GetTextMetricsA(hdc, &tm1);
5962 ok(r, "GetTextMetrics failed\n");
5963 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5964 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5965 DeleteObject(SelectObject(hdc, hfont_old));
5967 /* test the largest value */
5968 lf.lfHeight = -((1 << 16) - 1);
5969 hfont = CreateFontIndirectA(&lf);
5970 hfont_old = SelectObject(hdc, hfont);
5971 memset(&tm, 0, sizeof(tm));
5972 r = GetTextMetricsA(hdc, &tm);
5973 ok(r, "GetTextMetrics failed\n");
5974 ok(tm.tmHeight > tm1.tmHeight,
5975 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5976 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
5977 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5978 DeleteObject(SelectObject(hdc, hfont_old));
5980 /* test an invalid value */
5981 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
5982 lf.lfHeight = invalid_height[i];
5983 hfont = CreateFontIndirectA(&lf);
5984 hfont_old = SelectObject(hdc, hfont);
5985 memset(&tm, 0, sizeof(tm));
5986 r = GetTextMetricsA(hdc, &tm);
5987 ok(r, "GetTextMetrics failed\n");
5988 ok(tm.tmHeight == tm1.tmHeight,
5989 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5990 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
5991 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5992 DeleteObject(SelectObject(hdc, hfont_old));
5995 ReleaseDC(NULL, hdc);
5996 return;
5999 static void test_vertical_order(void)
6001 struct enum_font_data efd;
6002 LOGFONTA lf;
6003 HDC hdc;
6004 int i, j;
6006 hdc = CreateCompatibleDC(0);
6007 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6009 memset(&lf, 0, sizeof(lf));
6010 lf.lfCharSet = DEFAULT_CHARSET;
6011 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6012 lf.lfHeight = 16;
6013 lf.lfWidth = 16;
6014 lf.lfQuality = DEFAULT_QUALITY;
6015 lf.lfItalic = FALSE;
6016 lf.lfWeight = FW_DONTCARE;
6017 efd.total = 0;
6018 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
6019 for (i = 0; i < efd.total; i++)
6021 if (efd.lf[i].lfFaceName[0] != '@') continue;
6022 for (j = 0; j < efd.total; j++)
6024 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
6026 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
6027 break;
6031 DeleteDC( hdc );
6034 static void test_GetCharWidth32(void)
6036 BOOL ret;
6037 HDC hdc;
6038 LOGFONTA lf;
6039 HFONT hfont;
6040 INT bufferA;
6041 INT bufferW;
6042 HWND hwnd;
6044 if (!pGetCharWidth32A || !pGetCharWidth32W)
6046 win_skip("GetCharWidth32A/W not available on this platform\n");
6047 return;
6050 memset(&lf, 0, sizeof(lf));
6051 strcpy(lf.lfFaceName, "System");
6052 lf.lfHeight = 20;
6054 hfont = CreateFontIndirectA(&lf);
6055 hdc = GetDC(0);
6056 hfont = SelectObject(hdc, hfont);
6058 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6059 ok(ret, "GetCharWidth32W should have succeeded\n");
6060 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
6061 ok(ret, "GetCharWidth32A should have succeeded\n");
6062 ok (bufferA == bufferW, "Widths should be the same\n");
6063 ok (bufferA > 0," Width should be greater than zero\n");
6065 hfont = SelectObject(hdc, hfont);
6066 DeleteObject(hfont);
6067 ReleaseDC(NULL, hdc);
6069 memset(&lf, 0, sizeof(lf));
6070 strcpy(lf.lfFaceName, "Tahoma");
6071 lf.lfHeight = 20;
6073 hfont = CreateFontIndirectA(&lf);
6074 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
6075 0, 0, 0, NULL);
6076 hdc = GetDC(hwnd);
6077 SetMapMode( hdc, MM_ANISOTROPIC );
6078 SelectObject(hdc, hfont);
6080 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6081 ok(ret, "GetCharWidth32W should have succeeded\n");
6082 ok (bufferW > 0," Width should be greater than zero\n");
6083 SetWindowExtEx(hdc, -1,-1,NULL);
6084 SetGraphicsMode(hdc, GM_COMPATIBLE);
6085 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6086 ok(ret, "GetCharWidth32W should have succeeded\n");
6087 ok (bufferW > 0," Width should be greater than zero\n");
6088 SetGraphicsMode(hdc, GM_ADVANCED);
6089 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6090 ok(ret, "GetCharWidth32W should have succeeded\n");
6091 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6092 SetWindowExtEx(hdc, 1,1,NULL);
6093 SetGraphicsMode(hdc, GM_COMPATIBLE);
6094 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6095 ok(ret, "GetCharWidth32W should have succeeded\n");
6096 ok (bufferW > 0," Width should be greater than zero\n");
6097 SetGraphicsMode(hdc, GM_ADVANCED);
6098 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6099 ok(ret, "GetCharWidth32W should have succeeded\n");
6100 ok (bufferW > 0," Width should be greater than zero\n");
6102 ReleaseDC(hwnd, hdc);
6103 DestroyWindow(hwnd);
6105 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
6106 0, 0, 0, NULL);
6107 hdc = GetDC(hwnd);
6108 SetMapMode( hdc, MM_ANISOTROPIC );
6109 SelectObject(hdc, hfont);
6111 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6112 ok(ret, "GetCharWidth32W should have succeeded\n");
6113 ok (bufferW > 0," Width should be greater than zero\n");
6114 SetWindowExtEx(hdc, -1,-1,NULL);
6115 SetGraphicsMode(hdc, GM_COMPATIBLE);
6116 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6117 ok(ret, "GetCharWidth32W should have succeeded\n");
6118 ok (bufferW > 0," Width should be greater than zero\n");
6119 SetGraphicsMode(hdc, GM_ADVANCED);
6120 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6121 ok(ret, "GetCharWidth32W should have succeeded\n");
6122 ok (bufferW > 0," Width should be greater than zero\n");
6123 SetWindowExtEx(hdc, 1,1,NULL);
6124 SetGraphicsMode(hdc, GM_COMPATIBLE);
6125 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6126 ok(ret, "GetCharWidth32W should have succeeded\n");
6127 ok (bufferW > 0," Width should be greater than zero\n");
6128 SetGraphicsMode(hdc, GM_ADVANCED);
6129 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6130 ok(ret, "GetCharWidth32W should have succeeded\n");
6131 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6133 ReleaseDC(hwnd, hdc);
6134 DestroyWindow(hwnd);
6135 DeleteObject(hfont);
6138 static void test_fake_bold_font(void)
6140 HDC hdc;
6141 HFONT hfont, hfont_old;
6142 LOGFONTA lf;
6143 BOOL ret;
6144 TEXTMETRICA tm[2];
6145 ABC abc[2];
6146 INT w[2];
6148 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
6149 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6150 return;
6153 /* Test outline font */
6154 memset(&lf, 0, sizeof(lf));
6155 strcpy(lf.lfFaceName, "Wingdings");
6156 lf.lfWeight = FW_NORMAL;
6157 lf.lfCharSet = SYMBOL_CHARSET;
6158 hfont = CreateFontIndirectA(&lf);
6160 hdc = GetDC(NULL);
6161 hfont_old = SelectObject(hdc, hfont);
6163 /* base metrics */
6164 ret = GetTextMetricsA(hdc, &tm[0]);
6165 ok(ret, "got %d\n", ret);
6166 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[0]);
6167 ok(ret, "got %d\n", ret);
6169 lf.lfWeight = FW_BOLD;
6170 hfont = CreateFontIndirectA(&lf);
6171 DeleteObject(SelectObject(hdc, hfont));
6173 /* bold metrics */
6174 ret = GetTextMetricsA(hdc, &tm[1]);
6175 ok(ret, "got %d\n", ret);
6176 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[1]);
6177 ok(ret, "got %d\n", ret);
6179 DeleteObject(SelectObject(hdc, hfont_old));
6180 ReleaseDC(NULL, hdc);
6182 /* compare results (outline) */
6183 ok(tm[0].tmHeight == tm[1].tmHeight, "expected %d, got %d\n", tm[0].tmHeight, tm[1].tmHeight);
6184 ok(tm[0].tmAscent == tm[1].tmAscent, "expected %d, got %d\n", tm[0].tmAscent, tm[1].tmAscent);
6185 ok(tm[0].tmDescent == tm[1].tmDescent, "expected %d, got %d\n", tm[0].tmDescent, tm[1].tmDescent);
6186 ok((tm[0].tmAveCharWidth + 1) == tm[1].tmAveCharWidth,
6187 "expected %d, got %d\n", tm[0].tmAveCharWidth + 1, tm[1].tmAveCharWidth);
6188 ok((tm[0].tmMaxCharWidth + 1) == tm[1].tmMaxCharWidth,
6189 "expected %d, got %d\n", tm[0].tmMaxCharWidth + 1, tm[1].tmMaxCharWidth);
6190 ok(tm[0].tmOverhang == tm[1].tmOverhang, "expected %d, got %d\n", tm[0].tmOverhang, tm[1].tmOverhang);
6191 w[0] = abc[0].abcA + abc[0].abcB + abc[0].abcC;
6192 w[1] = abc[1].abcA + abc[1].abcB + abc[1].abcC;
6193 ok((w[0] + 1) == w[1], "expected %d, got %d\n", w[0] + 1, w[1]);
6197 static void test_bitmap_font_glyph_index(void)
6199 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
6200 const struct {
6201 LPCSTR face;
6202 BYTE charset;
6203 } bitmap_font_list[] = {
6204 { "Courier", ANSI_CHARSET },
6205 { "Small Fonts", ANSI_CHARSET },
6206 { "Fixedsys", DEFAULT_CHARSET },
6207 { "System", DEFAULT_CHARSET }
6209 HDC hdc;
6210 LOGFONTA lf;
6211 HFONT hFont;
6212 CHAR facename[LF_FACESIZE];
6213 BITMAPINFO bmi;
6214 HBITMAP hBmp[2];
6215 void *pixels[2];
6216 int i, j;
6217 DWORD ret;
6218 BITMAP bmp;
6219 TEXTMETRICA tm;
6220 CHARSETINFO ci;
6221 BYTE chr = '\xA9';
6223 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
6224 win_skip("GetGlyphIndices is unavailable\n");
6225 return;
6228 hdc = CreateCompatibleDC(0);
6229 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6231 memset(&bmi, 0, sizeof(bmi));
6232 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
6233 bmi.bmiHeader.biBitCount = 32;
6234 bmi.bmiHeader.biPlanes = 1;
6235 bmi.bmiHeader.biWidth = 128;
6236 bmi.bmiHeader.biHeight = 32;
6237 bmi.bmiHeader.biCompression = BI_RGB;
6239 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
6240 memset(&lf, 0, sizeof(lf));
6241 lf.lfCharSet = bitmap_font_list[i].charset;
6242 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
6243 hFont = CreateFontIndirectA(&lf);
6244 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
6245 hFont = SelectObject(hdc, hFont);
6246 ret = GetTextMetricsA(hdc, &tm);
6247 ok(ret, "GetTextMetric failed\n");
6248 ret = GetTextFaceA(hdc, sizeof(facename), facename);
6249 ok(ret, "GetTextFace failed\n");
6250 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
6251 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
6252 continue;
6254 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
6255 skip("expected %s, got %s\n", lf.lfFaceName, facename);
6256 continue;
6259 for (j = 0; j < 2; j++) {
6260 HBITMAP hBmpPrev;
6261 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
6262 ok(hBmp[j] != NULL, "Can't create DIB\n");
6263 hBmpPrev = SelectObject(hdc, hBmp[j]);
6264 switch (j) {
6265 case 0:
6266 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
6267 break;
6268 case 1:
6270 int len = lstrlenW(text);
6271 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
6272 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
6273 ok(ret, "GetGlyphIndices failed\n");
6274 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
6275 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
6276 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
6277 HeapFree(GetProcessHeap(), 0, indices);
6278 break;
6281 ok(ret, "ExtTextOutW failed\n");
6282 SelectObject(hdc, hBmpPrev);
6285 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
6286 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6287 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6289 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
6290 if (!ret) {
6291 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6292 goto next;
6294 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
6295 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
6296 goto next;
6299 for (j = 0; j < 2; j++) {
6300 HBITMAP hBmpPrev;
6301 WORD code;
6302 hBmpPrev = SelectObject(hdc, hBmp[j]);
6303 switch (j) {
6304 case 0:
6305 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6306 break;
6307 case 1:
6308 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6309 ok(ret, "GetGlyphIndices failed\n");
6310 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6311 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6312 break;
6314 ok(ret, "ExtTextOutA failed\n");
6315 SelectObject(hdc, hBmpPrev);
6318 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6319 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6320 next:
6321 for (j = 0; j < 2; j++)
6322 DeleteObject(hBmp[j]);
6323 hFont = SelectObject(hdc, hFont);
6324 DeleteObject(hFont);
6327 DeleteDC(hdc);
6330 START_TEST(font)
6332 init();
6334 test_stock_fonts();
6335 test_logfont();
6336 test_bitmap_font();
6337 test_outline_font();
6338 test_bitmap_font_metrics();
6339 test_GdiGetCharDimensions();
6340 test_GetCharABCWidths();
6341 test_text_extents();
6342 test_GetGlyphIndices();
6343 test_GetKerningPairs();
6344 test_GetOutlineTextMetrics();
6345 test_SetTextJustification();
6346 test_font_charset();
6347 test_GdiGetCodePage();
6348 test_GetFontUnicodeRanges();
6349 test_nonexistent_font();
6350 test_orientation();
6351 test_height_selection();
6352 test_AddFontMemResource();
6353 test_EnumFonts();
6354 test_EnumFonts_subst();
6356 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6357 * I'd like to avoid them in this test.
6359 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6360 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6361 if (is_truetype_font_installed("Arial Black") &&
6362 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6364 test_EnumFontFamilies("", ANSI_CHARSET);
6365 test_EnumFontFamilies("", SYMBOL_CHARSET);
6366 test_EnumFontFamilies("", DEFAULT_CHARSET);
6368 else
6369 skip("Arial Black or Symbol/Wingdings is not installed\n");
6370 test_EnumFontFamiliesEx_default_charset();
6371 test_GetTextMetrics();
6372 test_GdiRealizationInfo();
6373 test_GetTextFace();
6374 test_GetGlyphOutline();
6375 test_GetTextMetrics2("Tahoma", -11);
6376 test_GetTextMetrics2("Tahoma", -55);
6377 test_GetTextMetrics2("Tahoma", -110);
6378 test_GetTextMetrics2("Arial", -11);
6379 test_GetTextMetrics2("Arial", -55);
6380 test_GetTextMetrics2("Arial", -110);
6381 test_CreateFontIndirect();
6382 test_CreateFontIndirectEx();
6383 test_oemcharset();
6384 test_fullname();
6385 test_fullname2();
6386 test_east_asian_font_selection();
6387 test_max_height();
6388 test_vertical_order();
6389 test_GetCharWidth32();
6390 test_fake_bold_font();
6391 test_bitmap_font_glyph_index();
6393 /* These tests should be last test until RemoveFontResource
6394 * is properly implemented.
6396 test_vertical_font();
6397 test_CreateScalableFontResource();