gdi32: Treat lpResults as optional in GetCharacterPlacement.
[wine.git] / dlls / gdi32 / tests / font.c
blob0d0770905d590e56fe07b8a712b74404d114ffc8
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/heap.h"
32 #include "wine/test.h"
34 static inline BOOL match_off_by_n(int a, int b, unsigned int n)
36 return abs(a - b) <= n;
38 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
39 #define near_match(a, b) match_off_by_n((a), (b), 6)
40 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
42 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
43 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
44 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
45 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
46 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
47 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
48 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
49 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
50 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
51 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
52 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
53 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
54 LPINT nfit, LPINT dxs, LPSIZE size );
55 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
56 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
57 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
58 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
59 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
60 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
61 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
62 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *);
63 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
65 static HMODULE hgdi32 = 0;
66 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
67 static WORD system_lang_id;
69 #ifdef WORDS_BIGENDIAN
70 #define GET_BE_WORD(x) (x)
71 #define GET_BE_DWORD(x) (x)
72 #else
73 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
74 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
75 #endif
77 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
78 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
79 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
80 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
81 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
82 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
84 static void init(void)
86 hgdi32 = GetModuleHandleA("gdi32.dll");
88 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
89 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
90 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
91 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
92 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
93 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
94 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
95 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
96 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
97 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
98 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
99 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
100 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
101 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
102 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
103 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
104 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
105 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
106 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
107 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
108 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
110 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
113 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
115 if (type != TRUETYPE_FONTTYPE) return 1;
117 return 0;
120 static BOOL is_truetype_font_installed(const char *name)
122 HDC hdc = GetDC(0);
123 BOOL ret = FALSE;
125 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
126 ret = TRUE;
128 ReleaseDC(0, hdc);
129 return ret;
132 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
134 return 0;
137 static BOOL is_font_installed(const char *name)
139 HDC hdc = GetDC(0);
140 BOOL ret = FALSE;
142 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
143 ret = TRUE;
145 ReleaseDC(0, hdc);
146 return ret;
149 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
151 HRSRC rsrc;
152 void *rsrc_data;
154 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
155 if (!rsrc) return NULL;
157 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
158 if (!rsrc_data) return NULL;
160 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
161 if (!*rsrc_size) return NULL;
163 return rsrc_data;
166 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
168 char tmp_path[MAX_PATH];
169 HANDLE hfile;
170 BOOL ret;
172 GetTempPathA(MAX_PATH, tmp_path);
173 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
175 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
176 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
178 ret = WriteFile(hfile, data, *size, size, NULL);
180 CloseHandle(hfile);
181 return ret;
184 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
186 void *rsrc_data;
187 DWORD rsrc_size;
189 rsrc_data = get_res_data( fontname, &rsrc_size );
190 if (!rsrc_data) return FALSE;
192 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
195 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
197 LOGFONTA getobj_lf;
198 int ret, minlen = 0;
200 if (!hfont)
201 return;
203 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
204 /* NT4 tries to be clever and only returns the minimum length */
205 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
206 minlen++;
207 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
208 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
209 ok(lf->lfHeight == getobj_lf.lfHeight ||
210 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
211 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
212 ok(lf->lfWidth == getobj_lf.lfWidth ||
213 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
214 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
215 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
216 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
217 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
218 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
219 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
220 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
221 ok(lf->lfWeight == getobj_lf.lfWeight ||
222 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
223 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
224 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
225 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
226 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
227 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
228 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
229 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
230 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
231 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
232 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
233 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
234 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
237 static HFONT create_font(const char* test, const LOGFONTA* lf)
239 HFONT hfont = CreateFontIndirectA(lf);
240 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
241 if (hfont)
242 check_font(test, lf, hfont);
243 return hfont;
246 static void test_logfont(void)
248 LOGFONTA lf;
249 HFONT hfont;
251 memset(&lf, 0, sizeof lf);
253 lf.lfCharSet = ANSI_CHARSET;
254 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
255 lf.lfWeight = FW_DONTCARE;
256 lf.lfHeight = 16;
257 lf.lfWidth = 16;
258 lf.lfQuality = DEFAULT_QUALITY;
260 lstrcpyA(lf.lfFaceName, "Arial");
261 hfont = create_font("Arial", &lf);
262 DeleteObject(hfont);
264 memset(&lf, 'A', sizeof(lf));
265 hfont = CreateFontIndirectA(&lf);
266 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
268 lf.lfFaceName[LF_FACESIZE - 1] = 0;
269 check_font("AAA...", &lf, hfont);
270 DeleteObject(hfont);
273 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
275 if (type & RASTER_FONTTYPE)
277 LOGFONTA *lf = (LOGFONTA *)lParam;
278 *lf = *elf;
279 return 0; /* stop enumeration */
282 return 1; /* continue enumeration */
285 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
287 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
288 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
289 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
290 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
291 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
292 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
293 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
294 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
295 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
296 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
297 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
298 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
299 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
300 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
301 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
302 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
303 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
304 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
305 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
306 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
309 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
310 LONG lfWidth, const char *test_str,
311 INT test_str_len, const TEXTMETRICA *tm_orig,
312 const SIZE *size_orig, INT width_of_A_orig,
313 INT scale_x, INT scale_y)
315 LOGFONTA lf;
316 OUTLINETEXTMETRICA otm;
317 TEXTMETRICA tm;
318 SIZE size;
319 INT width_of_A, cx, cy;
320 UINT ret;
322 if (!hfont)
323 return;
325 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
327 GetObjectA(hfont, sizeof(lf), &lf);
329 if (GetOutlineTextMetricsA(hdc, 0, NULL))
331 otm.otmSize = sizeof(otm) / 2;
332 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
333 ok(ret == sizeof(otm)/2 /* XP */ ||
334 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
336 memset(&otm, 0x1, sizeof(otm));
337 otm.otmSize = sizeof(otm);
338 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
339 ok(ret == sizeof(otm) /* XP */ ||
340 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
342 memset(&tm, 0x2, sizeof(tm));
343 ret = GetTextMetricsA(hdc, &tm);
344 ok(ret, "GetTextMetricsA failed\n");
345 /* the structure size is aligned */
346 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
348 ok(0, "tm != otm\n");
349 compare_tm(&tm, &otm.otmTextMetrics);
352 tm = otm.otmTextMetrics;
353 if (0) /* these metrics are scaled too, but with rounding errors */
355 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
356 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
358 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
359 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
360 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
361 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
362 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
363 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
365 else
367 ret = GetTextMetricsA(hdc, &tm);
368 ok(ret, "GetTextMetricsA failed\n");
371 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
372 cy = tm.tmHeight / tm_orig->tmHeight;
373 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
374 lfHeight, scale_x, scale_y, cx, cy);
375 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
376 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
377 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
378 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
379 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
381 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
382 if (lf.lfHeight)
384 if (lf.lfWidth)
385 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
387 else
388 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
390 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
392 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
393 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
395 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
397 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);
400 /* Test how GDI scales bitmap font metrics */
401 static void test_bitmap_font(void)
403 static const char test_str[11] = "Test String";
404 HDC hdc;
405 LOGFONTA bitmap_lf;
406 HFONT hfont, old_hfont;
407 TEXTMETRICA tm_orig;
408 SIZE size_orig;
409 INT ret, i, width_orig, height_orig, scale, lfWidth;
411 hdc = CreateCompatibleDC(0);
413 /* "System" has only 1 pixel size defined, otherwise the test breaks */
414 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
415 if (ret)
417 ReleaseDC(0, hdc);
418 trace("no bitmap fonts were found, skipping the test\n");
419 return;
422 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
424 height_orig = bitmap_lf.lfHeight;
425 lfWidth = bitmap_lf.lfWidth;
427 hfont = create_font("bitmap", &bitmap_lf);
428 old_hfont = SelectObject(hdc, hfont);
429 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
430 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
431 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
432 SelectObject(hdc, old_hfont);
433 DeleteObject(hfont);
435 bitmap_lf.lfHeight = 0;
436 bitmap_lf.lfWidth = 4;
437 hfont = create_font("bitmap", &bitmap_lf);
438 old_hfont = SelectObject(hdc, hfont);
439 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
440 SelectObject(hdc, old_hfont);
441 DeleteObject(hfont);
443 bitmap_lf.lfHeight = height_orig;
444 bitmap_lf.lfWidth = lfWidth;
446 /* test fractional scaling */
447 for (i = 1; i <= height_orig * 6; i++)
449 INT nearest_height;
451 bitmap_lf.lfHeight = i;
452 hfont = create_font("fractional", &bitmap_lf);
453 scale = (i + height_orig - 1) / height_orig;
454 nearest_height = scale * height_orig;
455 /* Only jump to the next height if the difference <= 25% original height */
456 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
457 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
458 so we'll not test this particular height. */
459 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
460 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
461 old_hfont = SelectObject(hdc, hfont);
462 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
463 SelectObject(hdc, old_hfont);
464 DeleteObject(hfont);
467 /* test integer scaling 3x2 */
468 bitmap_lf.lfHeight = height_orig * 2;
469 bitmap_lf.lfWidth *= 3;
470 hfont = create_font("3x2", &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, 2);
473 SelectObject(hdc, old_hfont);
474 DeleteObject(hfont);
476 /* test integer scaling 3x3 */
477 bitmap_lf.lfHeight = height_orig * 3;
478 bitmap_lf.lfWidth = 0;
479 hfont = create_font("3x3", &bitmap_lf);
480 old_hfont = SelectObject(hdc, hfont);
481 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
482 SelectObject(hdc, old_hfont);
483 DeleteObject(hfont);
485 DeleteDC(hdc);
488 /* Test how GDI scales outline font metrics */
489 static void test_outline_font(void)
491 static const char test_str[11] = "Test String";
492 HDC hdc, hdc_2;
493 LOGFONTA lf;
494 HFONT hfont, old_hfont, old_hfont_2;
495 OUTLINETEXTMETRICA otm;
496 SIZE size_orig;
497 INT width_orig, height_orig, lfWidth;
498 XFORM xform;
499 GLYPHMETRICS gm;
500 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
501 POINT pt;
502 INT ret;
504 if (!is_truetype_font_installed("Arial"))
506 skip("Arial is not installed\n");
507 return;
510 hdc = CreateCompatibleDC(0);
512 memset(&lf, 0, sizeof(lf));
513 strcpy(lf.lfFaceName, "Arial");
514 lf.lfHeight = 72;
515 hfont = create_font("outline", &lf);
516 old_hfont = SelectObject(hdc, hfont);
517 otm.otmSize = sizeof(otm);
518 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
519 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
520 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
522 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
523 SelectObject(hdc, old_hfont);
524 DeleteObject(hfont);
526 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
527 lf.lfHeight = otm.otmEMSquare;
528 lf.lfHeight = -lf.lfHeight;
529 hfont = create_font("outline", &lf);
530 old_hfont = SelectObject(hdc, hfont);
531 otm.otmSize = sizeof(otm);
532 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
533 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
534 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
535 SelectObject(hdc, old_hfont);
536 DeleteObject(hfont);
538 height_orig = otm.otmTextMetrics.tmHeight;
539 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
541 /* test integer scaling 3x2 */
542 lf.lfHeight = height_orig * 2;
543 lf.lfWidth = lfWidth * 3;
544 hfont = create_font("3x2", &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, 2);
547 SelectObject(hdc, old_hfont);
548 DeleteObject(hfont);
550 /* test integer scaling 3x3 */
551 lf.lfHeight = height_orig * 3;
552 lf.lfWidth = lfWidth * 3;
553 hfont = create_font("3x3", &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, 3, 3);
556 SelectObject(hdc, old_hfont);
557 DeleteObject(hfont);
559 /* test integer scaling 1x1 */
560 lf.lfHeight = height_orig * 1;
561 lf.lfWidth = lfWidth * 1;
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);
565 SelectObject(hdc, old_hfont);
566 DeleteObject(hfont);
568 /* test integer scaling 1x1 */
569 lf.lfHeight = height_orig;
570 lf.lfWidth = 0;
571 hfont = create_font("1x1", &lf);
572 old_hfont = SelectObject(hdc, hfont);
573 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
575 /* with an identity matrix */
576 memset(&gm, 0, sizeof(gm));
577 SetLastError(0xdeadbeef);
578 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
582 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
583 /* with a custom matrix */
584 memset(&gm, 0, sizeof(gm));
585 SetLastError(0xdeadbeef);
586 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
587 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
588 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
589 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
592 /* Test that changing the DC transformation affects only the font
593 * selected on this DC and doesn't affect the same font selected on
594 * another DC.
596 hdc_2 = CreateCompatibleDC(0);
597 old_hfont_2 = SelectObject(hdc_2, hfont);
598 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
600 SetMapMode(hdc, MM_ANISOTROPIC);
602 /* font metrics on another DC should be unchanged */
603 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
605 /* test restrictions of compatibility mode GM_COMPATIBLE */
606 /* part 1: rescaling only X should not change font scaling on screen.
607 So compressing the X axis by 2 is not done, and this
608 appears as X scaling of 2 that no one requested. */
609 SetWindowExtEx(hdc, 100, 100, NULL);
610 SetViewportExtEx(hdc, 50, 100, 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 /* part 2: rescaling only Y should change font scaling.
616 As also X is scaled by a factor of 2, but this is not
617 requested by the DC transformation, we get a scaling factor
618 of 2 in the X coordinate. */
619 SetViewportExtEx(hdc, 100, 200, NULL);
620 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
621 /* font metrics on another DC should be unchanged */
622 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
624 /* restore scaling */
625 SetMapMode(hdc, MM_TEXT);
627 /* font metrics on another DC should be unchanged */
628 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
630 SelectObject(hdc_2, old_hfont_2);
631 DeleteDC(hdc_2);
633 if (!SetGraphicsMode(hdc, GM_ADVANCED))
635 SelectObject(hdc, old_hfont);
636 DeleteObject(hfont);
637 DeleteDC(hdc);
638 skip("GM_ADVANCED is not supported on this platform\n");
639 return;
642 xform.eM11 = 20.0f;
643 xform.eM12 = 0.0f;
644 xform.eM21 = 0.0f;
645 xform.eM22 = 20.0f;
646 xform.eDx = 0.0f;
647 xform.eDy = 0.0f;
649 SetLastError(0xdeadbeef);
650 ret = SetWorldTransform(hdc, &xform);
651 ok(ret, "SetWorldTransform error %u\n", GetLastError());
653 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
655 /* with an identity matrix */
656 memset(&gm, 0, sizeof(gm));
657 SetLastError(0xdeadbeef);
658 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
659 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
660 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
661 pt.x = width_orig; pt.y = 0;
662 LPtoDP(hdc, &pt, 1);
663 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
664 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
665 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
666 /* with a custom matrix */
667 memset(&gm, 0, sizeof(gm));
668 SetLastError(0xdeadbeef);
669 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
670 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
671 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
672 pt.x = width_orig; pt.y = 0;
673 LPtoDP(hdc, &pt, 1);
674 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
675 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
676 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
678 SetLastError(0xdeadbeef);
679 ret = SetMapMode(hdc, MM_LOMETRIC);
680 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
682 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
684 /* with an identity matrix */
685 memset(&gm, 0, sizeof(gm));
686 SetLastError(0xdeadbeef);
687 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
688 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
689 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
690 pt.x = width_orig; pt.y = 0;
691 LPtoDP(hdc, &pt, 1);
692 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
693 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
694 /* with a custom matrix */
695 memset(&gm, 0, sizeof(gm));
696 SetLastError(0xdeadbeef);
697 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
698 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
699 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
700 pt.x = width_orig; pt.y = 0;
701 LPtoDP(hdc, &pt, 1);
702 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
703 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
705 SetLastError(0xdeadbeef);
706 ret = SetMapMode(hdc, MM_TEXT);
707 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
709 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
711 /* with an identity matrix */
712 memset(&gm, 0, sizeof(gm));
713 SetLastError(0xdeadbeef);
714 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
715 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
716 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
717 pt.x = width_orig; pt.y = 0;
718 LPtoDP(hdc, &pt, 1);
719 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
720 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
721 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
722 /* with a custom matrix */
723 memset(&gm, 0, sizeof(gm));
724 SetLastError(0xdeadbeef);
725 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
726 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
727 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
728 pt.x = width_orig; pt.y = 0;
729 LPtoDP(hdc, &pt, 1);
730 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
731 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
732 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
734 SelectObject(hdc, old_hfont);
735 DeleteObject(hfont);
736 DeleteDC(hdc);
739 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
741 LOGFONTA *lf = (LOGFONTA *)lParam;
743 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
745 *lf = *elf;
746 return 0; /* stop enumeration */
748 return 1; /* continue enumeration */
751 static BOOL is_CJK(void)
753 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
756 #define FH_SCALE 0x80000000
757 static void test_bitmap_font_metrics(void)
759 static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
760 static const struct font_data
762 const char face_name[LF_FACESIZE];
763 int weight, height, ascent, descent, int_leading, ext_leading;
764 int ave_char_width, max_char_width, dpi;
765 BYTE first_char, last_char, def_char, break_char;
766 DWORD ansi_bitfield;
767 const WORD *skip_lang_id;
768 int scaled_height;
769 } fd[] =
771 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
772 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
773 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
775 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
777 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
778 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 16 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
782 { "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 },
783 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
784 { "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 },
785 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
786 { "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 },
787 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
788 { "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 },
789 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
790 { "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 },
791 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
793 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
794 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
795 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
796 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
797 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
798 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
799 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
800 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
801 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
802 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
803 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
804 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
805 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
806 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
807 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
808 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
812 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
813 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
814 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
815 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
816 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
817 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
818 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
819 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
820 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
823 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
824 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
826 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
827 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
828 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
830 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
831 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
833 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
834 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
835 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
836 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
837 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
838 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
839 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
841 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
842 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
843 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
844 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
845 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
846 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
847 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
848 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
849 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
850 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
851 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
853 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
854 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
855 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
857 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
858 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
859 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
861 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
862 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
863 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
865 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
866 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
868 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
869 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
870 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
871 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
872 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
873 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
874 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
875 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
876 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
877 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
878 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
879 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
880 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
881 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
882 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
883 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
884 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
885 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
886 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
887 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
888 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
890 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
891 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
892 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
893 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
894 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
895 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
896 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
897 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
898 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
899 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
900 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
901 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
903 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
904 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
905 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
907 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
909 /* FIXME: add "Terminal" */
911 static const int font_log_pixels[] = { 96, 120 };
912 HDC hdc;
913 LOGFONTA lf;
914 HFONT hfont, old_hfont;
915 TEXTMETRICA tm;
916 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
917 char face_name[LF_FACESIZE];
918 CHARSETINFO csi;
920 trace("system language id %04x\n", system_lang_id);
922 expected_cs = GetACP();
923 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
925 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
926 return;
928 expected_cs = csi.ciCharset;
929 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
931 hdc = CreateCompatibleDC(0);
932 ok(hdc != NULL, "failed to create hdc\n");
934 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
935 GetDeviceCaps(hdc, LOGPIXELSY));
937 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
938 diff = 32768;
939 font_res = 0;
940 for (i = 0; i < ARRAY_SIZE(font_log_pixels); i++)
942 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
943 if (new_diff < diff)
945 diff = new_diff;
946 font_res = font_log_pixels[i];
949 trace("best font resolution is %d\n", font_res);
951 for (i = 0; i < ARRAY_SIZE(fd); i++)
953 int bit, height;
955 memset(&lf, 0, sizeof(lf));
957 height = fd[i].height & ~FH_SCALE;
958 lf.lfHeight = height;
959 strcpy(lf.lfFaceName, fd[i].face_name);
961 for(bit = 0; bit < 32; bit++)
963 GLYPHMETRICS gm;
964 DWORD fs[2];
965 BOOL bRet;
967 fs[0] = 1L << bit;
968 fs[1] = 0;
969 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
970 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
972 lf.lfCharSet = csi.ciCharset;
973 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
974 if (fd[i].height & FH_SCALE)
975 ok(ret, "scaled font height %d should not be enumerated\n", height);
976 else
978 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
980 todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */
981 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
984 if (ret && !(fd[i].height & FH_SCALE))
985 continue;
987 hfont = create_font(lf.lfFaceName, &lf);
988 old_hfont = SelectObject(hdc, hfont);
990 SetLastError(0xdeadbeef);
991 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
992 ok(ret, "GetTextFace error %u\n", GetLastError());
994 if (strcmp(face_name, fd[i].face_name) != 0)
996 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
997 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
998 SelectObject(hdc, old_hfont);
999 DeleteObject(hfont);
1000 continue;
1003 memset(&gm, 0, sizeof(gm));
1004 SetLastError(0xdeadbeef);
1005 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1006 todo_wine {
1007 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1008 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1011 bRet = GetTextMetricsA(hdc, &tm);
1012 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1014 SetLastError(0xdeadbeef);
1015 ret = GetTextCharset(hdc);
1016 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1017 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1018 else
1019 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1021 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1022 trace("expected %s, height %d scaled_height %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1024 if(fd[i].dpi == tm.tmDigitizedAspectX)
1026 int skipme = 0;
1027 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1028 if (fd[i].skip_lang_id)
1030 int si = 0;
1031 skipme = 0;
1032 while(!skipme && fd[i].skip_lang_id[si])
1033 if (fd[i].skip_lang_id[si++] == system_lang_id)
1034 skipme = 1;
1036 if (!skipme)
1038 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1039 if (fd[i].height & FH_SCALE)
1040 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);
1041 else
1042 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);
1043 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1044 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1045 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);
1046 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);
1047 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);
1048 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1049 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1050 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1051 make default char test fail */
1052 if (tm.tmCharSet == lf.lfCharSet)
1053 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1054 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1055 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);
1057 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1058 that make the max width bigger */
1059 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1060 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);
1062 else
1063 skip("Skipping font metrics test for system langid 0x%x\n",
1064 system_lang_id);
1066 SelectObject(hdc, old_hfont);
1067 DeleteObject(hfont);
1071 DeleteDC(hdc);
1074 static void test_GdiGetCharDimensions(void)
1076 HDC hdc;
1077 TEXTMETRICW tm;
1078 LONG ret;
1079 SIZE size;
1080 LONG avgwidth, height;
1081 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1083 if (!pGdiGetCharDimensions)
1085 win_skip("GdiGetCharDimensions not available on this platform\n");
1086 return;
1089 hdc = CreateCompatibleDC(NULL);
1091 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1092 avgwidth = ((size.cx / 26) + 1) / 2;
1094 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1095 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1096 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1098 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1099 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1101 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1102 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1104 height = 0;
1105 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1106 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1107 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1109 DeleteDC(hdc);
1112 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1113 const TEXTMETRICA *lpntme,
1114 DWORD FontType, LPARAM lParam)
1116 if (FontType & TRUETYPE_FONTTYPE)
1118 HFONT hfont;
1120 hfont = CreateFontIndirectA(lpelfe);
1121 if (hfont)
1123 *(HFONT *)lParam = hfont;
1124 return 0;
1128 return 1;
1131 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, const ABC *base_abci, const ABC *base_abcw, const ABCFLOAT *base_abcf)
1133 ABC abc[1];
1134 ABCFLOAT abcf[1];
1135 BOOL ret = FALSE;
1137 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1138 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1139 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1140 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1141 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1143 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1144 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1145 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1146 ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1147 ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1149 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1150 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1151 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1152 ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1153 ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1156 static void test_GetCharABCWidths(void)
1158 static const WCHAR str[] = {'i',0};
1159 BOOL ret;
1160 HDC hdc;
1161 LOGFONTA lf;
1162 HFONT hfont;
1163 ABC abc[1];
1164 ABC abcw[1];
1165 ABCFLOAT abcf[1];
1166 WORD glyphs[1];
1167 DWORD nb;
1168 HWND hwnd;
1169 static const struct
1171 UINT first;
1172 UINT last;
1173 } range[] =
1175 {0xff, 0xff},
1176 {0x100, 0x100},
1177 {0xff, 0x100},
1178 {0x1ff, 0xff00},
1179 {0xffff, 0xffff},
1180 {0x10000, 0x10000},
1181 {0xffff, 0x10000},
1182 {0xffffff, 0xffffff},
1183 {0x1000000, 0x1000000},
1184 {0xffffff, 0x1000000},
1185 {0xffffffff, 0xffffffff},
1186 {0x00, 0xff}
1188 static const struct
1190 UINT cs;
1191 UINT a;
1192 UINT w;
1193 BOOL r[ARRAY_SIZE(range)];
1194 } c[] =
1196 {ANSI_CHARSET, 0x30, 0x30,
1197 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1198 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1199 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1200 {HANGEUL_CHARSET, 0x8141, 0xac02,
1201 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1202 {GB2312_CHARSET, 0x8141, 0x4e04,
1203 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1204 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1205 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1207 UINT i;
1209 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1211 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1212 return;
1215 memset(&lf, 0, sizeof(lf));
1216 strcpy(lf.lfFaceName, "System");
1217 lf.lfHeight = 20;
1219 hfont = CreateFontIndirectA(&lf);
1220 hdc = GetDC(0);
1221 hfont = SelectObject(hdc, hfont);
1223 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1224 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1226 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1227 ok(!ret, "GetCharABCWidthsI should have failed\n");
1229 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1230 ok(!ret, "GetCharABCWidthsI should have failed\n");
1232 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1233 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1235 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1236 ok(!ret, "GetCharABCWidthsW should have failed\n");
1238 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1239 ok(!ret, "GetCharABCWidthsW should have failed\n");
1241 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1242 ok(!ret, "GetCharABCWidthsW should have failed\n");
1244 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1245 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1247 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1248 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1250 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1251 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1253 hfont = SelectObject(hdc, hfont);
1254 DeleteObject(hfont);
1256 for (i = 0; i < ARRAY_SIZE(c); ++i)
1258 ABC a[2], w[2];
1259 ABC full[256];
1260 UINT code = 0x41, j;
1262 lf.lfFaceName[0] = '\0';
1263 lf.lfCharSet = c[i].cs;
1264 lf.lfPitchAndFamily = 0;
1265 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1267 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1268 continue;
1271 memset(a, 0, sizeof a);
1272 memset(w, 0, sizeof w);
1273 hfont = SelectObject(hdc, hfont);
1274 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1275 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1276 memcmp(a, w, sizeof a) == 0,
1277 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1279 memset(a, 0xbb, sizeof a);
1280 ret = pGetCharABCWidthsA(hdc, code, code, a);
1281 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1282 memset(full, 0xcc, sizeof full);
1283 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1284 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1285 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1286 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1288 for (j = 0; j < ARRAY_SIZE(range); ++j)
1290 memset(full, 0xdd, sizeof full);
1291 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1292 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1293 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1294 if (ret)
1296 UINT last = range[j].last - range[j].first;
1297 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1298 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1299 "GetCharABCWidthsA %x should match. codepage = %u\n",
1300 range[j].last, c[i].cs);
1304 hfont = SelectObject(hdc, hfont);
1305 DeleteObject(hfont);
1308 memset(&lf, 0, sizeof(lf));
1309 strcpy(lf.lfFaceName, "Tahoma");
1310 lf.lfHeight = 200;
1311 hfont = CreateFontIndirectA(&lf);
1313 /* test empty glyph's metrics */
1314 hfont = SelectObject(hdc, hfont);
1315 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1316 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1317 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1318 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1319 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1320 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1322 /* 1) prepare unrotated font metrics */
1323 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1324 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1325 DeleteObject(SelectObject(hdc, hfont));
1327 /* 2) get rotated font metrics */
1328 lf.lfEscapement = lf.lfOrientation = 900;
1329 hfont = CreateFontIndirectA(&lf);
1330 hfont = SelectObject(hdc, hfont);
1331 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1332 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1334 /* 3) compare ABC results */
1335 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1336 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1337 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1338 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1339 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1340 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1342 DeleteObject(SelectObject(hdc, hfont));
1344 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1345 in various widths. */
1346 for (i = 1; i <= 2; i++)
1348 UINT j;
1349 UINT code;
1351 memset(&lf, 0, sizeof(lf));
1352 lf.lfHeight = 20;
1353 switch(i)
1355 case 1:
1356 strcpy(lf.lfFaceName, "Tahoma");
1357 code = 'a';
1358 break;
1359 case 2:
1360 strcpy(lf.lfFaceName, "Times New Roman");
1361 lf.lfItalic = TRUE;
1362 code = 'f';
1363 break;
1365 if (!is_truetype_font_installed(lf.lfFaceName))
1367 skip("%s is not installed\n", lf.lfFaceName);
1368 continue;
1370 for (j = 1; j <= 80; j++)
1372 GLYPHMETRICS gm;
1374 lf.lfWidth = j;
1375 hfont = CreateFontIndirectA(&lf);
1376 hfont = SelectObject(hdc, hfont);
1378 nb = GetGlyphOutlineA(hdc, code, GGO_METRICS, &gm, 0, NULL, &mat);
1379 ok(nb, "GetGlyphOutlineA should have succeeded at width %d\n", i);
1381 ret = GetCharABCWidthsA(hdc, code, code, abc);
1382 ok(ret, "GetCharABCWidthsA should have succeeded at width %d\n", i);
1384 ok(abc[0].abcA == gm.gmptGlyphOrigin.x,
1385 "abcA(%d) and gmptGlyphOrigin.x(%d) values are different at width %d\n",
1386 abc[0].abcA, gm.gmptGlyphOrigin.x, i);
1387 ok(abc[0].abcB == gm.gmBlackBoxX,
1388 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1389 abc[0].abcB, gm.gmBlackBoxX, i);
1390 DeleteObject(SelectObject(hdc, hfont));
1393 ReleaseDC(NULL, hdc);
1395 trace("ABC sign test for a variety of transforms:\n");
1396 memset(&lf, 0, sizeof(lf));
1397 strcpy(lf.lfFaceName, "Tahoma");
1398 lf.lfHeight = 20;
1399 hfont = CreateFontIndirectA(&lf);
1400 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1401 0, 0, 0, NULL);
1402 hdc = GetDC(hwnd);
1403 SetMapMode(hdc, MM_ANISOTROPIC);
1404 SelectObject(hdc, hfont);
1406 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1407 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1409 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1410 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1411 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1412 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1413 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1414 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1416 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf);
1417 SetWindowExtEx(hdc, -1, -1, NULL);
1418 SetGraphicsMode(hdc, GM_COMPATIBLE);
1419 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf);
1420 SetGraphicsMode(hdc, GM_ADVANCED);
1421 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf);
1422 SetWindowExtEx(hdc, 1, 1, NULL);
1423 SetGraphicsMode(hdc, GM_COMPATIBLE);
1424 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf);
1425 SetGraphicsMode(hdc, GM_ADVANCED);
1426 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf);
1428 ReleaseDC(hwnd, hdc);
1429 DestroyWindow(hwnd);
1431 trace("RTL layout\n");
1432 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1433 0, 0, 0, NULL);
1434 hdc = GetDC(hwnd);
1435 SetMapMode(hdc, MM_ANISOTROPIC);
1436 SelectObject(hdc, hfont);
1438 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf);
1439 SetWindowExtEx(hdc, -1, -1, NULL);
1440 SetGraphicsMode(hdc, GM_COMPATIBLE);
1441 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf);
1442 SetGraphicsMode(hdc, GM_ADVANCED);
1443 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf);
1444 SetWindowExtEx(hdc, 1, 1, NULL);
1445 SetGraphicsMode(hdc, GM_COMPATIBLE);
1446 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf);
1447 SetGraphicsMode(hdc, GM_ADVANCED);
1448 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf);
1450 ReleaseDC(hwnd, hdc);
1451 DestroyWindow(hwnd);
1452 DeleteObject(hfont);
1455 static void test_text_extents(void)
1457 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1458 static const WCHAR emptyW[] = {0};
1459 LPINT extents;
1460 INT i, len, fit1, fit2, extents2[3];
1461 LOGFONTA lf;
1462 TEXTMETRICA tm;
1463 HDC hdc;
1464 HFONT hfont;
1465 SIZE sz;
1466 SIZE sz1, sz2;
1467 BOOL ret;
1469 memset(&lf, 0, sizeof(lf));
1470 strcpy(lf.lfFaceName, "Arial");
1471 lf.lfHeight = 20;
1473 hfont = CreateFontIndirectA(&lf);
1474 hdc = GetDC(0);
1475 hfont = SelectObject(hdc, hfont);
1476 GetTextMetricsA(hdc, &tm);
1477 ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1478 ok(ret, "got %d\n", ret);
1479 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1481 memset(&sz, 0xcc, sizeof(sz));
1482 ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1483 ok(ret, "got %d\n", ret);
1484 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1486 memset(&sz, 0xcc, sizeof(sz));
1487 ret = GetTextExtentPointA(hdc, "", 0, &sz);
1488 ok(ret, "got %d\n", ret);
1489 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1491 SetLastError(0xdeadbeef);
1492 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1493 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1495 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1496 hfont = SelectObject(hdc, hfont);
1497 DeleteObject(hfont);
1498 ReleaseDC(0, hdc);
1499 return;
1502 memset(&sz, 0xcc, sizeof(sz));
1503 ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1504 ok(ret, "got %d\n", ret);
1505 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1507 memset(&sz, 0xcc, sizeof(sz));
1508 ret = GetTextExtentPointW(hdc, emptyW, 0, &sz);
1509 ok(ret, "got %d\n", ret);
1510 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1512 len = lstrlenW(wt);
1513 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1514 extents[0] = 1; /* So that the increasing sequence test will fail
1515 if the extents array is untouched. */
1516 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1517 GetTextExtentPointW(hdc, wt, len, &sz2);
1518 ok(sz1.cy == sz2.cy,
1519 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1520 /* Because of the '\n' in the string GetTextExtentExPoint and
1521 GetTextExtentPoint return different widths under Win2k, but
1522 under WinXP they return the same width. So we don't test that
1523 here. */
1525 for (i = 1; i < len; ++i)
1526 ok(extents[i-1] <= extents[i],
1527 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1529 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1530 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1531 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1532 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1533 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1534 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1535 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1536 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1537 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1538 ok(extents[0] == extents[2] && extents[1] == extents[3],
1539 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1540 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1541 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1542 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1544 /* extents functions fail with -ve counts (the interesting case being -1) */
1545 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1546 ok(ret == FALSE, "got %d\n", ret);
1547 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1548 ok(ret == FALSE, "got %d\n", ret);
1549 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1550 ok(ret == FALSE, "got %d\n", ret);
1552 /* max_extent = 0 succeeds and returns zero */
1553 fit1 = fit2 = -215;
1554 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1555 ok(ret == TRUE ||
1556 broken(ret == FALSE), /* NT4, 2k */
1557 "got %d\n", ret);
1558 ok(fit1 == 0 ||
1559 broken(fit1 == -215), /* NT4, 2k */
1560 "fit = %d\n", fit1);
1561 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1562 ok(ret == TRUE, "got %d\n", ret);
1563 ok(fit2 == 0, "fit = %d\n", fit2);
1565 /* max_extent = -1 is interpreted as a very large width that will
1566 * definitely fit our three characters */
1567 fit1 = fit2 = -215;
1568 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1569 ok(ret == TRUE, "got %d\n", ret);
1570 ok(fit1 == 3, "fit = %d\n", fit1);
1571 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1572 ok(ret == TRUE, "got %d\n", ret);
1573 ok(fit2 == 3, "fit = %d\n", fit2);
1575 /* max_extent = -2 is interpreted similarly, but the Ansi version
1576 * rejects it while the Unicode one accepts it */
1577 fit1 = fit2 = -215;
1578 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1579 ok(ret == FALSE, "got %d\n", ret);
1580 ok(fit1 == -215, "fit = %d\n", fit1);
1581 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1582 ok(ret == TRUE, "got %d\n", ret);
1583 ok(fit2 == 3, "fit = %d\n", fit2);
1585 hfont = SelectObject(hdc, hfont);
1586 DeleteObject(hfont);
1588 /* non-MM_TEXT mapping mode */
1589 lf.lfHeight = 2000;
1590 hfont = CreateFontIndirectA(&lf);
1591 hfont = SelectObject(hdc, hfont);
1593 SetMapMode( hdc, MM_HIMETRIC );
1594 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1595 ok(ret, "got %d\n", ret);
1596 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1598 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1599 ok(ret, "got %d\n", ret);
1600 ok(fit1 == 2, "got %d\n", fit1);
1601 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1602 for(i = 0; i < 2; i++)
1603 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1605 hfont = SelectObject(hdc, hfont);
1606 DeleteObject(hfont);
1607 HeapFree(GetProcessHeap(), 0, extents);
1608 ReleaseDC(NULL, hdc);
1611 static void test_GetGlyphIndices(void)
1613 HDC hdc;
1614 HFONT hfont;
1615 DWORD charcount;
1616 LOGFONTA lf;
1617 DWORD flags = 0;
1618 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1619 WORD glyphs[(sizeof(testtext)/2)-1];
1620 TEXTMETRICA textm;
1621 HFONT hOldFont;
1623 if (!pGetGlyphIndicesW) {
1624 win_skip("GetGlyphIndicesW not available on platform\n");
1625 return;
1628 hdc = GetDC(0);
1630 memset(&lf, 0, sizeof(lf));
1631 strcpy(lf.lfFaceName, "System");
1632 lf.lfHeight = 16;
1633 lf.lfCharSet = ANSI_CHARSET;
1635 hfont = CreateFontIndirectA(&lf);
1636 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1637 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1638 if (textm.tmCharSet == ANSI_CHARSET)
1640 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1641 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1642 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1643 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1644 flags = 0;
1645 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1646 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1647 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1648 textm.tmDefaultChar, glyphs[4]);
1650 else
1651 /* FIXME: Write tests for non-ANSI charsets. */
1652 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1654 if(!is_font_installed("Tahoma"))
1656 skip("Tahoma is not installed so skipping this test\n");
1657 return;
1659 memset(&lf, 0, sizeof(lf));
1660 strcpy(lf.lfFaceName, "Tahoma");
1661 lf.lfHeight = 20;
1663 hfont = CreateFontIndirectA(&lf);
1664 hOldFont = SelectObject(hdc, hfont);
1665 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1666 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1667 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1668 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1669 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1670 flags = 0;
1671 testtext[0] = textm.tmDefaultChar;
1672 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1673 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1674 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1675 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1676 DeleteObject(SelectObject(hdc, hOldFont));
1679 static void test_GetKerningPairs(void)
1681 static const struct kerning_data
1683 const char face_name[LF_FACESIZE];
1684 LONG height;
1685 /* some interesting fields from OUTLINETEXTMETRIC */
1686 LONG tmHeight, tmAscent, tmDescent;
1687 UINT otmEMSquare;
1688 INT otmAscent;
1689 INT otmDescent;
1690 UINT otmLineGap;
1691 UINT otmsCapEmHeight;
1692 UINT otmsXHeight;
1693 INT otmMacAscent;
1694 INT otmMacDescent;
1695 UINT otmMacLineGap;
1696 UINT otmusMinimumPPEM;
1697 /* small subset of kerning pairs to test */
1698 DWORD total_kern_pairs;
1699 const KERNINGPAIR kern_pair[26];
1700 } kd[] =
1702 {"Arial", 12, 12, 9, 3,
1703 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1706 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1707 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1708 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1709 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1710 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1711 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1712 {933,970,+1},{933,972,-1}
1715 {"Arial", -34, 39, 32, 7,
1716 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1719 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1720 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1721 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1722 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1723 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1724 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1725 {933,970,+2},{933,972,-3}
1728 { "Arial", 120, 120, 97, 23,
1729 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1732 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1733 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1734 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1735 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1736 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1737 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1738 {933,970,+6},{933,972,-10}
1741 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1742 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1743 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1746 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1747 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1748 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1749 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1750 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1751 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1752 {933,970,+54},{933,972,-83}
1755 #endif
1757 LOGFONTA lf;
1758 HFONT hfont, hfont_old;
1759 KERNINGPAIR *kern_pair;
1760 HDC hdc;
1761 DWORD total_kern_pairs, ret, i, n, matches;
1763 hdc = GetDC(0);
1765 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1766 * which may render this test unusable, so we're trying to avoid that.
1768 SetLastError(0xdeadbeef);
1769 GetKerningPairsW(hdc, 0, NULL);
1770 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1772 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1773 ReleaseDC(0, hdc);
1774 return;
1777 for (i = 0; i < ARRAY_SIZE(kd); i++)
1779 OUTLINETEXTMETRICW otm;
1780 UINT uiRet;
1782 if (!is_font_installed(kd[i].face_name))
1784 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1785 continue;
1788 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1790 memset(&lf, 0, sizeof(lf));
1791 strcpy(lf.lfFaceName, kd[i].face_name);
1792 lf.lfHeight = kd[i].height;
1793 hfont = CreateFontIndirectA(&lf);
1794 ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name);
1796 hfont_old = SelectObject(hdc, hfont);
1798 SetLastError(0xdeadbeef);
1799 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1800 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1801 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1803 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1804 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1805 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1806 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1807 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1808 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1810 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1811 kd[i].otmEMSquare, otm.otmEMSquare);
1812 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1813 kd[i].otmAscent, otm.otmAscent);
1814 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1815 kd[i].otmDescent, otm.otmDescent);
1816 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1817 kd[i].otmLineGap, otm.otmLineGap);
1818 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1819 kd[i].otmMacDescent, otm.otmMacDescent);
1820 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1821 kd[i].otmMacAscent, otm.otmMacAscent);
1822 todo_wine
1823 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1824 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1825 todo_wine
1826 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1827 kd[i].otmsXHeight, otm.otmsXHeight);
1828 ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1829 kd[i].otmMacLineGap, otm.otmMacLineGap);
1830 todo_wine
1831 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1832 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1834 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1835 trace("total_kern_pairs %u\n", total_kern_pairs);
1836 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1838 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1839 * passes on XP.
1841 SetLastError(0xdeadbeef);
1842 ret = GetKerningPairsW(hdc, 0, kern_pair);
1843 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1844 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1845 ok(ret == 0, "got %u, expected 0\n", ret);
1847 ret = GetKerningPairsW(hdc, 100, NULL);
1848 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1850 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1851 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1853 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1854 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1856 matches = 0;
1858 for (n = 0; n < ret; n++)
1860 DWORD j;
1861 /* Disabled to limit console spam */
1862 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1863 trace("{'%c','%c',%d},\n",
1864 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1865 for (j = 0; j < kd[i].total_kern_pairs; j++)
1867 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1868 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1870 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1871 "pair %d:%d got %d, expected %d\n",
1872 kern_pair[n].wFirst, kern_pair[n].wSecond,
1873 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1874 matches++;
1879 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1880 matches, kd[i].total_kern_pairs);
1882 HeapFree(GetProcessHeap(), 0, kern_pair);
1884 SelectObject(hdc, hfont_old);
1885 DeleteObject(hfont);
1888 ReleaseDC(0, hdc);
1891 struct font_data
1893 const char face_name[LF_FACESIZE];
1894 int requested_height;
1895 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1896 BOOL exact;
1899 static void test_height( HDC hdc, const struct font_data *fd )
1901 LOGFONTA lf;
1902 HFONT hfont, old_hfont;
1903 TEXTMETRICA tm;
1904 INT ret, i;
1906 for (i = 0; fd[i].face_name[0]; i++)
1908 if (!is_truetype_font_installed(fd[i].face_name))
1910 skip("%s is not installed\n", fd[i].face_name);
1911 continue;
1914 memset(&lf, 0, sizeof(lf));
1915 lf.lfHeight = fd[i].requested_height;
1916 lf.lfWeight = fd[i].weight;
1917 strcpy(lf.lfFaceName, fd[i].face_name);
1919 hfont = CreateFontIndirectA(&lf);
1920 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
1922 old_hfont = SelectObject(hdc, hfont);
1923 ret = GetTextMetricsA(hdc, &tm);
1924 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1925 if(fd[i].dpi == tm.tmDigitizedAspectX)
1927 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);
1928 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);
1929 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);
1930 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);
1931 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);
1932 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);
1935 SelectObject(hdc, old_hfont);
1936 /* force GDI to use new font, otherwise Windows leaks the font reference */
1937 GetTextMetricsA(hdc, &tm);
1938 DeleteObject(hfont);
1942 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1944 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1945 DWORD *table = (DWORD *)ttf + 3;
1947 for (i = 0; i < num_tables; i++)
1949 if (table[0] == tag)
1950 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1951 table += 4;
1953 return NULL;
1956 static void test_height_selection_vdmx( HDC hdc )
1958 static const struct font_data charset_0[] = /* doesn't use VDMX */
1960 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1961 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1962 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1963 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1964 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1965 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1966 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1967 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1968 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1969 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1970 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1971 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1972 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1973 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1974 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1975 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1976 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1977 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1978 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1979 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1980 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1981 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1982 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1983 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1984 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1985 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1986 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1987 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1988 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1989 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1990 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1991 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1992 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1993 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1994 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1995 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1996 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1997 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1998 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1999 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
2000 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2001 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
2002 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
2003 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
2004 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
2005 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
2006 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
2007 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
2008 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
2009 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2010 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
2011 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2012 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2015 static const struct font_data charset_1[] = /* Uses VDMX */
2017 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
2018 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
2019 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2020 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2021 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2022 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2023 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2024 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2025 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2026 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2027 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2028 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2029 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2030 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2031 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2032 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2033 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2034 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2035 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2036 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2037 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2038 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2039 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2040 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
2041 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
2042 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
2043 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2044 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2045 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2046 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2047 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2048 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2049 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2050 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2051 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2052 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2053 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2054 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2055 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2056 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2057 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2058 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2059 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2060 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2061 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2062 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2063 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2064 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2065 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2066 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2067 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2068 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2069 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2072 static const struct vdmx_data
2074 WORD version;
2075 BYTE bCharSet;
2076 const struct font_data *fd;
2077 } data[] =
2079 { 0, 0, charset_0 },
2080 { 0, 1, charset_1 },
2081 { 1, 0, charset_0 },
2082 { 1, 1, charset_1 }
2084 int i;
2085 DWORD size, num;
2086 WORD *vdmx_header;
2087 BYTE *ratio_rec;
2088 char ttf_name[MAX_PATH];
2089 void *res, *copy;
2090 BOOL ret;
2092 if (!pAddFontResourceExA)
2094 win_skip("AddFontResourceExA unavailable\n");
2095 return;
2098 for (i = 0; i < ARRAY_SIZE(data); i++)
2100 res = get_res_data( "wine_vdmx.ttf", &size );
2102 copy = HeapAlloc( GetProcessHeap(), 0, size );
2103 memcpy( copy, res, size );
2104 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2105 vdmx_header[0] = GET_BE_WORD( data[i].version );
2106 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2107 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2108 ratio_rec = (BYTE *)&vdmx_header[3];
2109 ratio_rec[0] = data[i].bCharSet;
2111 write_tmp_file( copy, &size, ttf_name );
2112 HeapFree( GetProcessHeap(), 0, copy );
2114 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2115 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2116 if (!num) win_skip("Unable to add ttf font resource\n");
2117 else
2119 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2120 test_height( hdc, data[i].fd );
2121 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2123 ret = DeleteFileA( ttf_name );
2124 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2125 "DeleteFile error %d\n", GetLastError());
2129 static void test_height_selection(void)
2131 static const struct font_data tahoma[] =
2133 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2134 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2135 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2136 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2137 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2138 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2139 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2140 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2141 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2142 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2143 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2145 HDC hdc = CreateCompatibleDC(0);
2146 ok(hdc != NULL, "failed to create hdc\n");
2148 test_height( hdc, tahoma );
2149 test_height_selection_vdmx( hdc );
2151 DeleteDC(hdc);
2154 static UINT get_font_fsselection(LOGFONTA *lf)
2156 OUTLINETEXTMETRICA *otm;
2157 HFONT hfont, hfont_old;
2158 DWORD ret, otm_size;
2159 UINT fsSelection;
2160 HDC hdc;
2162 hdc = GetDC(0);
2163 hfont = CreateFontIndirectA(lf);
2164 ok(hfont != NULL, "failed to create a font\n");
2166 hfont_old = SelectObject(hdc, hfont);
2168 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2169 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2170 otm->otmSize = sizeof(*otm);
2171 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2172 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2173 fsSelection = otm->otmfsSelection;
2174 HeapFree(GetProcessHeap(), 0, otm);
2175 SelectObject(hdc, hfont_old);
2176 DeleteObject(hfont);
2177 ReleaseDC(0, hdc);
2179 return fsSelection;
2182 static void test_GetOutlineTextMetrics(void)
2184 OUTLINETEXTMETRICA *otm;
2185 LOGFONTA lf;
2186 HFONT hfont, hfont_old;
2187 HDC hdc;
2188 DWORD ret, otm_size;
2189 LPSTR unset_ptr;
2190 UINT fsSelection;
2192 /* check fsSelection field with bold simulation */
2193 memset(&lf, 0, sizeof(lf));
2194 strcpy(lf.lfFaceName, "Wingdings");
2195 lf.lfCharSet = SYMBOL_CHARSET;
2197 /* regular face */
2198 fsSelection = get_font_fsselection(&lf);
2199 ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection);
2201 /* face with bold simulation */
2202 lf.lfWeight = FW_BOLD;
2203 fsSelection = get_font_fsselection(&lf);
2204 ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection);
2206 /* check fsSelection field with oblique simulation */
2207 memset(&lf, 0, sizeof(lf));
2208 strcpy(lf.lfFaceName, "Tahoma");
2209 lf.lfHeight = -13;
2210 lf.lfWeight = FW_NORMAL;
2211 lf.lfPitchAndFamily = DEFAULT_PITCH;
2212 lf.lfQuality = PROOF_QUALITY;
2214 /* regular face */
2215 fsSelection = get_font_fsselection(&lf);
2216 ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection);
2218 lf.lfItalic = 1;
2219 /* face with oblique simulation */
2220 fsSelection = get_font_fsselection(&lf);
2221 ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection);
2223 if (!is_font_installed("Arial"))
2225 skip("Arial is not installed\n");
2226 return;
2229 hdc = GetDC(0);
2231 memset(&lf, 0, sizeof(lf));
2232 strcpy(lf.lfFaceName, "Arial");
2233 lf.lfHeight = -13;
2234 lf.lfWeight = FW_NORMAL;
2235 lf.lfPitchAndFamily = DEFAULT_PITCH;
2236 lf.lfQuality = PROOF_QUALITY;
2237 hfont = CreateFontIndirectA(&lf);
2238 ok(hfont != NULL, "failed to create a font\n");
2240 hfont_old = SelectObject(hdc, hfont);
2241 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2242 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2244 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2246 memset(otm, 0xAA, otm_size);
2247 SetLastError(0xdeadbeef);
2248 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2249 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2250 ok(ret == 1 /* Win9x */ ||
2251 ret == otm->otmSize /* XP*/,
2252 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2253 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2255 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2256 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2257 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2258 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2261 memset(otm, 0xAA, otm_size);
2262 SetLastError(0xdeadbeef);
2263 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2264 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2265 ok(ret == 1 /* Win9x */ ||
2266 ret == otm->otmSize /* XP*/,
2267 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2268 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2270 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2271 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2272 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2273 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2276 /* ask about truncated data */
2277 memset(otm, 0xAA, otm_size);
2278 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2279 SetLastError(0xdeadbeef);
2280 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2281 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2282 ok(ret == 1 /* Win9x */ ||
2283 ret == otm->otmSize /* XP*/,
2284 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2285 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2287 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2288 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2289 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2291 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2293 /* check handling of NULL pointer */
2294 SetLastError(0xdeadbeef);
2295 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2296 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2298 HeapFree(GetProcessHeap(), 0, otm);
2300 SelectObject(hdc, hfont_old);
2301 DeleteObject(hfont);
2303 ReleaseDC(0, hdc);
2306 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2308 INT y,
2309 breakCount,
2310 areaWidth = clientArea->right - clientArea->left,
2311 nErrors = 0, e;
2312 const char *pFirstChar, *pLastChar;
2313 SIZE size;
2314 TEXTMETRICA tm;
2315 struct err
2317 const char *start;
2318 int len;
2319 int GetTextExtentExPointWWidth;
2320 } error[20];
2322 GetTextMetricsA(hdc, &tm);
2323 y = clientArea->top;
2324 do {
2325 breakCount = 0;
2326 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2327 pFirstChar = str;
2329 do {
2330 pLastChar = str;
2332 /* if not at the end of the string, ... */
2333 if (*str == '\0') break;
2334 /* ... add the next word to the current extent */
2335 while (*str != '\0' && *str++ != tm.tmBreakChar);
2336 breakCount++;
2337 SetTextJustification(hdc, 0, 0);
2338 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2339 } while ((int) size.cx < areaWidth);
2341 /* ignore trailing break chars */
2342 breakCount--;
2343 while (*(pLastChar - 1) == tm.tmBreakChar)
2345 pLastChar--;
2346 breakCount--;
2349 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2351 SetTextJustification(hdc, 0, 0);
2352 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2354 /* do not justify the last extent */
2355 if (*str != '\0' && breakCount > 0)
2357 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2358 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2359 if (size.cx != areaWidth && nErrors < ARRAY_SIZE(error) - 1)
2361 error[nErrors].start = pFirstChar;
2362 error[nErrors].len = pLastChar - pFirstChar;
2363 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2364 nErrors++;
2368 y += size.cy;
2369 str = pLastChar;
2370 } while (*str && y < clientArea->bottom);
2372 for (e = 0; e < nErrors; e++)
2374 /* The width returned by GetTextExtentPoint32() is exactly the same
2375 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2376 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2377 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2378 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2382 static void test_SetTextJustification(void)
2384 HDC hdc;
2385 RECT clientArea;
2386 LOGFONTA lf;
2387 HFONT hfont;
2388 HWND hwnd;
2389 SIZE size, expect;
2390 int i;
2391 WORD indices[2];
2392 static const char testText[] =
2393 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2394 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2395 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2396 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2397 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2398 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2399 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2401 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2402 GetClientRect( hwnd, &clientArea );
2403 hdc = GetDC( hwnd );
2405 if (!is_font_installed("Times New Roman"))
2407 skip("Times New Roman is not installed\n");
2408 return;
2411 memset(&lf, 0, sizeof lf);
2412 lf.lfCharSet = ANSI_CHARSET;
2413 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2414 lf.lfWeight = FW_DONTCARE;
2415 lf.lfHeight = 20;
2416 lf.lfQuality = DEFAULT_QUALITY;
2417 lstrcpyA(lf.lfFaceName, "Times New Roman");
2418 hfont = create_font("Times New Roman", &lf);
2419 SelectObject(hdc, hfont);
2421 testJustification(hdc, testText, &clientArea);
2423 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2424 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2426 SetTextJustification(hdc, 0, 0);
2427 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2428 GetTextExtentPoint32A(hdc, " ", 3, &size);
2429 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2430 SetTextJustification(hdc, 4, 1);
2431 GetTextExtentPoint32A(hdc, " ", 1, &size);
2432 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2433 SetTextJustification(hdc, 9, 2);
2434 GetTextExtentPoint32A(hdc, " ", 2, &size);
2435 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2436 SetTextJustification(hdc, 7, 3);
2437 GetTextExtentPoint32A(hdc, " ", 3, &size);
2438 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2439 SetTextJustification(hdc, 7, 3);
2440 SetTextCharacterExtra(hdc, 2 );
2441 GetTextExtentPoint32A(hdc, " ", 3, &size);
2442 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2443 SetTextJustification(hdc, 0, 0);
2444 SetTextCharacterExtra(hdc, 0);
2445 size.cx = size.cy = 1234;
2446 GetTextExtentPoint32A(hdc, " ", 0, &size);
2447 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2448 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2449 SetTextJustification(hdc, 5, 1);
2450 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2451 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2452 SetTextJustification(hdc, 0, 0);
2454 SetMapMode( hdc, MM_ANISOTROPIC );
2455 SetWindowExtEx( hdc, 2, 2, NULL );
2456 GetClientRect( hwnd, &clientArea );
2457 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2458 testJustification(hdc, testText, &clientArea);
2460 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2461 for (i = 0; i < 10; i++)
2463 SetTextCharacterExtra(hdc, i);
2464 GetTextExtentPoint32A(hdc, "A", 1, &size);
2465 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2467 SetTextCharacterExtra(hdc, 0);
2468 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2469 for (i = 0; i < 10; i++)
2471 SetTextCharacterExtra(hdc, i);
2472 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2473 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2475 SetTextCharacterExtra(hdc, 0);
2477 SetViewportExtEx( hdc, 3, 3, NULL );
2478 GetClientRect( hwnd, &clientArea );
2479 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2480 testJustification(hdc, testText, &clientArea);
2482 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2483 for (i = 0; i < 10; i++)
2485 SetTextCharacterExtra(hdc, i);
2486 GetTextExtentPoint32A(hdc, "A", 1, &size);
2487 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2490 done:
2491 DeleteObject(hfont);
2492 ReleaseDC(hwnd, hdc);
2493 DestroyWindow(hwnd);
2496 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2498 HDC hdc;
2499 LOGFONTA lf;
2500 HFONT hfont, hfont_old;
2501 CHARSETINFO csi;
2502 FONTSIGNATURE fs;
2503 INT cs;
2504 DWORD i, ret;
2505 char name[64];
2507 assert(count <= 128);
2509 memset(&lf, 0, sizeof(lf));
2511 lf.lfCharSet = charset;
2512 lf.lfHeight = 10;
2513 lstrcpyA(lf.lfFaceName, "Arial");
2514 SetLastError(0xdeadbeef);
2515 hfont = CreateFontIndirectA(&lf);
2516 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2518 hdc = GetDC(0);
2519 hfont_old = SelectObject(hdc, hfont);
2521 cs = GetTextCharsetInfo(hdc, &fs, 0);
2522 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2524 SetLastError(0xdeadbeef);
2525 ret = GetTextFaceA(hdc, sizeof(name), name);
2526 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2528 if (charset == SYMBOL_CHARSET)
2530 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2531 ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n");
2533 else
2535 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2536 ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2539 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2541 trace("Can't find codepage for charset %d\n", cs);
2542 ReleaseDC(0, hdc);
2543 return FALSE;
2545 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2547 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2549 skip("Font code page %d, looking for code page %d\n",
2550 pGdiGetCodePage(hdc), code_page);
2551 ReleaseDC(0, hdc);
2552 return FALSE;
2555 if (unicode)
2557 char ansi_buf[128];
2558 WCHAR unicode_buf[128];
2560 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2562 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2564 SetLastError(0xdeadbeef);
2565 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2566 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2567 count, ret, GetLastError());
2569 else
2571 char ansi_buf[128];
2573 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2575 SetLastError(0xdeadbeef);
2576 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2577 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2578 count, ret, GetLastError());
2581 SelectObject(hdc, hfont_old);
2582 DeleteObject(hfont);
2584 ReleaseDC(0, hdc);
2586 return TRUE;
2589 static void test_font_charset(void)
2591 static struct charset_data
2593 INT charset;
2594 UINT code_page;
2595 WORD font_idxA[128], font_idxW[128];
2596 } cd[] =
2598 { ANSI_CHARSET, 1252 },
2599 { RUSSIAN_CHARSET, 1251 },
2600 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2602 int i;
2604 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2606 win_skip("Skipping the font charset test on a Win9x platform\n");
2607 return;
2610 if (!is_font_installed("Arial"))
2612 skip("Arial is not installed\n");
2613 return;
2616 for (i = 0; i < ARRAY_SIZE(cd); i++)
2618 if (cd[i].charset == SYMBOL_CHARSET)
2620 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2622 skip("Symbol or Wingdings is not installed\n");
2623 break;
2626 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2627 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2628 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2631 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2632 if (i > 2)
2634 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2635 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2637 else
2638 skip("Symbol or Wingdings is not installed\n");
2641 static void test_GdiGetCodePage(void)
2643 static const struct _matching_data
2645 UINT current_codepage;
2646 LPCSTR lfFaceName;
2647 UCHAR lfCharSet;
2648 UINT expected_codepage;
2649 } matching_data[] = {
2650 {1251, "Arial", ANSI_CHARSET, 1252},
2651 {1251, "Tahoma", ANSI_CHARSET, 1252},
2653 {1252, "Arial", ANSI_CHARSET, 1252},
2654 {1252, "Tahoma", ANSI_CHARSET, 1252},
2656 {1253, "Arial", ANSI_CHARSET, 1252},
2657 {1253, "Tahoma", ANSI_CHARSET, 1252},
2659 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2660 { 932, "Tahoma", ANSI_CHARSET, 1252},
2661 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2663 { 936, "Arial", ANSI_CHARSET, 936},
2664 { 936, "Tahoma", ANSI_CHARSET, 936},
2665 { 936, "Simsun", ANSI_CHARSET, 936},
2667 { 949, "Arial", ANSI_CHARSET, 949},
2668 { 949, "Tahoma", ANSI_CHARSET, 949},
2669 { 949, "Gulim", ANSI_CHARSET, 949},
2671 { 950, "Arial", ANSI_CHARSET, 950},
2672 { 950, "Tahoma", ANSI_CHARSET, 950},
2673 { 950, "PMingLiU", ANSI_CHARSET, 950},
2675 HDC hdc;
2676 LOGFONTA lf;
2677 HFONT hfont;
2678 UINT charset, acp;
2679 DWORD codepage;
2680 int i;
2682 if (!pGdiGetCodePage)
2684 skip("GdiGetCodePage not available on this platform\n");
2685 return;
2688 acp = GetACP();
2690 for (i = 0; i < ARRAY_SIZE(matching_data); i++)
2692 /* only test data matched current locale codepage */
2693 if (matching_data[i].current_codepage != acp)
2694 continue;
2696 if (!is_font_installed(matching_data[i].lfFaceName))
2698 skip("%s is not installed\n", matching_data[i].lfFaceName);
2699 continue;
2702 hdc = GetDC(0);
2704 memset(&lf, 0, sizeof(lf));
2705 lf.lfHeight = -16;
2706 lf.lfCharSet = matching_data[i].lfCharSet;
2707 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2708 hfont = CreateFontIndirectA(&lf);
2709 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2711 hfont = SelectObject(hdc, hfont);
2712 charset = GetTextCharset(hdc);
2713 codepage = pGdiGetCodePage(hdc);
2714 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2715 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2716 ok(codepage == matching_data[i].expected_codepage,
2717 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2719 hfont = SelectObject(hdc, hfont);
2720 DeleteObject(hfont);
2722 /* CLIP_DFA_DISABLE turns off the font association */
2723 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2724 hfont = CreateFontIndirectA(&lf);
2725 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2727 hfont = SelectObject(hdc, hfont);
2728 charset = GetTextCharset(hdc);
2729 codepage = pGdiGetCodePage(hdc);
2730 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2731 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2732 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2734 hfont = SelectObject(hdc, hfont);
2735 DeleteObject(hfont);
2737 ReleaseDC(NULL, hdc);
2741 static void test_GetFontUnicodeRanges(void)
2743 LOGFONTA lf;
2744 HDC hdc;
2745 HFONT hfont, hfont_old;
2746 DWORD size;
2747 GLYPHSET *gs;
2748 DWORD i;
2750 if (!pGetFontUnicodeRanges)
2752 win_skip("GetFontUnicodeRanges not available before W2K\n");
2753 return;
2756 memset(&lf, 0, sizeof(lf));
2757 lstrcpyA(lf.lfFaceName, "Arial");
2758 hfont = create_font("Arial", &lf);
2760 hdc = GetDC(0);
2761 hfont_old = SelectObject(hdc, hfont);
2763 size = pGetFontUnicodeRanges(NULL, NULL);
2764 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2766 size = pGetFontUnicodeRanges(hdc, NULL);
2767 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2769 gs = HeapAlloc(GetProcessHeap(), 0, size);
2771 size = pGetFontUnicodeRanges(hdc, gs);
2772 ok(size, "GetFontUnicodeRanges failed\n");
2774 if (0) /* Disabled to limit console spam */
2775 for (i = 0; i < gs->cRanges; i++)
2776 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2777 trace("found %u ranges\n", gs->cRanges);
2779 HeapFree(GetProcessHeap(), 0, gs);
2781 SelectObject(hdc, hfont_old);
2782 DeleteObject(hfont);
2783 ReleaseDC(NULL, hdc);
2786 struct enum_font_data
2788 int total, size;
2789 LOGFONTA *lf;
2792 struct enum_fullname_data
2794 int total, size;
2795 ENUMLOGFONTA *elf;
2798 struct enum_font_dataW
2800 int total, size;
2801 LOGFONTW *lf;
2804 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2806 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2807 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2809 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2810 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2812 if (type != TRUETYPE_FONTTYPE) return 1;
2814 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2816 if (0) /* Disabled to limit console spam */
2817 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2818 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2819 if (efd->total >= efd->size)
2821 efd->size = max( (efd->total + 1) * 2, 256 );
2822 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2823 if (!efd->lf) return 0;
2825 efd->lf[efd->total++] = *lf;
2827 return 1;
2830 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2832 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2833 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2835 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2836 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2838 if (type != TRUETYPE_FONTTYPE) return 1;
2840 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2842 if (0) /* Disabled to limit console spam */
2843 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2844 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2845 if (efd->total >= efd->size)
2847 efd->size = max( (efd->total + 1) * 2, 256 );
2848 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2849 if (!efd->lf) return 0;
2851 efd->lf[efd->total++] = *lf;
2853 return 1;
2856 static void get_charset_stats(struct enum_font_data *efd,
2857 int *ansi_charset, int *symbol_charset,
2858 int *russian_charset)
2860 int i;
2862 *ansi_charset = 0;
2863 *symbol_charset = 0;
2864 *russian_charset = 0;
2866 for (i = 0; i < efd->total; i++)
2868 switch (efd->lf[i].lfCharSet)
2870 case ANSI_CHARSET:
2871 (*ansi_charset)++;
2872 break;
2873 case SYMBOL_CHARSET:
2874 (*symbol_charset)++;
2875 break;
2876 case RUSSIAN_CHARSET:
2877 (*russian_charset)++;
2878 break;
2883 static void get_charset_statsW(struct enum_font_dataW *efd,
2884 int *ansi_charset, int *symbol_charset,
2885 int *russian_charset)
2887 int i;
2889 *ansi_charset = 0;
2890 *symbol_charset = 0;
2891 *russian_charset = 0;
2893 for (i = 0; i < efd->total; i++)
2895 switch (efd->lf[i].lfCharSet)
2897 case ANSI_CHARSET:
2898 (*ansi_charset)++;
2899 break;
2900 case SYMBOL_CHARSET:
2901 (*symbol_charset)++;
2902 break;
2903 case RUSSIAN_CHARSET:
2904 (*russian_charset)++;
2905 break;
2910 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2912 struct enum_font_data efd;
2913 struct enum_font_dataW efdw;
2914 LOGFONTA lf;
2915 HDC hdc;
2916 int i, ret, ansi_charset, symbol_charset, russian_charset;
2918 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2920 if (*font_name && !is_truetype_font_installed(font_name))
2922 skip("%s is not installed\n", font_name);
2923 return;
2925 memset( &efd, 0, sizeof(efd) );
2926 memset( &efdw, 0, sizeof(efdw) );
2928 hdc = GetDC(0);
2930 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2931 * while EnumFontFamiliesEx doesn't.
2933 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2936 * Use EnumFontFamiliesW since win98 crashes when the
2937 * second parameter is NULL using EnumFontFamilies
2939 efdw.total = 0;
2940 SetLastError(0xdeadbeef);
2941 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2942 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2943 if(ret)
2945 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2946 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2947 ansi_charset, symbol_charset, russian_charset);
2948 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2949 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2950 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2951 ok(russian_charset > 0 ||
2952 broken(russian_charset == 0), /* NT4 */
2953 "NULL family should enumerate RUSSIAN_CHARSET\n");
2956 efdw.total = 0;
2957 SetLastError(0xdeadbeef);
2958 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2959 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2960 if(ret)
2962 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2963 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2964 ansi_charset, symbol_charset, russian_charset);
2965 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2966 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2967 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2968 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2972 efd.total = 0;
2973 SetLastError(0xdeadbeef);
2974 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2975 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2976 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2977 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2978 ansi_charset, symbol_charset, russian_charset,
2979 *font_name ? font_name : "<empty>");
2980 if (*font_name)
2981 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2982 else
2983 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2984 for (i = 0; i < efd.total; i++)
2986 /* FIXME: remove completely once Wine is fixed */
2987 todo_wine_if(efd.lf[i].lfCharSet != font_charset)
2988 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2989 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2990 font_name, efd.lf[i].lfFaceName);
2993 memset(&lf, 0, sizeof(lf));
2994 lf.lfCharSet = ANSI_CHARSET;
2995 strcpy(lf.lfFaceName, font_name);
2996 efd.total = 0;
2997 SetLastError(0xdeadbeef);
2998 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2999 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3000 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3001 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
3002 ansi_charset, symbol_charset, russian_charset,
3003 *font_name ? font_name : "<empty>");
3004 if (font_charset == SYMBOL_CHARSET)
3006 if (*font_name)
3007 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
3008 else
3009 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
3011 else
3013 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
3014 for (i = 0; i < efd.total; i++)
3016 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3017 if (*font_name)
3018 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3019 font_name, efd.lf[i].lfFaceName);
3023 /* DEFAULT_CHARSET should enumerate all available charsets */
3024 memset(&lf, 0, sizeof(lf));
3025 lf.lfCharSet = DEFAULT_CHARSET;
3026 strcpy(lf.lfFaceName, font_name);
3027 efd.total = 0;
3028 SetLastError(0xdeadbeef);
3029 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3030 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3031 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3032 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
3033 ansi_charset, symbol_charset, russian_charset,
3034 *font_name ? font_name : "<empty>");
3035 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
3036 for (i = 0; i < efd.total; i++)
3038 if (*font_name)
3039 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3040 font_name, efd.lf[i].lfFaceName);
3042 if (*font_name)
3044 switch (font_charset)
3046 case ANSI_CHARSET:
3047 ok(ansi_charset > 0,
3048 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3049 ok(!symbol_charset,
3050 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
3051 ok(russian_charset > 0,
3052 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3053 break;
3054 case SYMBOL_CHARSET:
3055 ok(!ansi_charset,
3056 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
3057 ok(symbol_charset,
3058 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3059 ok(!russian_charset,
3060 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
3061 break;
3062 case DEFAULT_CHARSET:
3063 ok(ansi_charset > 0,
3064 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3065 ok(symbol_charset > 0,
3066 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3067 ok(russian_charset > 0,
3068 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3069 break;
3072 else
3074 ok(ansi_charset > 0,
3075 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3076 ok(symbol_charset > 0,
3077 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3078 ok(russian_charset > 0,
3079 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3082 memset(&lf, 0, sizeof(lf));
3083 lf.lfCharSet = SYMBOL_CHARSET;
3084 strcpy(lf.lfFaceName, font_name);
3085 efd.total = 0;
3086 SetLastError(0xdeadbeef);
3087 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3088 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3089 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3090 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
3091 ansi_charset, symbol_charset, russian_charset,
3092 *font_name ? font_name : "<empty>");
3093 if (*font_name && font_charset == ANSI_CHARSET)
3094 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
3095 else
3097 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
3098 for (i = 0; i < efd.total; i++)
3100 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3101 if (*font_name)
3102 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3103 font_name, efd.lf[i].lfFaceName);
3106 ok(!ansi_charset,
3107 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3108 ok(symbol_charset > 0,
3109 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3110 ok(!russian_charset,
3111 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3114 ReleaseDC(0, hdc);
3116 heap_free( efd.lf );
3117 heap_free( efdw.lf );
3120 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
3122 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
3123 LOGFONTA *target = (LOGFONTA *)lParam;
3124 const DWORD valid_bits = 0x003f01ff;
3125 CHARSETINFO csi;
3126 DWORD fs;
3128 if (type != TRUETYPE_FONTTYPE) return TRUE;
3130 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
3131 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
3132 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
3133 *target = *lf;
3134 return FALSE;
3138 return TRUE;
3141 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3143 struct enum_font_data *efd = (struct enum_font_data *)lParam;
3145 if (type != TRUETYPE_FONTTYPE) return 1;
3147 if (efd->total >= efd->size)
3149 efd->size = max( (efd->total + 1) * 2, 256 );
3150 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
3151 if (!efd->lf) return 0;
3153 efd->lf[efd->total++] = *lf;
3155 return 1;
3158 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3160 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3162 if (type != TRUETYPE_FONTTYPE) return 1;
3164 if (efnd->total >= efnd->size)
3166 efnd->size = max( (efnd->total + 1) * 2, 256 );
3167 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
3168 if (!efnd->elf) return 0;
3170 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3172 return 1;
3175 static void test_EnumFontFamiliesEx_default_charset(void)
3177 struct enum_font_data efd;
3178 LOGFONTA target, enum_font;
3179 UINT acp;
3180 HDC hdc;
3181 CHARSETINFO csi;
3183 acp = GetACP();
3184 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3185 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3186 return;
3189 hdc = GetDC(0);
3190 memset(&enum_font, 0, sizeof(enum_font));
3191 enum_font.lfCharSet = csi.ciCharset;
3192 target.lfFaceName[0] = '\0';
3193 target.lfCharSet = csi.ciCharset;
3194 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3195 if (target.lfFaceName[0] == '\0') {
3196 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3197 return;
3199 if (acp == 874 || acp == 1255 || acp == 1256) {
3200 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3201 target.lfCharSet = ANSI_CHARSET;
3204 memset(&efd, 0, sizeof(efd));
3205 memset(&enum_font, 0, sizeof(enum_font));
3206 strcpy(enum_font.lfFaceName, target.lfFaceName);
3207 enum_font.lfCharSet = DEFAULT_CHARSET;
3208 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3209 ReleaseDC(0, hdc);
3211 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3212 if (efd.total < 2)
3213 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3214 else
3215 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3216 "(%s) got charset %d expected %d\n",
3217 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3219 heap_free(efd.lf);
3220 return;
3223 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3225 HFONT hfont, hfont_prev;
3226 DWORD ret;
3227 GLYPHMETRICS gm1, gm2;
3228 LOGFONTA lf2 = *lf;
3229 WORD idx;
3231 if(!pGetGlyphIndicesA)
3232 return;
3234 /* negative widths are handled just as positive ones */
3235 lf2.lfWidth = -lf->lfWidth;
3237 SetLastError(0xdeadbeef);
3238 hfont = CreateFontIndirectA(lf);
3239 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3240 check_font("original", lf, hfont);
3242 hfont_prev = SelectObject(hdc, hfont);
3244 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3245 if (ret == GDI_ERROR || idx == 0xffff)
3247 SelectObject(hdc, hfont_prev);
3248 DeleteObject(hfont);
3249 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3250 return;
3253 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3254 memset(&gm1, 0xab, sizeof(gm1));
3255 SetLastError(0xdeadbeef);
3256 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3257 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3259 SelectObject(hdc, hfont_prev);
3260 DeleteObject(hfont);
3262 SetLastError(0xdeadbeef);
3263 hfont = CreateFontIndirectA(&lf2);
3264 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3265 check_font("negative width", &lf2, hfont);
3267 hfont_prev = SelectObject(hdc, hfont);
3269 memset(&gm2, 0xbb, sizeof(gm2));
3270 SetLastError(0xdeadbeef);
3271 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3272 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3274 SelectObject(hdc, hfont_prev);
3275 DeleteObject(hfont);
3277 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3278 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3279 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3280 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3281 gm1.gmCellIncX == gm2.gmCellIncX &&
3282 gm1.gmCellIncY == gm2.gmCellIncY,
3283 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3284 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3285 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3286 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3287 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3290 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3291 #include "pshpack2.h"
3292 typedef struct
3294 USHORT version;
3295 SHORT xAvgCharWidth;
3296 USHORT usWeightClass;
3297 USHORT usWidthClass;
3298 SHORT fsType;
3299 SHORT ySubscriptXSize;
3300 SHORT ySubscriptYSize;
3301 SHORT ySubscriptXOffset;
3302 SHORT ySubscriptYOffset;
3303 SHORT ySuperscriptXSize;
3304 SHORT ySuperscriptYSize;
3305 SHORT ySuperscriptXOffset;
3306 SHORT ySuperscriptYOffset;
3307 SHORT yStrikeoutSize;
3308 SHORT yStrikeoutPosition;
3309 SHORT sFamilyClass;
3310 PANOSE panose;
3311 ULONG ulUnicodeRange1;
3312 ULONG ulUnicodeRange2;
3313 ULONG ulUnicodeRange3;
3314 ULONG ulUnicodeRange4;
3315 CHAR achVendID[4];
3316 USHORT fsSelection;
3317 USHORT usFirstCharIndex;
3318 USHORT usLastCharIndex;
3319 /* According to the Apple spec, original version didn't have the below fields,
3320 * version numbers were taken from the OpenType spec.
3322 /* version 0 (TrueType 1.5) */
3323 USHORT sTypoAscender;
3324 USHORT sTypoDescender;
3325 USHORT sTypoLineGap;
3326 USHORT usWinAscent;
3327 USHORT usWinDescent;
3328 /* version 1 (TrueType 1.66) */
3329 ULONG ulCodePageRange1;
3330 ULONG ulCodePageRange2;
3331 /* version 2 (OpenType 1.2) */
3332 SHORT sxHeight;
3333 SHORT sCapHeight;
3334 USHORT usDefaultChar;
3335 USHORT usBreakChar;
3336 USHORT usMaxContext;
3337 /* version 4 (OpenType 1.6) */
3338 USHORT usLowerOpticalPointSize;
3339 USHORT usUpperOpticalPointSize;
3340 } TT_OS2_V4;
3341 #include "poppack.h"
3343 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3345 typedef struct
3347 USHORT version;
3348 USHORT num_tables;
3349 } cmap_header;
3351 typedef struct
3353 USHORT plat_id;
3354 USHORT enc_id;
3355 ULONG offset;
3356 } cmap_encoding_record;
3358 typedef struct
3360 USHORT format;
3361 USHORT length;
3362 USHORT language;
3364 BYTE glyph_ids[256];
3365 } cmap_format_0;
3367 typedef struct
3369 USHORT format;
3370 USHORT length;
3371 USHORT language;
3373 USHORT seg_countx2;
3374 USHORT search_range;
3375 USHORT entry_selector;
3376 USHORT range_shift;
3378 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3379 /* Then follows:
3380 USHORT pad;
3381 USHORT start_count[seg_countx2 / 2];
3382 USHORT id_delta[seg_countx2 / 2];
3383 USHORT id_range_offset[seg_countx2 / 2];
3384 USHORT glyph_ids[];
3386 } cmap_format_4;
3388 typedef struct
3390 USHORT end_count;
3391 USHORT start_count;
3392 USHORT id_delta;
3393 USHORT id_range_offset;
3394 } cmap_format_4_seg;
3396 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V4 *os2, WORD family, const char *name)
3398 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3399 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3400 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3401 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3402 os2->panose.bWeight, os2->panose.bProportion);
3405 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3407 int i;
3408 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3410 *first = 256;
3412 for(i = 0; i < 256; i++)
3414 if(cmap->glyph_ids[i] == 0) continue;
3415 *last = i;
3416 if(*first == 256) *first = i;
3418 if(*first == 256) return FALSE;
3419 return TRUE;
3422 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3424 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3425 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3426 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3427 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3428 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3431 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3433 int i;
3434 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3435 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3437 *first = 0x10000;
3439 for(i = 0; i < seg_count; i++)
3441 cmap_format_4_seg seg;
3443 get_seg4(cmap, i, &seg);
3445 if(seg.start_count > 0xfffe) break;
3447 if(*first == 0x10000) *first = seg.start_count;
3449 *last = min(seg.end_count, 0xfffe);
3452 if(*first == 0x10000) return FALSE;
3453 return TRUE;
3456 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3458 USHORT i;
3459 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3461 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3463 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3464 return (BYTE *)header + GET_BE_DWORD(record->offset);
3465 record++;
3467 return NULL;
3470 typedef enum
3472 cmap_none,
3473 cmap_ms_unicode,
3474 cmap_ms_symbol
3475 } cmap_type;
3477 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3479 LONG size, ret;
3480 cmap_header *header;
3481 void *cmap;
3482 BOOL r = FALSE;
3483 WORD format;
3485 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3486 ok(size != GDI_ERROR, "no cmap table found\n");
3487 if(size == GDI_ERROR) return FALSE;
3489 header = HeapAlloc(GetProcessHeap(), 0, size);
3490 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3491 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3492 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3494 cmap = get_cmap(header, 3, 1);
3495 if(cmap)
3496 *cmap_type = cmap_ms_unicode;
3497 else
3499 cmap = get_cmap(header, 3, 0);
3500 if(cmap) *cmap_type = cmap_ms_symbol;
3502 if(!cmap)
3504 *cmap_type = cmap_none;
3505 goto end;
3508 format = GET_BE_WORD(*(WORD *)cmap);
3509 switch(format)
3511 case 0:
3512 r = get_first_last_from_cmap0(cmap, first, last);
3513 break;
3514 case 4:
3515 r = get_first_last_from_cmap4(cmap, first, last, size);
3516 break;
3517 default:
3518 trace("unhandled cmap format %d\n", format);
3519 break;
3522 end:
3523 HeapFree(GetProcessHeap(), 0, header);
3524 return r;
3527 #define TT_PLATFORM_APPLE_UNICODE 0
3528 #define TT_PLATFORM_MACINTOSH 1
3529 #define TT_PLATFORM_MICROSOFT 3
3530 #define TT_APPLE_ID_DEFAULT 0
3531 #define TT_APPLE_ID_ISO_10646 2
3532 #define TT_APPLE_ID_UNICODE_2_0 3
3533 #define TT_MS_ID_SYMBOL_CS 0
3534 #define TT_MS_ID_UNICODE_CS 1
3535 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3536 #define TT_NAME_ID_FONT_FAMILY 1
3537 #define TT_NAME_ID_FONT_SUBFAMILY 2
3538 #define TT_NAME_ID_UNIQUE_ID 3
3539 #define TT_NAME_ID_FULL_NAME 4
3540 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3542 typedef struct sfnt_name
3544 USHORT platform_id;
3545 USHORT encoding_id;
3546 USHORT language_id;
3547 USHORT name_id;
3548 USHORT length;
3549 USHORT offset;
3550 } sfnt_name;
3552 static const LANGID mac_langid_table[] =
3554 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3555 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3556 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3557 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3558 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3559 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3560 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3561 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3562 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3563 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3564 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3565 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3566 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3567 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3568 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3569 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3570 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3571 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3572 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3573 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3574 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3575 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3576 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3577 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3578 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3579 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3580 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3581 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3582 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3583 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3584 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3585 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3586 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3587 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3588 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3589 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3590 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3591 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3592 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3593 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3594 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3595 0, /* TT_MAC_LANGID_YIDDISH */
3596 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3597 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3598 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3599 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3600 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3601 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3602 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3603 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3604 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3605 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3606 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3607 0, /* TT_MAC_LANGID_MOLDAVIAN */
3608 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3609 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3610 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3611 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3612 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3613 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3614 0, /* TT_MAC_LANGID_KURDISH */
3615 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3616 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3617 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3618 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3619 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3620 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3621 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3622 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3623 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3624 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3625 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3626 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3627 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3628 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3629 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3630 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3631 0, /* TT_MAC_LANGID_BURMESE */
3632 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3633 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3634 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3635 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3636 0, /* TT_MAC_LANGID_TAGALOG */
3637 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3638 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3639 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3640 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3641 0, /* TT_MAC_LANGID_GALLA */
3642 0, /* TT_MAC_LANGID_SOMALI */
3643 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3644 0, /* TT_MAC_LANGID_RUANDA */
3645 0, /* TT_MAC_LANGID_RUNDI */
3646 0, /* TT_MAC_LANGID_CHEWA */
3647 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3648 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3649 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3650 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3651 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3652 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3653 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3654 0, /* TT_MAC_LANGID_LATIN */
3655 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3656 0, /* TT_MAC_LANGID_GUARANI */
3657 0, /* TT_MAC_LANGID_AYMARA */
3658 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3659 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3660 0, /* TT_MAC_LANGID_DZONGKHA */
3661 0, /* TT_MAC_LANGID_JAVANESE */
3662 0, /* TT_MAC_LANGID_SUNDANESE */
3663 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3664 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3665 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3666 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3667 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3668 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3669 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3670 0, /* TT_MAC_LANGID_TONGAN */
3671 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3672 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3673 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3676 static inline WORD get_mac_code_page( const sfnt_name *name )
3678 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3679 return 10000 + GET_BE_WORD(name->encoding_id);
3682 static int match_name_table_language( const sfnt_name *name, LANGID lang )
3684 LANGID name_lang;
3685 int res = 0;
3687 switch (GET_BE_WORD(name->platform_id))
3689 case TT_PLATFORM_MICROSOFT:
3690 res += 5; /* prefer the Microsoft name */
3691 switch (GET_BE_WORD(name->encoding_id))
3693 case TT_MS_ID_UNICODE_CS:
3694 case TT_MS_ID_SYMBOL_CS:
3695 name_lang = GET_BE_WORD(name->language_id);
3696 break;
3697 default:
3698 return 0;
3700 break;
3701 case TT_PLATFORM_MACINTOSH:
3702 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3703 if (GET_BE_WORD(name->language_id) >= ARRAY_SIZE(mac_langid_table)) return 0;
3704 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3705 break;
3706 case TT_PLATFORM_APPLE_UNICODE:
3707 res += 2; /* prefer Unicode encodings */
3708 switch (GET_BE_WORD(name->encoding_id))
3710 case TT_APPLE_ID_DEFAULT:
3711 case TT_APPLE_ID_ISO_10646:
3712 case TT_APPLE_ID_UNICODE_2_0:
3713 if (GET_BE_WORD(name->language_id) >= ARRAY_SIZE(mac_langid_table)) return 0;
3714 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3715 break;
3716 default:
3717 return 0;
3719 break;
3720 default:
3721 return 0;
3723 if (name_lang == lang) res += 30;
3724 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3725 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3726 return res;
3729 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3731 struct sfnt_name_header
3733 USHORT format;
3734 USHORT number_of_record;
3735 USHORT storage_offset;
3736 } *header;
3737 sfnt_name *entry;
3738 BOOL r = FALSE;
3739 LONG size, offset, length;
3740 LONG c, ret;
3741 WCHAR *name;
3742 BYTE *data;
3743 USHORT i;
3744 int res, best_lang = 0, best_index = -1;
3746 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3747 ok(size != GDI_ERROR, "no name table found\n");
3748 if(size == GDI_ERROR) return FALSE;
3750 data = HeapAlloc(GetProcessHeap(), 0, size);
3751 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3752 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3754 header = (void *)data;
3755 header->format = GET_BE_WORD(header->format);
3756 header->number_of_record = GET_BE_WORD(header->number_of_record);
3757 header->storage_offset = GET_BE_WORD(header->storage_offset);
3758 if (header->format != 0)
3760 trace("got format %u\n", header->format);
3761 goto out;
3763 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3765 trace("number records out of range: %d\n", header->number_of_record);
3766 goto out;
3768 if (header->storage_offset >= size)
3770 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3771 goto out;
3774 entry = (void *)&header[1];
3775 for (i = 0; i < header->number_of_record; i++)
3777 if (GET_BE_WORD(entry[i].name_id) != name_id) continue;
3778 res = match_name_table_language( &entry[i], language_id);
3779 if (res > best_lang)
3781 best_lang = res;
3782 best_index = i;
3786 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset);
3787 length = GET_BE_WORD(entry[best_index].length);
3788 if (offset + length > size)
3790 trace("entry %d is out of range\n", best_index);
3791 goto out;
3793 if (length >= out_size)
3795 trace("buffer too small for entry %d\n", best_index);
3796 goto out;
3799 name = (WCHAR *)(data + offset);
3800 for (c = 0; c < length / 2; c++)
3801 out_buf[c] = GET_BE_WORD(name[c]);
3802 out_buf[c] = 0;
3804 r = TRUE;
3806 out:
3807 HeapFree(GetProcessHeap(), 0, data);
3808 return r;
3811 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3813 HDC hdc;
3814 HFONT hfont, hfont_old;
3815 TEXTMETRICA tmA;
3816 TT_OS2_V4 tt_os2;
3817 LONG size, ret;
3818 const char *font_name = lf->lfFaceName;
3819 DWORD cmap_first = 0, cmap_last = 0;
3820 UINT ascent, descent, cell_height;
3821 cmap_type cmap_type;
3822 BOOL sys_lang_non_english;
3824 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3825 hdc = GetDC(0);
3827 SetLastError(0xdeadbeef);
3828 hfont = CreateFontIndirectA(lf);
3829 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3831 hfont_old = SelectObject(hdc, hfont);
3833 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3834 if (size == GDI_ERROR)
3836 trace("OS/2 chunk was not found\n");
3837 goto end_of_test;
3839 if (size > sizeof(tt_os2))
3841 trace("got too large OS/2 chunk of size %u\n", size);
3842 size = sizeof(tt_os2);
3845 memset(&tt_os2, 0, sizeof(tt_os2));
3846 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3847 ok(ret >= TT_OS2_V0_SIZE && ret <= size, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE,
3848 size, ret);
3850 SetLastError(0xdeadbeef);
3851 ret = GetTextMetricsA(hdc, &tmA);
3852 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3854 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3856 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3858 else
3860 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3861 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3862 UINT os2_first_char, os2_last_char, default_char, break_char;
3863 USHORT version;
3864 TEXTMETRICW tmW;
3866 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3867 descent = abs((SHORT)GET_BE_WORD(tt_os2.usWinDescent));
3868 cell_height = ascent + descent;
3869 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3870 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3872 version = GET_BE_WORD(tt_os2.version);
3874 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3875 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3876 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3877 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3879 if (winetest_debug > 1)
3880 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3881 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3882 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3884 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3886 expect_first_W = 0;
3887 switch(GetACP())
3889 case 1255: /* Hebrew */
3890 expect_last_W = 0xf896;
3891 break;
3892 case 1257: /* Baltic */
3893 expect_last_W = 0xf8fd;
3894 break;
3895 default:
3896 expect_last_W = 0xf0ff;
3898 expect_break_W = 0x20;
3899 expect_default_W = expect_break_W - 1;
3900 expect_first_A = 0x1e;
3901 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3903 else
3905 expect_first_W = cmap_first;
3906 expect_last_W = cmap_last;
3907 if(os2_first_char <= 1)
3908 expect_break_W = os2_first_char + 2;
3909 else if(os2_first_char > 0xff)
3910 expect_break_W = 0x20;
3911 else
3912 expect_break_W = os2_first_char;
3913 expect_default_W = expect_break_W - 1;
3914 expect_first_A = expect_default_W - 1;
3915 expect_last_A = min(expect_last_W, 0xff);
3917 expect_break_A = expect_break_W;
3918 expect_default_A = expect_default_W;
3920 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3921 todo_wine_if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3922 ok(tmA.tmFirstChar == expect_first_A ||
3923 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3924 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3925 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3926 ok(tmA.tmLastChar == expect_last_A ||
3927 tmA.tmLastChar == 0xff /* win9x */,
3928 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3929 else
3930 skip("tmLastChar is DBCS lead byte\n");
3931 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3932 font_name, tmA.tmBreakChar, expect_break_A);
3933 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3934 "A: tmDefaultChar for %s got %02x expected %02x\n",
3935 font_name, tmA.tmDefaultChar, expect_default_A);
3938 SetLastError(0xdeadbeef);
3939 ret = GetTextMetricsW(hdc, &tmW);
3940 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3941 "GetTextMetricsW error %u\n", GetLastError());
3942 if (ret)
3944 /* Wine uses the os2 first char */
3945 todo_wine_if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3946 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3947 font_name, tmW.tmFirstChar, expect_first_W);
3949 /* Wine uses the os2 last char */
3950 todo_wine_if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3951 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3952 font_name, tmW.tmLastChar, expect_last_W);
3953 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3954 font_name, tmW.tmBreakChar, expect_break_W);
3955 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3956 "W: tmDefaultChar for %s got %02x expected %02x\n",
3957 font_name, tmW.tmDefaultChar, expect_default_W);
3959 /* Test the aspect ratio while we have tmW */
3960 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3961 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3962 tmW.tmDigitizedAspectX, ret);
3963 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3964 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3965 tmW.tmDigitizedAspectX, ret);
3969 /* test FF_ values */
3970 switch(tt_os2.panose.bFamilyType)
3972 case PAN_ANY:
3973 case PAN_NO_FIT:
3974 case PAN_FAMILY_TEXT_DISPLAY:
3975 case PAN_FAMILY_PICTORIAL:
3976 default:
3977 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3978 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3980 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3981 break;
3983 switch(tt_os2.panose.bSerifStyle)
3985 case PAN_ANY:
3986 case PAN_NO_FIT:
3987 default:
3988 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3989 break;
3991 case PAN_SERIF_COVE:
3992 case PAN_SERIF_OBTUSE_COVE:
3993 case PAN_SERIF_SQUARE_COVE:
3994 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3995 case PAN_SERIF_SQUARE:
3996 case PAN_SERIF_THIN:
3997 case PAN_SERIF_BONE:
3998 case PAN_SERIF_EXAGGERATED:
3999 case PAN_SERIF_TRIANGLE:
4000 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
4001 break;
4003 case PAN_SERIF_NORMAL_SANS:
4004 case PAN_SERIF_OBTUSE_SANS:
4005 case PAN_SERIF_PERP_SANS:
4006 case PAN_SERIF_FLARED:
4007 case PAN_SERIF_ROUNDED:
4008 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
4009 break;
4011 break;
4013 case PAN_FAMILY_SCRIPT:
4014 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
4015 break;
4017 case PAN_FAMILY_DECORATIVE:
4018 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
4019 break;
4022 test_negative_width(hdc, lf);
4024 end_of_test:
4025 SelectObject(hdc, hfont_old);
4026 DeleteObject(hfont);
4028 ReleaseDC(0, hdc);
4031 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4033 INT *enumed = (INT *)lParam;
4035 if (type == TRUETYPE_FONTTYPE)
4037 (*enumed)++;
4038 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
4040 return 1;
4043 static void test_GetTextMetrics(void)
4045 LOGFONTA lf;
4046 HDC hdc;
4047 INT enumed;
4049 /* Report only once */
4050 if(!pGetGlyphIndicesA)
4051 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
4053 hdc = GetDC(0);
4055 memset(&lf, 0, sizeof(lf));
4056 lf.lfCharSet = DEFAULT_CHARSET;
4057 enumed = 0;
4058 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
4059 trace("Tested metrics of %d truetype fonts\n", enumed);
4061 ReleaseDC(0, hdc);
4064 static void test_nonexistent_font(void)
4066 static const struct
4068 const char *name;
4069 int charset;
4070 } font_subst[] =
4072 { "Times New Roman Baltic", 186 },
4073 { "Times New Roman CE", 238 },
4074 { "Times New Roman CYR", 204 },
4075 { "Times New Roman Greek", 161 },
4076 { "Times New Roman TUR", 162 }
4078 static const struct
4080 const char *name;
4081 int charset;
4082 } shell_subst[] =
4084 { "MS Shell Dlg", 186 },
4085 { "MS Shell Dlg", 238 },
4086 { "MS Shell Dlg", 204 },
4087 { "MS Shell Dlg", 161 },
4088 { "MS Shell Dlg", 162 }
4090 LOGFONTA lf;
4091 HDC hdc;
4092 HFONT hfont;
4093 CHARSETINFO csi;
4094 INT cs, expected_cs, i, ret;
4095 char buf[LF_FACESIZE];
4097 expected_cs = GetACP();
4098 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
4100 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
4101 return;
4103 expected_cs = csi.ciCharset;
4104 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
4106 hdc = CreateCompatibleDC(0);
4108 for (i = 0; i < ARRAY_SIZE(shell_subst); i++)
4110 ret = is_font_installed(shell_subst[i].name);
4111 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4112 ret = is_truetype_font_installed(shell_subst[i].name);
4113 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4115 memset(&lf, 0, sizeof(lf));
4116 lf.lfHeight = -13;
4117 lf.lfWeight = FW_REGULAR;
4118 strcpy(lf.lfFaceName, shell_subst[i].name);
4119 hfont = CreateFontIndirectA(&lf);
4120 hfont = SelectObject(hdc, hfont);
4121 GetTextFaceA(hdc, sizeof(buf), buf);
4122 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4123 cs = GetTextCharset(hdc);
4124 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name);
4126 DeleteObject(SelectObject(hdc, hfont));
4128 memset(&lf, 0, sizeof(lf));
4129 lf.lfHeight = -13;
4130 lf.lfWeight = FW_DONTCARE;
4131 strcpy(lf.lfFaceName, shell_subst[i].name);
4132 hfont = CreateFontIndirectA(&lf);
4133 hfont = SelectObject(hdc, hfont);
4134 GetTextFaceA(hdc, sizeof(buf), buf);
4135 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4136 cs = GetTextCharset(hdc);
4137 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name);
4138 DeleteObject(SelectObject(hdc, hfont));
4141 if (!is_truetype_font_installed("Arial") ||
4142 !is_truetype_font_installed("Times New Roman"))
4144 DeleteDC(hdc);
4145 skip("Arial or Times New Roman not installed\n");
4146 return;
4149 memset(&lf, 0, sizeof(lf));
4150 lf.lfHeight = 100;
4151 lf.lfWeight = FW_REGULAR;
4152 lf.lfCharSet = ANSI_CHARSET;
4153 lf.lfPitchAndFamily = FF_SWISS;
4154 strcpy(lf.lfFaceName, "Nonexistent font");
4155 hfont = CreateFontIndirectA(&lf);
4156 hfont = SelectObject(hdc, hfont);
4157 GetTextFaceA(hdc, sizeof(buf), buf);
4158 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4159 cs = GetTextCharset(hdc);
4160 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4161 DeleteObject(SelectObject(hdc, hfont));
4163 memset(&lf, 0, sizeof(lf));
4164 lf.lfHeight = -13;
4165 lf.lfWeight = FW_DONTCARE;
4166 strcpy(lf.lfFaceName, "Nonexistent font");
4167 hfont = CreateFontIndirectA(&lf);
4168 hfont = SelectObject(hdc, hfont);
4169 GetTextFaceA(hdc, sizeof(buf), buf);
4170 todo_wine /* Wine uses Arial for all substitutions */
4171 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
4172 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
4173 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4174 "Got %s\n", buf);
4175 cs = GetTextCharset(hdc);
4176 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
4177 DeleteObject(SelectObject(hdc, hfont));
4179 memset(&lf, 0, sizeof(lf));
4180 lf.lfHeight = -13;
4181 lf.lfWeight = FW_REGULAR;
4182 strcpy(lf.lfFaceName, "Nonexistent font");
4183 hfont = CreateFontIndirectA(&lf);
4184 hfont = SelectObject(hdc, hfont);
4185 GetTextFaceA(hdc, sizeof(buf), buf);
4186 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4187 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
4188 cs = GetTextCharset(hdc);
4189 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4190 DeleteObject(SelectObject(hdc, hfont));
4192 memset(&lf, 0, sizeof(lf));
4193 lf.lfHeight = -13;
4194 lf.lfWeight = FW_DONTCARE;
4195 strcpy(lf.lfFaceName, "Times New Roman");
4196 hfont = CreateFontIndirectA(&lf);
4197 hfont = SelectObject(hdc, hfont);
4198 GetTextFaceA(hdc, sizeof(buf), buf);
4199 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
4200 cs = GetTextCharset(hdc);
4201 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4202 DeleteObject(SelectObject(hdc, hfont));
4204 for (i = 0; i < ARRAY_SIZE(font_subst); i++)
4206 ret = is_font_installed(font_subst[i].name);
4207 todo_wine
4208 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4209 "%s should be enumerated\n", font_subst[i].name);
4210 ret = is_truetype_font_installed(font_subst[i].name);
4211 todo_wine
4212 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4213 "%s should be enumerated\n", font_subst[i].name);
4215 memset(&lf, 0, sizeof(lf));
4216 lf.lfHeight = -13;
4217 lf.lfWeight = FW_REGULAR;
4218 strcpy(lf.lfFaceName, font_subst[i].name);
4219 hfont = CreateFontIndirectA(&lf);
4220 hfont = SelectObject(hdc, hfont);
4221 cs = GetTextCharset(hdc);
4222 if (font_subst[i].charset == expected_cs)
4224 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4225 GetTextFaceA(hdc, sizeof(buf), buf);
4226 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
4228 else
4230 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
4231 GetTextFaceA(hdc, sizeof(buf), buf);
4232 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4233 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
4235 DeleteObject(SelectObject(hdc, hfont));
4237 memset(&lf, 0, sizeof(lf));
4238 lf.lfHeight = -13;
4239 lf.lfWeight = FW_DONTCARE;
4240 strcpy(lf.lfFaceName, font_subst[i].name);
4241 hfont = CreateFontIndirectA(&lf);
4242 hfont = SelectObject(hdc, hfont);
4243 GetTextFaceA(hdc, sizeof(buf), buf);
4244 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
4245 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
4246 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
4247 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4248 "got %s for font %s\n", buf, font_subst[i].name);
4249 cs = GetTextCharset(hdc);
4250 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4251 DeleteObject(SelectObject(hdc, hfont));
4254 DeleteDC(hdc);
4257 static void test_RealizationInfo(void)
4259 struct font_realization_info {
4260 DWORD size;
4261 DWORD flags;
4262 DWORD cache_num;
4263 DWORD instance_id;
4264 DWORD unk;
4265 WORD face_index;
4266 WORD simulations;
4269 struct realization_info_t
4271 DWORD flags;
4272 DWORD cache_num;
4273 DWORD instance_id;
4276 HDC hdc;
4277 DWORD info[4], info2[10];
4278 BOOL r, have_file = FALSE;
4279 HFONT hfont, hfont_old;
4280 LOGFONTA lf;
4281 DWORD needed, read;
4282 HANDLE h;
4283 BYTE file[16], data[14];
4284 struct file_info
4286 FILETIME time;
4287 LARGE_INTEGER size;
4288 WCHAR path[MAX_PATH];
4289 } file_info;
4290 FILETIME time;
4291 LARGE_INTEGER size;
4293 if(!pGdiRealizationInfo)
4295 win_skip("GdiRealizationInfo not available\n");
4296 return;
4299 hdc = GetDC(0);
4301 memset(info, 0xcc, sizeof(info));
4302 r = pGdiRealizationInfo(hdc, info);
4303 ok(r != 0, "ret 0\n");
4304 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
4305 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4307 if (!is_truetype_font_installed("Tahoma"))
4309 skip("skipping GdiRealizationInfo with truetype font\n");
4310 goto end;
4313 memset(&lf, 0, sizeof(lf));
4314 strcpy(lf.lfFaceName, "Tahoma");
4315 lf.lfHeight = 20;
4316 lf.lfWeight = FW_BOLD;
4317 lf.lfItalic = 1;
4318 hfont = CreateFontIndirectA(&lf);
4319 hfont_old = SelectObject(hdc, hfont);
4321 memset(info, 0xcc, sizeof(info));
4322 r = pGdiRealizationInfo(hdc, info);
4323 ok(r != 0, "ret 0\n");
4324 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
4325 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4327 if (pGetFontRealizationInfo)
4329 struct font_realization_info *fri = (struct font_realization_info*)info2;
4330 struct realization_info_t *ri = (struct realization_info_t*)info;
4332 /* The first DWORD represents a struct size. On a
4333 newly rebooted system setting this to < 16 results
4334 in GetFontRealizationInfo failing. However there
4335 appears to be some caching going on which results
4336 in calls after a successful call also succeeding even
4337 if the size < 16. This means we can't reliably test
4338 this behaviour. */
4340 memset(info2, 0xcc, sizeof(info2));
4341 info2[0] = 16;
4342 r = pGetFontRealizationInfo(hdc, info2);
4343 ok(r != 0, "ret 0\n");
4344 /* We may get the '24' version here if that has been previously
4345 requested. */
4346 ok(fri->size == 16 || fri->size == 24, "got %d\n", info2[0]);
4347 ok(fri->flags == ri->flags, "flags mismatch\n");
4348 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4349 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4350 ok(info2[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2[6]);
4352 memset(info2, 0xcc, sizeof(info2));
4353 info2[0] = 28;
4354 r = pGetFontRealizationInfo(hdc, info2);
4355 ok(r == FALSE, "got %d\n", r);
4357 memset(info2, 0xcc, sizeof(info2));
4358 info2[0] = 24;
4359 r = pGetFontRealizationInfo(hdc, info2);
4360 ok(r != 0, "ret 0\n");
4361 ok(fri->size == 24, "got %d\n", fri->size);
4362 ok(fri->flags == ri->flags, "flags mismatch\n");
4363 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4364 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4365 ok(fri->simulations == 0x2, "got simulations flags 0x%04x\n", fri->simulations);
4366 ok(fri->face_index == 0, "got wrong face index %u\n", fri->face_index);
4367 ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4369 /* Test GetFontFileInfo() */
4370 /* invalid font id */
4371 SetLastError(0xdeadbeef);
4372 r = pGetFontFileInfo(0xabababab, 0, &file_info, sizeof(file_info), &needed);
4373 ok(r == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "ret %d gle %d\n", r, GetLastError());
4375 needed = 0;
4376 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed);
4377 ok(r != 0 || GetLastError() == ERROR_NOACCESS, "ret %d gle %d\n", r, GetLastError());
4379 if (r)
4381 ok(needed > 0 && needed < sizeof(file_info), "got needed size %u\n", needed);
4383 h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
4384 ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError());
4386 GetFileTime(h, NULL, NULL, &time);
4387 ok(!CompareFileTime(&file_info.time, &time), "time mismatch\n");
4388 GetFileSizeEx(h, &size);
4389 ok(file_info.size.QuadPart == size.QuadPart, "size mismatch\n");
4391 /* Read first 16 bytes from the file */
4392 ReadFile(h, file, sizeof(file), &read, NULL);
4393 CloseHandle(h);
4394 have_file = TRUE;
4396 /* shorter buffer */
4397 SetLastError(0xdeadbeef);
4398 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, needed - 1, &needed);
4399 ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %d\n", r, GetLastError());
4402 if (pGetFontFileData) {
4403 /* Get bytes 2 - 16 using GetFontFileData */
4404 r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data));
4405 ok(r != 0, "ret 0 gle %d\n", GetLastError());
4407 if (have_file)
4408 ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n");
4409 else
4410 win_skip("GetFontFileInfo() failed, skipping\n");
4414 DeleteObject(SelectObject(hdc, hfont_old));
4416 end:
4417 ReleaseDC(0, hdc);
4420 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4421 the nul in the count of characters copied when the face name buffer is not
4422 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4423 always includes it. */
4424 static void test_GetTextFace(void)
4426 static const char faceA[] = "Tahoma";
4427 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
4428 LOGFONTA fA = {0};
4429 LOGFONTW fW = {0};
4430 char bufA[LF_FACESIZE];
4431 WCHAR bufW[LF_FACESIZE];
4432 HFONT f, g;
4433 HDC dc;
4434 int n;
4436 if(!is_font_installed("Tahoma"))
4438 skip("Tahoma is not installed so skipping this test\n");
4439 return;
4442 /* 'A' case. */
4443 memcpy(fA.lfFaceName, faceA, sizeof faceA);
4444 f = CreateFontIndirectA(&fA);
4445 ok(f != NULL, "CreateFontIndirectA failed\n");
4447 dc = GetDC(NULL);
4448 g = SelectObject(dc, f);
4449 n = GetTextFaceA(dc, sizeof bufA, bufA);
4450 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
4451 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
4453 /* Play with the count arg. */
4454 bufA[0] = 'x';
4455 n = GetTextFaceA(dc, 0, bufA);
4456 ok(n == 0, "GetTextFaceA returned %d\n", n);
4457 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4459 bufA[0] = 'x';
4460 n = GetTextFaceA(dc, 1, bufA);
4461 ok(n == 0, "GetTextFaceA returned %d\n", n);
4462 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4464 bufA[0] = 'x'; bufA[1] = 'y';
4465 n = GetTextFaceA(dc, 2, bufA);
4466 ok(n == 1, "GetTextFaceA returned %d\n", n);
4467 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
4469 n = GetTextFaceA(dc, 0, NULL);
4470 ok(n == sizeof faceA ||
4471 broken(n == 0), /* win98, winMe */
4472 "GetTextFaceA returned %d\n", n);
4474 DeleteObject(SelectObject(dc, g));
4475 ReleaseDC(NULL, dc);
4477 /* 'W' case. */
4478 memcpy(fW.lfFaceName, faceW, sizeof faceW);
4479 SetLastError(0xdeadbeef);
4480 f = CreateFontIndirectW(&fW);
4481 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
4483 win_skip("CreateFontIndirectW is not implemented\n");
4484 return;
4486 ok(f != NULL, "CreateFontIndirectW failed\n");
4488 dc = GetDC(NULL);
4489 g = SelectObject(dc, f);
4490 n = GetTextFaceW(dc, ARRAY_SIZE(bufW), bufW);
4491 ok(n == ARRAY_SIZE(faceW), "GetTextFaceW returned %d\n", n);
4492 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
4494 /* Play with the count arg. */
4495 bufW[0] = 'x';
4496 n = GetTextFaceW(dc, 0, bufW);
4497 ok(n == 0, "GetTextFaceW returned %d\n", n);
4498 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4500 bufW[0] = 'x';
4501 n = GetTextFaceW(dc, 1, bufW);
4502 ok(n == 1, "GetTextFaceW returned %d\n", n);
4503 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4505 bufW[0] = 'x'; bufW[1] = 'y';
4506 n = GetTextFaceW(dc, 2, bufW);
4507 ok(n == 2, "GetTextFaceW returned %d\n", n);
4508 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4510 n = GetTextFaceW(dc, 0, NULL);
4511 ok(n == ARRAY_SIZE(faceW), "GetTextFaceW returned %d\n", n);
4513 DeleteObject(SelectObject(dc, g));
4514 ReleaseDC(NULL, dc);
4517 static void test_orientation(void)
4519 static const char test_str[11] = "Test String";
4520 HDC hdc;
4521 LOGFONTA lf;
4522 HFONT hfont, old_hfont;
4523 SIZE size;
4525 if (!is_truetype_font_installed("Arial"))
4527 skip("Arial is not installed\n");
4528 return;
4531 hdc = CreateCompatibleDC(0);
4532 memset(&lf, 0, sizeof(lf));
4533 lstrcpyA(lf.lfFaceName, "Arial");
4534 lf.lfHeight = 72;
4535 lf.lfOrientation = lf.lfEscapement = 900;
4536 hfont = create_font("orientation", &lf);
4537 old_hfont = SelectObject(hdc, hfont);
4538 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4539 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4540 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4541 SelectObject(hdc, old_hfont);
4542 DeleteObject(hfont);
4543 DeleteDC(hdc);
4546 static void test_oemcharset(void)
4548 HDC hdc;
4549 LOGFONTA lf, clf;
4550 HFONT hfont, old_hfont;
4551 int charset;
4553 hdc = CreateCompatibleDC(0);
4554 ZeroMemory(&lf, sizeof(lf));
4555 lf.lfHeight = 12;
4556 lf.lfCharSet = OEM_CHARSET;
4557 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4558 lstrcpyA(lf.lfFaceName, "Terminal");
4559 hfont = CreateFontIndirectA(&lf);
4560 old_hfont = SelectObject(hdc, hfont);
4561 charset = GetTextCharset(hdc);
4562 todo_wine
4563 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4564 hfont = SelectObject(hdc, old_hfont);
4565 GetObjectA(hfont, sizeof(clf), &clf);
4566 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4567 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4568 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4569 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4570 DeleteObject(hfont);
4571 DeleteDC(hdc);
4574 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4575 const TEXTMETRICA *lpntme,
4576 DWORD FontType, LPARAM lParam)
4578 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4579 CHARSETINFO csi;
4580 LOGFONTA lf = *lpelfe;
4581 HFONT hfont;
4582 DWORD found_subset;
4584 /* skip bitmap, proportional or vertical font */
4585 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4586 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4587 lf.lfFaceName[0] == '@')
4588 return 1;
4590 /* skip linked font */
4591 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4592 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4593 return 1;
4595 /* skip linked font, like SimSun-ExtB */
4596 switch (lpelfe->lfCharSet) {
4597 case SHIFTJIS_CHARSET:
4598 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4599 break;
4600 case GB2312_CHARSET:
4601 case CHINESEBIG5_CHARSET:
4602 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4603 break;
4604 case HANGEUL_CHARSET:
4605 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4606 break;
4607 default:
4608 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4609 break;
4611 if (!found_subset)
4612 return 1;
4614 /* test with an odd height */
4615 lf.lfHeight = -19;
4616 lf.lfWidth = 0;
4617 hfont = CreateFontIndirectA(&lf);
4618 if (hfont)
4620 *(HFONT *)lParam = hfont;
4621 return 0;
4623 return 1;
4626 static void test_GetGlyphOutline(void)
4628 HDC hdc;
4629 GLYPHMETRICS gm, gm2;
4630 LOGFONTA lf;
4631 HFONT hfont, old_hfont;
4632 INT ret, ret2;
4633 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4634 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4635 static const struct
4637 UINT cs;
4638 UINT a;
4639 UINT w;
4640 } c[] =
4642 {ANSI_CHARSET, 0x30, 0x30},
4643 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4644 {HANGEUL_CHARSET, 0x8141, 0xac02},
4645 {GB2312_CHARSET, 0x8141, 0x4e04},
4646 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4648 UINT i;
4650 if (!is_truetype_font_installed("Tahoma"))
4652 skip("Tahoma is not installed\n");
4653 return;
4656 hdc = CreateCompatibleDC(0);
4657 memset(&lf, 0, sizeof(lf));
4658 lf.lfHeight = 72;
4659 lstrcpyA(lf.lfFaceName, "Tahoma");
4660 SetLastError(0xdeadbeef);
4661 hfont = CreateFontIndirectA(&lf);
4662 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4663 old_hfont = SelectObject(hdc, hfont);
4665 memset(&gm, 0, sizeof(gm));
4666 SetLastError(0xdeadbeef);
4667 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4668 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4670 memset(&gm, 0, sizeof(gm));
4671 SetLastError(0xdeadbeef);
4672 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4673 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4674 ok(GetLastError() == 0xdeadbeef ||
4675 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4676 "expected 0xdeadbeef, got %u\n", GetLastError());
4678 memset(&gm, 0, sizeof(gm));
4679 SetLastError(0xdeadbeef);
4680 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4681 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4682 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4684 memset(&gm, 0, sizeof(gm));
4685 SetLastError(0xdeadbeef);
4686 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4687 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4689 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4690 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4693 /* test for needed buffer size request on space char */
4694 memset(&gm, 0, sizeof(gm));
4695 SetLastError(0xdeadbeef);
4696 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4697 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4699 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4700 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX);
4701 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY);
4704 /* requesting buffer size for space char + error */
4705 memset(&gm, 0, sizeof(gm));
4706 SetLastError(0xdeadbeef);
4707 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4708 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4710 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4711 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4712 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX);
4713 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY);
4716 /* test GetGlyphOutline with a buffer too small */
4717 SetLastError(0xdeadbeef);
4718 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat);
4719 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4720 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4722 for (i = 0; i < ARRAY_SIZE(fmt); ++i)
4724 DWORD dummy;
4726 memset(&gm, 0xab, sizeof(gm));
4727 SetLastError(0xdeadbeef);
4728 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4729 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4731 if (fmt[i] == GGO_METRICS)
4732 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4733 else
4734 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4735 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4736 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4739 memset(&gm, 0xab, sizeof(gm));
4740 SetLastError(0xdeadbeef);
4741 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4742 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4744 if (fmt[i] == GGO_METRICS)
4745 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4746 else
4747 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4748 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4749 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4752 memset(&gm, 0xab, sizeof(gm));
4753 SetLastError(0xdeadbeef);
4754 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4755 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4757 if (fmt[i] == GGO_METRICS)
4758 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4759 else
4760 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4761 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4762 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4765 memset(&gm, 0xab, sizeof(gm));
4766 SetLastError(0xdeadbeef);
4767 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4768 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4770 if (fmt[i] == GGO_METRICS) {
4771 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4772 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4773 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4775 else
4777 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4778 memset(&gm2, 0xab, sizeof(gm2));
4779 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4780 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4785 SelectObject(hdc, old_hfont);
4786 DeleteObject(hfont);
4788 for (i = 0; i < ARRAY_SIZE(c); ++i)
4790 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4791 TEXTMETRICA tm;
4793 lf.lfFaceName[0] = '\0';
4794 lf.lfCharSet = c[i].cs;
4795 lf.lfPitchAndFamily = 0;
4796 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4798 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4799 continue;
4802 old_hfont = SelectObject(hdc, hfont);
4804 /* expected to ignore superfluous bytes (sigle-byte character) */
4805 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4806 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4807 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4809 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4810 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4811 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4813 /* expected to ignore superfluous bytes (double-byte character) */
4814 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4815 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4816 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4817 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4819 /* expected to match wide-char version results */
4820 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4821 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4823 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4825 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4826 continue;
4828 DeleteObject(SelectObject(hdc, hfont));
4829 if (c[i].a <= 0xff)
4831 DeleteObject(SelectObject(hdc, old_hfont));
4832 continue;
4835 ret = GetObjectA(hfont, sizeof lf, &lf);
4836 ok(ret > 0, "GetObject error %u\n", GetLastError());
4838 ret = GetTextMetricsA(hdc, &tm);
4839 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4840 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4841 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4842 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4843 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4844 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4845 "expected %d, got %d (%s:%d)\n",
4846 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4848 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4849 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4850 ok(gm2.gmCellIncY == -lf.lfHeight,
4851 "expected %d, got %d (%s:%d)\n",
4852 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4854 lf.lfItalic = TRUE;
4855 hfont = CreateFontIndirectA(&lf);
4856 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4857 DeleteObject(SelectObject(hdc, hfont));
4858 ret = GetTextMetricsA(hdc, &tm);
4859 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4860 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4861 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4862 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4863 "expected %d, got %d (%s:%d)\n",
4864 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4866 lf.lfItalic = FALSE;
4867 lf.lfEscapement = lf.lfOrientation = 2700;
4868 hfont = CreateFontIndirectA(&lf);
4869 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4870 DeleteObject(SelectObject(hdc, hfont));
4871 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4872 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4873 ok(gm2.gmCellIncY == -lf.lfHeight,
4874 "expected %d, got %d (%s:%d)\n",
4875 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4877 hfont = SelectObject(hdc, old_hfont);
4878 DeleteObject(hfont);
4881 DeleteDC(hdc);
4884 /* bug #9995: there is a limit to the character width that can be specified */
4885 static void test_GetTextMetrics2(const char *fontname, int font_height)
4887 HFONT of, hf;
4888 HDC hdc;
4889 TEXTMETRICA tm;
4890 BOOL ret;
4891 int ave_width, height, width, ratio, scale;
4893 if (!is_truetype_font_installed( fontname)) {
4894 skip("%s is not installed\n", fontname);
4895 return;
4897 hdc = CreateCompatibleDC(0);
4898 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4899 /* select width = 0 */
4900 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4901 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4902 DEFAULT_QUALITY, VARIABLE_PITCH,
4903 fontname);
4904 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4905 of = SelectObject( hdc, hf);
4906 ret = GetTextMetricsA( hdc, &tm);
4907 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4908 height = tm.tmHeight;
4909 ave_width = tm.tmAveCharWidth;
4910 SelectObject( hdc, of);
4911 DeleteObject( hf);
4913 trace("height %d, ave width %d\n", height, ave_width);
4915 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4917 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4918 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4919 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4920 ok(hf != 0, "CreateFont failed\n");
4921 of = SelectObject(hdc, hf);
4922 ret = GetTextMetricsA(hdc, &tm);
4923 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4924 SelectObject(hdc, of);
4925 DeleteObject(hf);
4927 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4928 break;
4931 DeleteDC(hdc);
4933 ratio = width / height;
4934 scale = width / ave_width;
4936 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4937 width, height, ratio, width, ave_width, scale);
4939 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4942 static void test_GetCharacterPlacement(void)
4944 GCP_RESULTSA result;
4945 DWORD size, size2;
4946 WCHAR glyphs[20];
4947 HDC hdc;
4949 hdc = CreateCompatibleDC(0);
4950 ok(!!hdc, "CreateCompatibleDC failed\n");
4952 memset(&result, 0, sizeof(result));
4953 result.lStructSize = sizeof(result);
4954 result.lpGlyphs = glyphs;
4955 result.nGlyphs = 20;
4957 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, &result, 0);
4958 ok(size, "GetCharacterPlacementA failed!\n");
4960 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, NULL, 0);
4961 ok(size2, "GetCharacterPlacementA failed!\n");
4962 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
4964 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, NULL, GCP_REORDER);
4965 ok(size2, "GetCharacterPlacementA failed!\n");
4966 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
4968 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, &result, GCP_REORDER);
4969 ok(size, "GetCharacterPlacementA failed!\n");
4970 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
4972 DeleteDC(hdc);
4975 static void test_CreateFontIndirect(void)
4977 LOGFONTA lf, getobj_lf;
4978 int ret, i;
4979 HFONT hfont;
4980 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4982 memset(&lf, 0, sizeof(lf));
4983 lf.lfCharSet = ANSI_CHARSET;
4984 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4985 lf.lfHeight = 16;
4986 lf.lfWidth = 16;
4987 lf.lfQuality = DEFAULT_QUALITY;
4988 lf.lfItalic = FALSE;
4989 lf.lfWeight = FW_DONTCARE;
4991 for (i = 0; i < ARRAY_SIZE(TestName); i++)
4993 lstrcpyA(lf.lfFaceName, TestName[i]);
4994 hfont = CreateFontIndirectA(&lf);
4995 ok(hfont != 0, "CreateFontIndirectA failed\n");
4996 SetLastError(0xdeadbeef);
4997 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4998 ok(ret, "GetObject failed: %d\n", GetLastError());
4999 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
5000 ok(lf.lfWeight == getobj_lf.lfWeight ||
5001 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
5002 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
5003 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
5004 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
5005 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
5006 DeleteObject(hfont);
5010 static void test_CreateFontIndirectEx(void)
5012 ENUMLOGFONTEXDVA lfex;
5013 HFONT hfont;
5015 if (!pCreateFontIndirectExA)
5017 win_skip("CreateFontIndirectExA is not available\n");
5018 return;
5021 if (!is_truetype_font_installed("Arial"))
5023 skip("Arial is not installed\n");
5024 return;
5027 SetLastError(0xdeadbeef);
5028 hfont = pCreateFontIndirectExA(NULL);
5029 ok(hfont == NULL, "got %p\n", hfont);
5030 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
5032 memset(&lfex, 0, sizeof(lfex));
5033 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
5034 hfont = pCreateFontIndirectExA(&lfex);
5035 ok(hfont != 0, "CreateFontIndirectEx failed\n");
5036 if (hfont)
5037 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
5038 DeleteObject(hfont);
5041 static void free_font(void *font)
5043 UnmapViewOfFile(font);
5046 static void *load_font(const char *font_name, DWORD *font_size)
5048 char file_name[MAX_PATH];
5049 HANDLE file, mapping;
5050 void *font;
5052 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
5053 strcat(file_name, "\\fonts\\");
5054 strcat(file_name, font_name);
5056 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
5057 if (file == INVALID_HANDLE_VALUE) return NULL;
5059 *font_size = GetFileSize(file, NULL);
5061 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
5062 if (!mapping)
5064 CloseHandle(file);
5065 return NULL;
5068 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5070 CloseHandle(file);
5071 CloseHandle(mapping);
5072 return font;
5075 static void test_AddFontMemResource(void)
5077 void *font;
5078 DWORD font_size, num_fonts;
5079 HANDLE ret;
5080 BOOL bRet;
5082 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
5084 win_skip("AddFontMemResourceEx is not available on this platform\n");
5085 return;
5088 font = load_font("sserife.fon", &font_size);
5089 if (!font)
5091 skip("Unable to locate and load font sserife.fon\n");
5092 return;
5095 SetLastError(0xdeadbeef);
5096 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
5097 ok(!ret, "AddFontMemResourceEx should fail\n");
5098 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5099 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5100 GetLastError());
5102 SetLastError(0xdeadbeef);
5103 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
5104 ok(!ret, "AddFontMemResourceEx should fail\n");
5105 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5106 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5107 GetLastError());
5109 SetLastError(0xdeadbeef);
5110 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
5111 ok(!ret, "AddFontMemResourceEx should fail\n");
5112 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5113 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5114 GetLastError());
5116 SetLastError(0xdeadbeef);
5117 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
5118 ok(!ret, "AddFontMemResourceEx should fail\n");
5119 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5120 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5121 GetLastError());
5123 SetLastError(0xdeadbeef);
5124 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
5125 ok(!ret, "AddFontMemResourceEx should fail\n");
5126 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5127 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5128 GetLastError());
5130 SetLastError(0xdeadbeef);
5131 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
5132 ok(!ret, "AddFontMemResourceEx should fail\n");
5133 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5134 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5135 GetLastError());
5137 num_fonts = 0xdeadbeef;
5138 SetLastError(0xdeadbeef);
5139 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
5140 ok(!ret, "AddFontMemResourceEx should fail\n");
5141 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5142 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5143 GetLastError());
5144 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5146 if (0) /* hangs under windows 2000 */
5148 num_fonts = 0xdeadbeef;
5149 SetLastError(0xdeadbeef);
5150 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
5151 ok(!ret, "AddFontMemResourceEx should fail\n");
5152 ok(GetLastError() == 0xdeadbeef,
5153 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5154 GetLastError());
5155 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5158 num_fonts = 0xdeadbeef;
5159 SetLastError(0xdeadbeef);
5160 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
5161 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
5162 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5163 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
5165 free_font(font);
5167 SetLastError(0xdeadbeef);
5168 bRet = pRemoveFontMemResourceEx(ret);
5169 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
5171 /* test invalid pointer to number of loaded fonts */
5172 font = load_font("sserife.fon", &font_size);
5173 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
5175 SetLastError(0xdeadbeef);
5176 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
5177 ok(!ret, "AddFontMemResourceEx should fail\n");
5178 ok(GetLastError() == 0xdeadbeef,
5179 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5180 GetLastError());
5182 SetLastError(0xdeadbeef);
5183 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
5184 ok(!ret, "AddFontMemResourceEx should fail\n");
5185 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5186 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5187 GetLastError());
5189 free_font(font);
5192 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5194 LOGFONTA *lf;
5196 if (type != TRUETYPE_FONTTYPE) return 1;
5198 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5200 lf = (LOGFONTA *)lparam;
5201 *lf = *elf;
5202 return 0;
5205 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5207 int ret;
5208 LOGFONTA *lf;
5210 if (type != TRUETYPE_FONTTYPE) return 1;
5212 lf = (LOGFONTA *)lparam;
5213 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
5214 if(ret == 0)
5216 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5217 *lf = *elf;
5218 return 0;
5220 return 1;
5223 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5225 return lparam;
5228 static void test_EnumFonts(void)
5230 int ret;
5231 LOGFONTA lf;
5232 HDC hdc;
5234 if (!is_truetype_font_installed("Arial"))
5236 skip("Arial is not installed\n");
5237 return;
5240 /* Windows uses localized font face names, so Arial Bold won't be found */
5241 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
5243 skip("User locale is not English, skipping the test\n");
5244 return;
5247 hdc = CreateCompatibleDC(0);
5249 /* check that the enumproc's retval is returned */
5250 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
5251 ok(ret == 0xcafe, "got %08x\n", ret);
5253 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
5254 ok(!ret, "font Arial is not enumerated\n");
5255 ret = strcmp(lf.lfFaceName, "Arial");
5256 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5257 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5259 strcpy(lf.lfFaceName, "Arial");
5260 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5261 ok(!ret, "font Arial is not enumerated\n");
5262 ret = strcmp(lf.lfFaceName, "Arial");
5263 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5264 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5266 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
5267 ok(!ret, "font Arial Bold is not enumerated\n");
5268 ret = strcmp(lf.lfFaceName, "Arial");
5269 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5270 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5272 strcpy(lf.lfFaceName, "Arial Bold");
5273 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5274 ok(ret, "font Arial Bold should not be enumerated\n");
5276 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
5277 ok(!ret, "font Arial Bold Italic is not enumerated\n");
5278 ret = strcmp(lf.lfFaceName, "Arial");
5279 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5280 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5282 strcpy(lf.lfFaceName, "Arial Bold Italic");
5283 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5284 ok(ret, "font Arial Bold Italic should not be enumerated\n");
5286 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
5287 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5289 strcpy(lf.lfFaceName, "Arial Italic Bold");
5290 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5291 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5293 DeleteDC(hdc);
5296 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5298 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5300 if (0) /* Disabled to limit console spam */
5301 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5302 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5304 if (type != TRUETYPE_FONTTYPE) return 1;
5305 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1;
5307 if (efnd->total >= efnd->size)
5309 efnd->size = max( (efnd->total + 1) * 2, 256 );
5310 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5311 if (!efnd->elf) return 0;
5313 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5314 return 0;
5317 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5319 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5321 if (0) /* Disabled to limit console spam */
5322 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5323 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5325 if (type != TRUETYPE_FONTTYPE) return 1;
5326 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1;
5328 if (efnd->total >= efnd->size)
5330 efnd->size = max( (efnd->total + 1) * 2, 256 );
5331 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5332 if (!efnd->elf) return 0;
5334 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5335 return 0;
5338 static void test_EnumFonts_subst(void)
5340 int ret;
5341 LOGFONTA lf;
5342 HDC hdc;
5343 struct enum_fullname_data efnd;
5345 ret = is_font_installed("MS Shell Dlg");
5346 ok(ret, "MS Shell Dlg should be enumerated\n");
5347 ret = is_truetype_font_installed("MS Shell Dlg");
5348 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n");
5350 ret = is_font_installed("MS Shell Dlg 2");
5351 ok(ret, "MS Shell Dlg 2 should be enumerated\n");
5352 ret = is_truetype_font_installed("MS Shell Dlg 2");
5353 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5355 hdc = CreateCompatibleDC(0);
5357 memset(&efnd, 0, sizeof(efnd));
5358 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5359 ok(ret, "MS Shell Dlg should not be enumerated\n");
5360 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n");
5362 memset(&lf, 0, sizeof(lf));
5363 lf.lfCharSet = DEFAULT_CHARSET;
5365 efnd.total = 0;
5366 strcpy(lf.lfFaceName, "MS Shell Dlg");
5367 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5368 ok(!ret, "MS Shell Dlg should be enumerated\n");
5369 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n");
5370 if (efnd.total)
5372 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
5373 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5374 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg");
5375 ok(ret, "did not expect MS Shell Dlg\n");
5378 efnd.total = 0;
5379 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5380 ok(ret, "MS Shell Dlg 2 should not be enumerated\n");
5381 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n");
5383 efnd.total = 0;
5384 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
5385 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5386 ok(!ret, "MS Shell Dlg 2 should be enumerated\n");
5387 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n");
5388 if (efnd.total)
5390 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
5391 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5392 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
5393 ok(ret, "did not expect MS Shell Dlg 2\n");
5396 heap_free(efnd.elf);
5397 DeleteDC(hdc);
5400 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5402 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
5403 const char *fullname = (const char *)lParam;
5405 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
5407 return 1;
5410 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
5412 HDC hdc = GetDC(0);
5413 BOOL ret = FALSE;
5415 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
5416 ret = TRUE;
5418 ReleaseDC(0, hdc);
5419 return ret;
5422 static void test_fullname(void)
5424 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5425 WCHAR bufW[LF_FULLFACESIZE];
5426 char bufA[LF_FULLFACESIZE];
5427 HFONT hfont, of;
5428 LOGFONTA lf;
5429 HDC hdc;
5430 int i;
5431 DWORD ret;
5433 hdc = CreateCompatibleDC(0);
5434 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5436 memset(&lf, 0, sizeof(lf));
5437 lf.lfCharSet = ANSI_CHARSET;
5438 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5439 lf.lfHeight = 16;
5440 lf.lfWidth = 16;
5441 lf.lfQuality = DEFAULT_QUALITY;
5442 lf.lfItalic = FALSE;
5443 lf.lfWeight = FW_DONTCARE;
5445 for (i = 0; i < ARRAY_SIZE(TestName); i++)
5447 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
5449 skip("%s is not installed\n", TestName[i]);
5450 continue;
5453 lstrcpyA(lf.lfFaceName, TestName[i]);
5454 hfont = CreateFontIndirectA(&lf);
5455 ok(hfont != 0, "CreateFontIndirectA failed\n");
5457 of = SelectObject(hdc, hfont);
5458 bufW[0] = 0;
5459 bufA[0] = 0;
5460 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
5461 ok(ret, "face full name could not be read\n");
5462 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
5463 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
5464 SelectObject(hdc, of);
5465 DeleteObject(hfont);
5467 DeleteDC(hdc);
5470 static WCHAR *prepend_at(WCHAR *family)
5472 if (!family)
5473 return NULL;
5475 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
5476 family[0] = '@';
5477 return family;
5480 static void test_fullname2_helper(const char *Family)
5482 char *FamilyName, *FaceName, *StyleName, *otmStr;
5483 struct enum_fullname_data efnd;
5484 WCHAR *bufW;
5485 char *bufA;
5486 HFONT hfont, of;
5487 LOGFONTA lf;
5488 HDC hdc;
5489 int i;
5490 DWORD otm_size, ret, buf_size;
5491 OUTLINETEXTMETRICA *otm;
5492 BOOL want_vertical, get_vertical;
5493 want_vertical = ( Family[0] == '@' );
5495 hdc = CreateCompatibleDC(0);
5496 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5498 memset(&lf, 0, sizeof(lf));
5499 lf.lfCharSet = DEFAULT_CHARSET;
5500 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5501 lf.lfHeight = 16;
5502 lf.lfWidth = 16;
5503 lf.lfQuality = DEFAULT_QUALITY;
5504 lf.lfItalic = FALSE;
5505 lf.lfWeight = FW_DONTCARE;
5506 strcpy(lf.lfFaceName, Family);
5507 memset(&efnd, 0, sizeof(efnd));
5508 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
5509 if (efnd.total == 0)
5510 skip("%s is not installed\n", lf.lfFaceName);
5512 for (i = 0; i < efnd.total; i++)
5514 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
5515 FaceName = (char *)efnd.elf[i].elfFullName;
5516 StyleName = (char *)efnd.elf[i].elfStyle;
5518 get_vertical = ( FamilyName[0] == '@' );
5519 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
5521 lstrcpyA(lf.lfFaceName, FaceName);
5522 hfont = CreateFontIndirectA(&lf);
5523 ok(hfont != 0, "CreateFontIndirectA failed\n");
5525 of = SelectObject(hdc, hfont);
5526 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
5527 ok(buf_size != GDI_ERROR, "no name table found\n");
5528 if (buf_size == GDI_ERROR) continue;
5530 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
5531 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
5533 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5534 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5535 memset(otm, 0, otm_size);
5536 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
5537 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
5538 if (ret == 0) continue;
5540 bufW[0] = 0;
5541 bufA[0] = 0;
5542 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
5543 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5544 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
5545 if (want_vertical) bufW = prepend_at(bufW);
5546 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5547 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
5548 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
5549 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
5551 bufW[0] = 0;
5552 bufA[0] = 0;
5553 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
5554 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5555 ok(ret, "FULL_NAME (face name) could not be read\n");
5556 if (want_vertical) bufW = prepend_at(bufW);
5557 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5558 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
5559 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
5560 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
5562 bufW[0] = 0;
5563 bufA[0] = 0;
5564 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
5565 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5566 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
5567 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5568 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
5569 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
5570 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
5572 bufW[0] = 0;
5573 bufA[0] = 0;
5574 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
5575 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5576 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
5577 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5578 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
5579 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
5581 SelectObject(hdc, of);
5582 DeleteObject(hfont);
5584 HeapFree(GetProcessHeap(), 0, otm);
5585 HeapFree(GetProcessHeap(), 0, bufW);
5586 HeapFree(GetProcessHeap(), 0, bufA);
5588 heap_free(efnd.elf);
5589 DeleteDC(hdc);
5592 static void test_fullname2(void)
5594 test_fullname2_helper("Arial");
5595 test_fullname2_helper("DejaVu Sans");
5596 test_fullname2_helper("Lucida Sans");
5597 test_fullname2_helper("Tahoma");
5598 test_fullname2_helper("Webdings");
5599 test_fullname2_helper("Wingdings");
5600 test_fullname2_helper("SimSun");
5601 test_fullname2_helper("NSimSun");
5602 test_fullname2_helper("MingLiu");
5603 test_fullname2_helper("PMingLiu");
5604 test_fullname2_helper("WenQuanYi Micro Hei");
5605 test_fullname2_helper("MS UI Gothic");
5606 test_fullname2_helper("Ume UI Gothic");
5607 test_fullname2_helper("MS Gothic");
5608 test_fullname2_helper("Ume Gothic");
5609 test_fullname2_helper("MS PGothic");
5610 test_fullname2_helper("Ume P Gothic");
5611 test_fullname2_helper("Gulim");
5612 test_fullname2_helper("Batang");
5613 test_fullname2_helper("UnBatang");
5614 test_fullname2_helper("UnDotum");
5615 test_fullname2_helper("@SimSun");
5616 test_fullname2_helper("@NSimSun");
5617 test_fullname2_helper("@MingLiu");
5618 test_fullname2_helper("@PMingLiu");
5619 test_fullname2_helper("@WenQuanYi Micro Hei");
5620 test_fullname2_helper("@MS UI Gothic");
5621 test_fullname2_helper("@Ume UI Gothic");
5622 test_fullname2_helper("@MS Gothic");
5623 test_fullname2_helper("@Ume Gothic");
5624 test_fullname2_helper("@MS PGothic");
5625 test_fullname2_helper("@Ume P Gothic");
5626 test_fullname2_helper("@Gulim");
5627 test_fullname2_helper("@Batang");
5628 test_fullname2_helper("@UnBatang");
5629 test_fullname2_helper("@UnDotum");
5633 static void test_GetGlyphOutline_empty_contour(void)
5635 HDC hdc;
5636 LOGFONTA lf;
5637 HFONT hfont, hfont_prev;
5638 TTPOLYGONHEADER *header;
5639 GLYPHMETRICS gm;
5640 char buf[1024];
5641 DWORD ret;
5643 memset(&lf, 0, sizeof(lf));
5644 lf.lfHeight = 72;
5645 lstrcpyA(lf.lfFaceName, "wine_test");
5647 hfont = CreateFontIndirectA(&lf);
5648 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5650 hdc = GetDC(NULL);
5652 hfont_prev = SelectObject(hdc, hfont);
5653 ok(hfont_prev != NULL, "SelectObject failed\n");
5655 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5656 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5658 header = (TTPOLYGONHEADER*)buf;
5659 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5660 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5661 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5662 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5663 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5664 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5665 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5666 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5668 SelectObject(hdc, hfont_prev);
5669 DeleteObject(hfont);
5670 ReleaseDC(NULL, hdc);
5673 static void test_GetGlyphOutline_metric_clipping(void)
5675 HDC hdc;
5676 LOGFONTA lf;
5677 HFONT hfont, hfont_prev;
5678 GLYPHMETRICS gm;
5679 TEXTMETRICA tm;
5680 TEXTMETRICW tmW;
5681 DWORD ret;
5683 memset(&lf, 0, sizeof(lf));
5684 lf.lfHeight = 72;
5685 lstrcpyA(lf.lfFaceName, "wine_test");
5687 SetLastError(0xdeadbeef);
5688 hfont = CreateFontIndirectA(&lf);
5689 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5691 hdc = GetDC(NULL);
5693 hfont_prev = SelectObject(hdc, hfont);
5694 ok(hfont_prev != NULL, "SelectObject failed\n");
5696 SetLastError(0xdeadbeef);
5697 ret = GetTextMetricsA(hdc, &tm);
5698 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5700 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5701 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5702 "Glyph top(%d) exceeds ascent(%d)\n",
5703 gm.gmptGlyphOrigin.y, tm.tmAscent);
5704 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5705 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5706 "Glyph bottom(%d) exceeds descent(%d)\n",
5707 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5709 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5710 GetTextMetricsW(hdc, &tmW);
5711 todo_wine
5712 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5714 SelectObject(hdc, hfont_prev);
5715 DeleteObject(hfont);
5716 ReleaseDC(NULL, hdc);
5719 static void test_fstype_fixup(void)
5721 HDC hdc;
5722 LOGFONTA lf;
5723 HFONT hfont, hfont_prev;
5724 DWORD ret;
5725 OUTLINETEXTMETRICA *otm;
5726 DWORD otm_size;
5728 memset(&lf, 0, sizeof(lf));
5729 lf.lfHeight = 72;
5730 lstrcpyA(lf.lfFaceName, "wine_test");
5732 SetLastError(0xdeadbeef);
5733 hfont = CreateFontIndirectA(&lf);
5734 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5736 hdc = GetDC(NULL);
5738 hfont_prev = SelectObject(hdc, hfont);
5739 ok(hfont_prev != NULL, "SelectObject failed\n");
5741 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5742 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5743 otm->otmSize = sizeof(*otm);
5744 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
5745 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
5747 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5748 valid bits are 1, 2, 3, 8, 9. */
5749 ok((otm->otmfsType & ~0x30e) == 0, "fsType %#x\n", otm->otmfsType);
5751 HeapFree(GetProcessHeap(), 0, otm);
5753 SelectObject(hdc, hfont_prev);
5754 DeleteObject(hfont);
5755 ReleaseDC(NULL, hdc);
5758 static void test_CreateScalableFontResource(void)
5760 char ttf_name[MAX_PATH];
5761 char tmp_path[MAX_PATH];
5762 char fot_name[MAX_PATH];
5763 char *file_part;
5764 DWORD ret;
5765 int i;
5767 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5769 win_skip("AddFontResourceExA is not available on this platform\n");
5770 return;
5773 if (!write_ttf_file("wine_test.ttf", ttf_name))
5775 skip("Failed to create ttf file for testing\n");
5776 return;
5779 trace("created %s\n", ttf_name);
5781 ret = is_truetype_font_installed("wine_test");
5782 ok(!ret, "font wine_test should not be enumerated\n");
5784 ret = GetTempPathA(MAX_PATH, tmp_path);
5785 ok(ret, "GetTempPath() error %d\n", GetLastError());
5786 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5787 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5789 ret = GetFileAttributesA(fot_name);
5790 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5792 SetLastError(0xdeadbeef);
5793 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5794 ok(!ret, "CreateScalableFontResource() should fail\n");
5795 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5797 SetLastError(0xdeadbeef);
5798 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5799 ok(!ret, "CreateScalableFontResource() should fail\n");
5800 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5802 file_part = strrchr(ttf_name, '\\');
5803 SetLastError(0xdeadbeef);
5804 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5805 ok(!ret, "CreateScalableFontResource() should fail\n");
5806 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5808 SetLastError(0xdeadbeef);
5809 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5810 ok(!ret, "CreateScalableFontResource() should fail\n");
5811 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5813 SetLastError(0xdeadbeef);
5814 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5815 ok(!ret, "CreateScalableFontResource() should fail\n");
5816 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5818 ret = DeleteFileA(fot_name);
5819 ok(ret, "DeleteFile() error %d\n", GetLastError());
5821 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5822 ok(!ret, "RemoveFontResourceEx() should fail\n");
5824 /* test public font resource */
5825 SetLastError(0xdeadbeef);
5826 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5827 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5829 ret = is_truetype_font_installed("wine_test");
5830 ok(!ret, "font wine_test should not be enumerated\n");
5832 SetLastError(0xdeadbeef);
5833 ret = pAddFontResourceExA(fot_name, 0, 0);
5834 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5836 ret = is_truetype_font_installed("wine_test");
5837 ok(ret, "font wine_test should be enumerated\n");
5839 test_GetGlyphOutline_empty_contour();
5840 test_GetGlyphOutline_metric_clipping();
5841 test_fstype_fixup();
5843 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5844 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5846 SetLastError(0xdeadbeef);
5847 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5848 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5850 ret = is_truetype_font_installed("wine_test");
5851 ok(!ret, "font wine_test should not be enumerated\n");
5853 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5854 ok(!ret, "RemoveFontResourceEx() should fail\n");
5856 /* test refcounting */
5857 for (i = 0; i < 5; i++)
5859 SetLastError(0xdeadbeef);
5860 ret = pAddFontResourceExA(fot_name, 0, 0);
5861 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5863 for (i = 0; i < 5; i++)
5865 SetLastError(0xdeadbeef);
5866 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5867 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5869 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5870 ok(!ret, "RemoveFontResourceEx() should fail\n");
5872 DeleteFileA(fot_name);
5874 /* test hidden font resource */
5875 SetLastError(0xdeadbeef);
5876 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5877 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5879 ret = is_truetype_font_installed("wine_test");
5880 ok(!ret, "font wine_test should not be enumerated\n");
5882 SetLastError(0xdeadbeef);
5883 ret = pAddFontResourceExA(fot_name, 0, 0);
5884 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5886 ret = is_truetype_font_installed("wine_test");
5887 todo_wine
5888 ok(!ret, "font wine_test should not be enumerated\n");
5890 /* XP allows removing a private font added with 0 flags */
5891 SetLastError(0xdeadbeef);
5892 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5893 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5895 ret = is_truetype_font_installed("wine_test");
5896 ok(!ret, "font wine_test should not be enumerated\n");
5898 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5899 ok(!ret, "RemoveFontResourceEx() should fail\n");
5901 DeleteFileA(fot_name);
5902 DeleteFileA(ttf_name);
5905 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5907 LOGFONTA lf;
5908 HFONT hfont, hfont_prev;
5909 HDC hdc;
5910 char facename[100];
5911 DWORD ret;
5912 static const WCHAR str[] = { 0x2025 };
5914 *installed = is_truetype_font_installed(name);
5916 lf.lfHeight = -18;
5917 lf.lfWidth = 0;
5918 lf.lfEscapement = 0;
5919 lf.lfOrientation = 0;
5920 lf.lfWeight = FW_DONTCARE;
5921 lf.lfItalic = 0;
5922 lf.lfUnderline = 0;
5923 lf.lfStrikeOut = 0;
5924 lf.lfCharSet = DEFAULT_CHARSET;
5925 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5926 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5927 lf.lfQuality = DEFAULT_QUALITY;
5928 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5929 strcpy(lf.lfFaceName, name);
5931 hfont = CreateFontIndirectA(&lf);
5932 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5934 hdc = GetDC(NULL);
5936 hfont_prev = SelectObject(hdc, hfont);
5937 ok(hfont_prev != NULL, "SelectObject failed\n");
5939 ret = GetTextFaceA(hdc, sizeof facename, facename);
5940 ok(ret, "GetTextFaceA failed\n");
5941 *selected = !strcmp(facename, name);
5943 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5944 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5945 if (!*selected)
5946 memset(gm, 0, sizeof *gm);
5948 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5949 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5951 SelectObject(hdc, hfont_prev);
5952 DeleteObject(hfont);
5953 ReleaseDC(NULL, hdc);
5956 static void check_vertical_metrics(const char *face)
5958 LOGFONTA lf;
5959 HFONT hfont, hfont_prev;
5960 HDC hdc;
5961 DWORD ret;
5962 GLYPHMETRICS rgm, vgm;
5963 const UINT code = 0x5EAD, height = 1000;
5964 WORD idx;
5965 ABC abc, vabc;
5966 OUTLINETEXTMETRICA otm;
5967 USHORT numOfLongVerMetrics;
5969 hdc = GetDC(NULL);
5971 memset(&lf, 0, sizeof(lf));
5972 strcpy(lf.lfFaceName, face);
5973 lf.lfHeight = -height;
5974 lf.lfCharSet = DEFAULT_CHARSET;
5975 lf.lfEscapement = lf.lfOrientation = 900;
5976 hfont = CreateFontIndirectA(&lf);
5977 hfont_prev = SelectObject(hdc, hfont);
5978 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5979 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5980 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5981 ok(ret, "GetCharABCWidthsW failed\n");
5982 DeleteObject(SelectObject(hdc, hfont_prev));
5984 memset(&lf, 0, sizeof(lf));
5985 strcpy(lf.lfFaceName, "@");
5986 strcat(lf.lfFaceName, face);
5987 lf.lfHeight = -height;
5988 lf.lfCharSet = DEFAULT_CHARSET;
5989 hfont = CreateFontIndirectA(&lf);
5990 hfont_prev = SelectObject(hdc, hfont);
5991 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5992 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5993 ret = GetCharABCWidthsW(hdc, code, code, &vabc);
5994 ok(ret, "GetCharABCWidthsW failed\n");
5995 ok(vabc.abcA == vgm.gmptGlyphOrigin.x, "expected %d, got %d\n",
5996 vabc.abcA, vgm.gmptGlyphOrigin.x);
5997 ok(vabc.abcB == vgm.gmBlackBoxX, "expected %d, got %d\n",
5998 vabc.abcB, vgm.gmBlackBoxX);
5999 ok(vabc.abcA + vabc.abcB + vabc.abcC == vgm.gmCellIncX,
6000 "expected %d, got %d\n",
6001 vabc.abcA + vabc.abcB + vabc.abcC, vgm.gmCellIncX);
6003 memset(&otm, 0, sizeof(otm));
6004 otm.otmSize = sizeof(otm);
6005 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
6006 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
6008 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
6009 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
6010 int offset;
6011 SHORT topSideBearing;
6013 if (!pGetGlyphIndicesW) {
6014 win_skip("GetGlyphIndices is not available on this platform\n");
6016 else {
6017 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
6018 ok(ret != 0, "GetGlyphIndicesW failed\n");
6019 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
6020 if (numOfLongVerMetrics > idx)
6021 offset = idx * 2 + 1;
6022 else
6023 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
6024 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
6025 &topSideBearing, sizeof(SHORT));
6026 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
6027 topSideBearing = GET_BE_WORD(topSideBearing);
6028 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
6029 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
6030 "expected %d, got %d\n",
6031 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
6034 else
6036 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
6037 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
6038 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
6041 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
6042 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
6043 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6044 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
6046 DeleteObject(SelectObject(hdc, hfont_prev));
6047 ReleaseDC(NULL, hdc);
6050 static void test_vertical_font(void)
6052 char ttf_name[MAX_PATH];
6053 int num, i;
6054 BOOL ret, installed, selected;
6055 GLYPHMETRICS gm;
6056 WORD hgi, vgi;
6057 const char* face_list[] = {
6058 "@WineTestVertical", /* has vmtx table */
6059 "@Ume Gothic", /* doesn't have vmtx table */
6060 "@MS UI Gothic", /* has vmtx table, available on native */
6063 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
6065 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
6066 return;
6069 if (!write_ttf_file("vertical.ttf", ttf_name))
6071 skip("Failed to create ttf file for testing\n");
6072 return;
6075 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
6076 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6078 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
6079 ok(installed, "WineTestVertical is not installed\n");
6080 ok(selected, "WineTestVertical is not selected\n");
6081 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6082 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6083 gm.gmBlackBoxX, gm.gmBlackBoxY);
6085 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
6086 ok(installed, "@WineTestVertical is not installed\n");
6087 ok(selected, "@WineTestVertical is not selected\n");
6088 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6089 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6090 gm.gmBlackBoxX, gm.gmBlackBoxY);
6092 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
6094 for (i = 0; i < ARRAY_SIZE(face_list); i++) {
6095 const char* face = face_list[i];
6096 if (!is_truetype_font_installed(face)) {
6097 skip("%s is not installed\n", face);
6098 continue;
6100 trace("Testing %s...\n", face);
6101 check_vertical_metrics(&face[1]);
6104 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
6105 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
6107 DeleteFileA(ttf_name);
6110 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
6111 DWORD type, LPARAM lParam)
6113 if (lf->lfFaceName[0] == '@') {
6114 return 0;
6116 return 1;
6119 static void test_east_asian_font_selection(void)
6121 HDC hdc;
6122 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
6123 GB2312_CHARSET, CHINESEBIG5_CHARSET };
6124 size_t i;
6126 hdc = GetDC(NULL);
6128 for (i = 0; i < ARRAY_SIZE(charset); i++)
6130 LOGFONTA lf;
6131 HFONT hfont;
6132 char face_name[LF_FACESIZE];
6133 int ret;
6135 memset(&lf, 0, sizeof lf);
6136 lf.lfFaceName[0] = '\0';
6137 lf.lfCharSet = charset[i];
6139 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
6141 skip("Vertical font for charset %u is not installed\n", charset[i]);
6142 continue;
6145 hfont = CreateFontIndirectA(&lf);
6146 hfont = SelectObject(hdc, hfont);
6147 memset(face_name, 0, sizeof face_name);
6148 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6149 ok(ret && face_name[0] != '@',
6150 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
6151 DeleteObject(SelectObject(hdc, hfont));
6153 memset(&lf, 0, sizeof lf);
6154 strcpy(lf.lfFaceName, "@");
6155 lf.lfCharSet = charset[i];
6156 hfont = CreateFontIndirectA(&lf);
6157 hfont = SelectObject(hdc, hfont);
6158 memset(face_name, 0, sizeof face_name);
6159 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6160 ok(ret && face_name[0] == '@',
6161 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
6162 DeleteObject(SelectObject(hdc, hfont));
6164 ReleaseDC(NULL, hdc);
6167 static int get_font_dpi(const LOGFONTA *lf, int *height)
6169 HDC hdc = CreateCompatibleDC(0);
6170 HFONT hfont;
6171 TEXTMETRICA tm;
6172 int ret;
6174 hfont = CreateFontIndirectA(lf);
6175 ok(hfont != 0, "CreateFontIndirect failed\n");
6177 SelectObject(hdc, hfont);
6178 ret = GetTextMetricsA(hdc, &tm);
6179 ok(ret, "GetTextMetrics failed\n");
6180 ret = tm.tmDigitizedAspectX;
6181 if (height) *height = tm.tmHeight;
6183 DeleteDC(hdc);
6184 DeleteObject(hfont);
6186 return ret;
6189 static void test_stock_fonts(void)
6191 static const int font[] =
6193 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
6194 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6196 static const struct test_data
6198 int charset, weight, height, height_pixels, dpi;
6199 const char face_name[LF_FACESIZE];
6200 WORD lang_id;
6201 } td[][12] =
6203 { /* ANSI_FIXED_FONT */
6204 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
6205 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_HEBREW},
6206 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
6207 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
6208 { 0 }
6210 { /* ANSI_VAR_FONT */
6211 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
6212 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
6213 { 0 }
6215 { /* SYSTEM_FONT */
6216 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6217 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6218 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6219 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6220 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6221 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6222 { 0 }
6224 { /* DEVICE_DEFAULT_FONT */
6225 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6226 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6227 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6228 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6229 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6230 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6231 { 0 }
6233 { /* DEFAULT_GUI_FONT */
6234 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6235 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
6236 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
6237 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
6238 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
6239 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
6240 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
6241 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
6242 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
6243 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6244 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6245 { 0 }
6248 int i, j;
6250 for (i = 0; i < ARRAY_SIZE(font); i++)
6252 HFONT hfont;
6253 LOGFONTA lf;
6254 int ret, height;
6256 hfont = GetStockObject(font[i]);
6257 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
6259 ret = GetObjectA(hfont, sizeof(lf), &lf);
6260 if (ret != sizeof(lf))
6262 /* NT4 */
6263 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
6264 continue;
6267 for (j = 0; td[i][j].face_name[0] != 0; j++)
6269 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) ||
6270 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) ||
6271 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name)))
6273 continue;
6276 ret = get_font_dpi(&lf, &height);
6277 if (ret != td[i][j].dpi)
6279 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6280 i, j, lf.lfFaceName, ret, td[i][j].dpi);
6281 continue;
6284 /* FIXME: Remove once Wine is fixed */
6285 todo_wine_if (td[i][j].dpi != 96 &&
6286 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6287 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
6288 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6289 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
6290 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6292 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
6293 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
6294 if (td[i][j].face_name[0] == '?')
6296 /* Wine doesn't have this font, skip this case for now.
6297 Actually, the face name is localized on Windows and varies
6298 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6299 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
6301 else
6303 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);
6305 break;
6310 static void test_max_height(void)
6312 HDC hdc;
6313 LOGFONTA lf;
6314 HFONT hfont, hfont_old;
6315 TEXTMETRICA tm1, tm;
6316 BOOL r;
6317 LONG invalid_height[] = { -65536, -123456, 123456 };
6318 size_t i;
6320 memset(&tm1, 0, sizeof(tm1));
6321 memset(&lf, 0, sizeof(lf));
6322 strcpy(lf.lfFaceName, "Tahoma");
6323 lf.lfHeight = -1;
6325 hdc = GetDC(NULL);
6327 /* get 1 ppem value */
6328 hfont = CreateFontIndirectA(&lf);
6329 hfont_old = SelectObject(hdc, hfont);
6330 r = GetTextMetricsA(hdc, &tm1);
6331 ok(r, "GetTextMetrics failed\n");
6332 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6333 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6334 DeleteObject(SelectObject(hdc, hfont_old));
6336 /* test the largest value */
6337 lf.lfHeight = -((1 << 16) - 1);
6338 hfont = CreateFontIndirectA(&lf);
6339 hfont_old = SelectObject(hdc, hfont);
6340 memset(&tm, 0, sizeof(tm));
6341 r = GetTextMetricsA(hdc, &tm);
6342 ok(r, "GetTextMetrics failed\n");
6343 ok(tm.tmHeight > tm1.tmHeight,
6344 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6345 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
6346 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6347 DeleteObject(SelectObject(hdc, hfont_old));
6349 /* test an invalid value */
6350 for (i = 0; i < ARRAY_SIZE(invalid_height); i++) {
6351 lf.lfHeight = invalid_height[i];
6352 hfont = CreateFontIndirectA(&lf);
6353 hfont_old = SelectObject(hdc, hfont);
6354 memset(&tm, 0, sizeof(tm));
6355 r = GetTextMetricsA(hdc, &tm);
6356 ok(r, "GetTextMetrics failed\n");
6357 ok(tm.tmHeight == tm1.tmHeight,
6358 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6359 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
6360 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6361 DeleteObject(SelectObject(hdc, hfont_old));
6364 ReleaseDC(NULL, hdc);
6365 return;
6368 static void test_vertical_order(void)
6370 struct enum_font_data efd;
6371 LOGFONTA lf;
6372 HDC hdc;
6373 int i, j;
6375 hdc = CreateCompatibleDC(0);
6376 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6378 memset(&lf, 0, sizeof(lf));
6379 lf.lfCharSet = DEFAULT_CHARSET;
6380 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6381 lf.lfHeight = 16;
6382 lf.lfWidth = 16;
6383 lf.lfQuality = DEFAULT_QUALITY;
6384 lf.lfItalic = FALSE;
6385 lf.lfWeight = FW_DONTCARE;
6386 memset( &efd, 0, sizeof(efd) );
6387 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
6388 for (i = 0; i < efd.total; i++)
6390 if (efd.lf[i].lfFaceName[0] != '@') continue;
6391 for (j = 0; j < efd.total; j++)
6393 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
6395 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
6396 break;
6400 heap_free( efd.lf );
6401 DeleteDC( hdc );
6404 static void test_GetCharWidth32(void)
6406 BOOL ret;
6407 HDC hdc;
6408 LOGFONTA lf;
6409 HFONT hfont;
6410 INT bufferA;
6411 INT bufferW;
6412 HWND hwnd;
6414 if (!pGetCharWidth32A || !pGetCharWidth32W)
6416 win_skip("GetCharWidth32A/W not available on this platform\n");
6417 return;
6420 memset(&lf, 0, sizeof(lf));
6421 strcpy(lf.lfFaceName, "System");
6422 lf.lfHeight = 20;
6424 hfont = CreateFontIndirectA(&lf);
6425 hdc = GetDC(0);
6426 hfont = SelectObject(hdc, hfont);
6428 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6429 ok(ret, "GetCharWidth32W should have succeeded\n");
6430 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
6431 ok(ret, "GetCharWidth32A should have succeeded\n");
6432 ok (bufferA == bufferW, "Widths should be the same\n");
6433 ok (bufferA > 0," Width should be greater than zero\n");
6435 hfont = SelectObject(hdc, hfont);
6436 DeleteObject(hfont);
6437 ReleaseDC(NULL, hdc);
6439 memset(&lf, 0, sizeof(lf));
6440 strcpy(lf.lfFaceName, "Tahoma");
6441 lf.lfHeight = 20;
6443 hfont = CreateFontIndirectA(&lf);
6444 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
6445 0, 0, 0, NULL);
6446 hdc = GetDC(hwnd);
6447 SetMapMode( hdc, MM_ANISOTROPIC );
6448 SelectObject(hdc, hfont);
6450 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6451 ok(ret, "GetCharWidth32W should have succeeded\n");
6452 ok (bufferW > 0," Width should be greater than zero\n");
6453 SetWindowExtEx(hdc, -1,-1,NULL);
6454 SetGraphicsMode(hdc, GM_COMPATIBLE);
6455 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6456 ok(ret, "GetCharWidth32W should have succeeded\n");
6457 ok (bufferW > 0," Width should be greater than zero\n");
6458 SetGraphicsMode(hdc, GM_ADVANCED);
6459 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6460 ok(ret, "GetCharWidth32W should have succeeded\n");
6461 ok (bufferW > 0," Width should be greater than zero\n");
6462 SetWindowExtEx(hdc, 1,1,NULL);
6463 SetGraphicsMode(hdc, GM_COMPATIBLE);
6464 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6465 ok(ret, "GetCharWidth32W should have succeeded\n");
6466 ok (bufferW > 0," Width should be greater than zero\n");
6467 SetGraphicsMode(hdc, GM_ADVANCED);
6468 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6469 ok(ret, "GetCharWidth32W should have succeeded\n");
6470 ok (bufferW > 0," Width should be greater than zero\n");
6472 ReleaseDC(hwnd, hdc);
6473 DestroyWindow(hwnd);
6475 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
6476 0, 0, 0, NULL);
6477 hdc = GetDC(hwnd);
6478 SetMapMode( hdc, MM_ANISOTROPIC );
6479 SelectObject(hdc, hfont);
6481 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6482 ok(ret, "GetCharWidth32W should have succeeded\n");
6483 ok (bufferW > 0," Width should be greater than zero\n");
6484 SetWindowExtEx(hdc, -1,-1,NULL);
6485 SetGraphicsMode(hdc, GM_COMPATIBLE);
6486 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6487 ok(ret, "GetCharWidth32W should have succeeded\n");
6488 ok (bufferW > 0," Width should be greater than zero\n");
6489 SetGraphicsMode(hdc, GM_ADVANCED);
6490 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6491 ok(ret, "GetCharWidth32W should have succeeded\n");
6492 ok (bufferW > 0," Width should be greater than zero\n");
6493 SetWindowExtEx(hdc, 1,1,NULL);
6494 SetGraphicsMode(hdc, GM_COMPATIBLE);
6495 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6496 ok(ret, "GetCharWidth32W should have succeeded\n");
6497 ok (bufferW > 0," Width should be greater than zero\n");
6498 SetGraphicsMode(hdc, GM_ADVANCED);
6499 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6500 ok(ret, "GetCharWidth32W should have succeeded\n");
6501 ok (bufferW > 0," Width should be greater than zero\n");
6503 ReleaseDC(hwnd, hdc);
6504 DestroyWindow(hwnd);
6505 DeleteObject(hfont);
6508 static void test_fake_bold_font(void)
6510 static const MAT2 x2_mat = { {0,2}, {0,0}, {0,0}, {0,2} };
6511 HDC hdc;
6512 LOGFONTA lf;
6513 BOOL ret;
6514 struct glyph_data {
6515 TEXTMETRICA tm;
6516 ABC abc;
6517 INT w;
6518 GLYPHMETRICS gm;
6519 } data[4];
6520 int i;
6521 DWORD r;
6523 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
6524 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6525 return;
6528 /* Test outline font */
6529 memset(&lf, 0, sizeof(lf));
6530 strcpy(lf.lfFaceName, "Wingdings");
6531 lf.lfCharSet = SYMBOL_CHARSET;
6533 hdc = GetDC(NULL);
6535 for (i = 0; i <= 1; i++)
6537 HFONT hfont, hfont_old;
6539 lf.lfWeight = i ? FW_BOLD : FW_NORMAL;
6540 hfont = CreateFontIndirectA(&lf);
6541 hfont_old = SelectObject(hdc, hfont);
6543 ret = GetTextMetricsA(hdc, &data[i].tm);
6544 ok(ret, "got %d\n", ret);
6545 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &data[i].abc);
6546 ok(ret, "got %d\n", ret);
6547 data[i].w = data[i].abc.abcA + data[i].abc.abcB + data[i].abc.abcC;
6548 r = GetGlyphOutlineA(hdc, 0x76, GGO_METRICS, &data[i].gm, 0, NULL, &x2_mat);
6549 ok(r != GDI_ERROR, "got %d\n", ret);
6551 SelectObject(hdc, hfont_old);
6552 DeleteObject(hfont);
6554 ReleaseDC(NULL, hdc);
6556 /* compare results (outline) */
6557 ok(data[0].tm.tmHeight == data[1].tm.tmHeight,
6558 "expected %d, got %d\n", data[0].tm.tmHeight, data[1].tm.tmHeight);
6559 ok(data[0].tm.tmAscent == data[1].tm.tmAscent,
6560 "expected %d, got %d\n", data[0].tm.tmAscent, data[1].tm.tmAscent);
6561 ok(data[0].tm.tmDescent == data[1].tm.tmDescent,
6562 "expected %d, got %d\n", data[0].tm.tmDescent, data[1].tm.tmDescent);
6563 ok(data[0].tm.tmAveCharWidth + 1 == data[1].tm.tmAveCharWidth,
6564 "expected %d, got %d\n", data[0].tm.tmAveCharWidth + 1, data[1].tm.tmAveCharWidth);
6565 ok(data[0].tm.tmMaxCharWidth + 1 == data[1].tm.tmMaxCharWidth,
6566 "expected %d, got %d\n", data[0].tm.tmMaxCharWidth + 1, data[1].tm.tmMaxCharWidth);
6567 ok(data[0].tm.tmOverhang == data[1].tm.tmOverhang,
6568 "expected %d, got %d\n", data[0].tm.tmOverhang, data[1].tm.tmOverhang);
6569 ok(data[0].w + 1 == data[1].w,
6570 "expected %d, got %d\n", data[0].w + 1, data[1].w);
6572 ok(data[0].gm.gmCellIncX + 1 == data[1].gm.gmCellIncX,
6573 "expected %d, got %d\n", data[0].gm.gmCellIncX + 1, data[1].gm.gmCellIncX);
6574 ok(data[0].gm.gmCellIncY == data[1].gm.gmCellIncY,
6575 "expected %d, got %d\n", data[0].gm.gmCellIncY, data[1].gm.gmCellIncY);
6577 /* Test bitmap font */
6578 memset(&data, 0xaa, sizeof(data));
6579 memset(&lf, 0, sizeof(lf));
6580 strcpy(lf.lfFaceName, "Courier");
6581 lf.lfCharSet = ANSI_CHARSET;
6583 hdc = GetDC(NULL);
6585 for (i = 0; i < 4; i++)
6587 HFONT hfont, hfont_old;
6589 lf.lfWeight = (i % 2) ? FW_BOLD : FW_NORMAL;
6590 lf.lfHeight = (i > 1) ? data[0].tm.tmHeight * x2_mat.eM11.value : 0;
6591 hfont = CreateFontIndirectA(&lf);
6592 hfont_old = SelectObject(hdc, hfont);
6594 ret = GetTextMetricsA(hdc, &data[i].tm);
6595 ok(ret, "got %d\n", ret);
6596 ret = pGetCharWidth32A(hdc, 0x76, 0x76, &data[i].w);
6597 ok(ret, "got %d\n", ret);
6599 SelectObject(hdc, hfont_old);
6600 DeleteObject(hfont);
6602 ReleaseDC(NULL, hdc);
6604 /* compare results (bitmap) */
6605 for (i = 0; i < 4; i+=2)
6607 int diff = (i > 1) ? x2_mat.eM11.value : 1;
6608 if (data[i].tm.tmPitchAndFamily & TMPF_TRUETYPE)
6610 skip("TrueType font is selected (expected a bitmap one)\n");
6611 continue;
6613 ok(data[i].tm.tmHeight == data[i+1].tm.tmHeight,
6614 "expected %d, got %d\n", data[i].tm.tmHeight, data[i+1].tm.tmHeight);
6615 ok(data[i].tm.tmAscent == data[i+1].tm.tmAscent,
6616 "expected %d, got %d\n", data[i].tm.tmAscent, data[i+1].tm.tmAscent);
6617 ok(data[i].tm.tmDescent == data[i+1].tm.tmDescent,
6618 "expected %d, got %d\n", data[i].tm.tmDescent, data[i+1].tm.tmDescent);
6619 ok(data[i+1].tm.tmAveCharWidth - data[i].tm.tmAveCharWidth == diff,
6620 "expected %d, got %d\n", diff, data[i+1].tm.tmAveCharWidth - data[i].tm.tmAveCharWidth);
6621 ok(data[i+1].tm.tmMaxCharWidth - data[i].tm.tmMaxCharWidth == diff,
6622 "expected %d, got %d\n", diff, data[i+1].tm.tmMaxCharWidth - data[i].tm.tmMaxCharWidth);
6623 ok(data[i].tm.tmOverhang == 0,
6624 "expected 0, got %d\n", data[i].tm.tmOverhang);
6625 ok(data[i+1].tm.tmOverhang == 1,
6626 "expected 1, got %d\n", data[i+1].tm.tmOverhang);
6627 ok(data[i].w + 1 == data[i+1].w,
6628 "expected %d, got %d\n", data[i].w + 1, data[i+1].w);
6632 static void test_bitmap_font_glyph_index(void)
6634 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
6635 const struct {
6636 LPCSTR face;
6637 BYTE charset;
6638 } bitmap_font_list[] = {
6639 { "Courier", ANSI_CHARSET },
6640 { "Small Fonts", ANSI_CHARSET },
6641 { "Fixedsys", DEFAULT_CHARSET },
6642 { "System", DEFAULT_CHARSET }
6644 HDC hdc;
6645 LOGFONTA lf;
6646 HFONT hFont;
6647 CHAR facename[LF_FACESIZE];
6648 BITMAPINFO bmi;
6649 HBITMAP hBmp[2];
6650 void *pixels[2];
6651 int i, j;
6652 DWORD ret;
6653 BITMAP bmp;
6654 TEXTMETRICA tm;
6655 CHARSETINFO ci;
6656 BYTE chr = '\xA9';
6658 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
6659 win_skip("GetGlyphIndices is unavailable\n");
6660 return;
6663 hdc = CreateCompatibleDC(0);
6664 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6666 memset(&bmi, 0, sizeof(bmi));
6667 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
6668 bmi.bmiHeader.biBitCount = 32;
6669 bmi.bmiHeader.biPlanes = 1;
6670 bmi.bmiHeader.biWidth = 128;
6671 bmi.bmiHeader.biHeight = 32;
6672 bmi.bmiHeader.biCompression = BI_RGB;
6674 for (i = 0; i < ARRAY_SIZE(bitmap_font_list); i++) {
6675 memset(&lf, 0, sizeof(lf));
6676 lf.lfCharSet = bitmap_font_list[i].charset;
6677 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
6678 hFont = CreateFontIndirectA(&lf);
6679 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
6680 hFont = SelectObject(hdc, hFont);
6681 ret = GetTextMetricsA(hdc, &tm);
6682 ok(ret, "GetTextMetric failed\n");
6683 ret = GetTextFaceA(hdc, sizeof(facename), facename);
6684 ok(ret, "GetTextFace failed\n");
6685 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
6686 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
6687 continue;
6689 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
6690 skip("expected %s, got %s\n", lf.lfFaceName, facename);
6691 continue;
6694 for (j = 0; j < 2; j++) {
6695 HBITMAP hBmpPrev;
6696 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
6697 ok(hBmp[j] != NULL, "Can't create DIB\n");
6698 hBmpPrev = SelectObject(hdc, hBmp[j]);
6699 switch (j) {
6700 case 0:
6701 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
6702 break;
6703 case 1:
6705 int len = lstrlenW(text);
6706 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
6707 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
6708 ok(ret, "GetGlyphIndices failed\n");
6709 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
6710 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
6711 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
6712 HeapFree(GetProcessHeap(), 0, indices);
6713 break;
6716 ok(ret, "ExtTextOutW failed\n");
6717 SelectObject(hdc, hBmpPrev);
6720 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
6721 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6722 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6724 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
6725 if (!ret) {
6726 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6727 goto next;
6729 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
6730 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
6731 goto next;
6734 for (j = 0; j < 2; j++) {
6735 HBITMAP hBmpPrev;
6736 WORD code;
6737 hBmpPrev = SelectObject(hdc, hBmp[j]);
6738 switch (j) {
6739 case 0:
6740 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6741 break;
6742 case 1:
6743 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6744 ok(ret, "GetGlyphIndices failed\n");
6745 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6746 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6747 break;
6749 ok(ret, "ExtTextOutA failed\n");
6750 SelectObject(hdc, hBmpPrev);
6753 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6754 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6755 next:
6756 for (j = 0; j < 2; j++)
6757 DeleteObject(hBmp[j]);
6758 hFont = SelectObject(hdc, hFont);
6759 DeleteObject(hFont);
6762 DeleteDC(hdc);
6765 static void test_GetCharWidthI(void)
6767 static const char *teststr = "wine ";
6768 HFONT hfont, prev_hfont;
6769 WORD glyphs[5];
6770 INT widths[5];
6771 LOGFONTA lf;
6772 ABC abc[5];
6773 int len, i;
6774 DWORD nb;
6775 BOOL ret;
6776 HDC hdc;
6778 memset(&lf, 0, sizeof(lf));
6779 strcpy(lf.lfFaceName, "Tahoma");
6780 lf.lfHeight = -20;
6782 hdc = GetDC(0);
6784 hfont = CreateFontIndirectA(&lf);
6785 prev_hfont = SelectObject(hdc, hfont);
6787 len = strlen(teststr);
6788 nb = GetGlyphIndicesA(hdc, teststr, len, glyphs, 0);
6789 ok(nb == len, "\n");
6791 memset(abc, 0xcc, sizeof(abc));
6792 ret = GetCharABCWidthsI(hdc, 0, len, glyphs, abc);
6793 ok(ret, "GetCharABCWidthsI failed\n");
6795 memset(widths, 0xcc, sizeof(widths));
6796 ret = GetCharWidthI(hdc, 0, len, glyphs, widths);
6797 ok(ret, "GetCharWidthI failed\n");
6799 for (i = 0; i < len; i++)
6800 ok(widths[i] == abc[i].abcA + abc[i].abcB + abc[i].abcC, "%u, glyph %u, got width %d\n",
6801 i, glyphs[i], widths[i]);
6803 DeleteObject(SelectObject(hdc, prev_hfont));
6804 ReleaseDC(0, hdc);
6807 static INT CALLBACK long_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lparam)
6809 BOOL *found_font = (BOOL *)lparam;
6810 *found_font = TRUE;
6811 return 1;
6814 static void test_long_names(void)
6816 char ttf_name[MAX_PATH];
6817 LOGFONTA font = {0};
6818 HFONT handle_font;
6819 BOOL found_font;
6820 int ret;
6821 HDC dc;
6823 if (!write_ttf_file("wine_longname.ttf", ttf_name))
6825 skip("Failed to create ttf file for testing\n");
6826 return;
6829 dc = GetDC(NULL);
6831 ret = AddFontResourceExA(ttf_name, FR_PRIVATE, 0);
6832 ok(ret, "AddFontResourceEx() failed\n");
6834 strcpy(font.lfFaceName, "wine_3_this_is_a_very_long_name");
6835 found_font = FALSE;
6836 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
6837 ok(found_font == TRUE, "EnumFontFamiliesExA didn't find font.\n");
6839 strcpy(font.lfFaceName, "wine_2_this_is_a_very_long_name");
6840 found_font = FALSE;
6841 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
6842 ok(found_font == TRUE, "EnumFontFamiliesExA didn't find font.\n");
6844 strcpy(font.lfFaceName, "wine_1_this_is_a_very_long_name");
6845 found_font = FALSE;
6846 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
6847 ok(found_font == FALSE, "EnumFontFamiliesExA must not find font.\n");
6849 handle_font = CreateFontIndirectA(&font);
6850 ok(handle_font != NULL, "CreateFontIndirectA failed\n");
6851 DeleteObject(handle_font);
6853 ret = RemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
6854 ok(ret, "RemoveFontResourceEx() failed\n");
6856 DeleteFileA(ttf_name);
6857 ReleaseDC(NULL, dc);
6860 START_TEST(font)
6862 init();
6864 test_stock_fonts();
6865 test_logfont();
6866 test_bitmap_font();
6867 test_outline_font();
6868 test_bitmap_font_metrics();
6869 test_GdiGetCharDimensions();
6870 test_GetCharABCWidths();
6871 test_text_extents();
6872 test_GetGlyphIndices();
6873 test_GetKerningPairs();
6874 test_GetOutlineTextMetrics();
6875 test_SetTextJustification();
6876 test_font_charset();
6877 test_GdiGetCodePage();
6878 test_GetFontUnicodeRanges();
6879 test_nonexistent_font();
6880 test_orientation();
6881 test_height_selection();
6882 test_AddFontMemResource();
6883 test_EnumFonts();
6884 test_EnumFonts_subst();
6886 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6887 * I'd like to avoid them in this test.
6889 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6890 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6891 if (is_truetype_font_installed("Arial Black") &&
6892 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6894 test_EnumFontFamilies("", ANSI_CHARSET);
6895 test_EnumFontFamilies("", SYMBOL_CHARSET);
6896 test_EnumFontFamilies("", DEFAULT_CHARSET);
6898 else
6899 skip("Arial Black or Symbol/Wingdings is not installed\n");
6900 test_EnumFontFamiliesEx_default_charset();
6901 test_GetTextMetrics();
6902 test_RealizationInfo();
6903 test_GetTextFace();
6904 test_GetGlyphOutline();
6905 test_GetTextMetrics2("Tahoma", -11);
6906 test_GetTextMetrics2("Tahoma", -55);
6907 test_GetTextMetrics2("Tahoma", -110);
6908 test_GetTextMetrics2("Arial", -11);
6909 test_GetTextMetrics2("Arial", -55);
6910 test_GetTextMetrics2("Arial", -110);
6911 test_GetCharacterPlacement();
6912 test_CreateFontIndirect();
6913 test_CreateFontIndirectEx();
6914 test_oemcharset();
6915 test_fullname();
6916 test_fullname2();
6917 test_east_asian_font_selection();
6918 test_max_height();
6919 test_vertical_order();
6920 test_GetCharWidth32();
6921 test_fake_bold_font();
6922 test_bitmap_font_glyph_index();
6923 test_GetCharWidthI();
6924 test_long_names();
6926 /* These tests should be last test until RemoveFontResource
6927 * is properly implemented.
6929 test_vertical_font();
6930 test_CreateScalableFontResource();