gdi32: Use NtGdiGetDeviceCaps for GetDeviceCaps implementation.
[wine.git] / dlls / gdi32 / tests / font.c
blob7aee0a86d231399186ff0f81eac91b90bbbbef83
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 <stdio.h>
24 #include <assert.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
32 #include "wine/heap.h"
33 #include "wine/test.h"
35 static inline BOOL match_off_by_n(int a, int b, unsigned int n)
37 return abs(a - b) <= n;
39 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
40 #define near_match(a, b) match_off_by_n((a), (b), 6)
41 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
43 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
44 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
45 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
46 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
47 static BOOL (WINAPI *pGetCharWidthInfo)(HDC hdc, void *);
48 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
49 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
50 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
51 LPINT nfit, LPINT dxs, LPSIZE size );
52 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
53 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
54 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
55 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
56 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
57 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
58 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
59 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, SIZE_T, SIZE_T *);
60 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, UINT64, void *, DWORD);
62 static HMODULE hgdi32 = 0;
63 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
64 static WORD system_lang_id;
66 #ifdef WORDS_BIGENDIAN
67 #define GET_BE_WORD(x) (x)
68 #define GET_BE_DWORD(x) (x)
69 #else
70 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
71 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
72 #endif
74 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
75 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
76 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
77 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
78 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
79 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
81 static void init(void)
83 hgdi32 = GetModuleHandleA("gdi32.dll");
85 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
86 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
87 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
88 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
89 pGetCharWidthInfo = (void *)GetProcAddress(hgdi32, "GetCharWidthInfo");
90 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
91 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
92 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
93 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
94 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
95 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
96 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
97 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
98 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
99 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
100 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
101 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
103 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
106 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
108 if (type != TRUETYPE_FONTTYPE) return 1;
110 return 0;
113 static BOOL is_truetype_font_installed(const char *name)
115 HDC hdc = GetDC(0);
116 BOOL ret = FALSE;
118 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
119 ret = TRUE;
121 ReleaseDC(0, hdc);
122 return ret;
125 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
127 return 0;
130 static BOOL is_font_installed(const char *name)
132 HDC hdc = GetDC(0);
133 BOOL ret = FALSE;
135 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
136 ret = TRUE;
138 ReleaseDC(0, hdc);
139 return ret;
142 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
144 HRSRC rsrc;
145 void *rsrc_data;
147 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
148 if (!rsrc) return NULL;
150 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
151 if (!rsrc_data) return NULL;
153 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
154 if (!*rsrc_size) return NULL;
156 return rsrc_data;
159 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
161 char tmp_path[MAX_PATH];
162 HANDLE hfile;
163 BOOL ret;
165 GetTempPathA(MAX_PATH, tmp_path);
166 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
168 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
169 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
171 ret = WriteFile(hfile, data, *size, size, NULL);
173 CloseHandle(hfile);
174 return ret;
177 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
179 void *rsrc_data;
180 DWORD rsrc_size;
182 rsrc_data = get_res_data( fontname, &rsrc_size );
183 if (!rsrc_data) return FALSE;
185 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
188 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
190 LOGFONTA getobj_lf;
191 int ret, minlen = 0;
193 if (!hfont)
194 return;
196 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
197 /* NT4 tries to be clever and only returns the minimum length */
198 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
199 minlen++;
200 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
201 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
202 ok(lf->lfHeight == getobj_lf.lfHeight ||
203 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
204 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
205 ok(lf->lfWidth == getobj_lf.lfWidth ||
206 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
207 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
208 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
209 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
210 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
211 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
212 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
213 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
214 ok(lf->lfWeight == getobj_lf.lfWeight ||
215 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
216 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
217 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
218 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
219 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
220 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
221 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
222 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
223 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
224 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
225 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
226 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
227 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
230 static HFONT create_font(const char* test, const LOGFONTA* lf)
232 HFONT hfont = CreateFontIndirectA(lf);
233 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
234 if (hfont)
235 check_font(test, lf, hfont);
236 return hfont;
239 static void test_logfont(void)
241 LOGFONTA lf;
242 HFONT hfont;
244 memset(&lf, 0, sizeof lf);
246 lf.lfCharSet = ANSI_CHARSET;
247 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
248 lf.lfWeight = FW_DONTCARE;
249 lf.lfHeight = 16;
250 lf.lfWidth = 16;
251 lf.lfQuality = DEFAULT_QUALITY;
253 lstrcpyA(lf.lfFaceName, "Arial");
254 hfont = create_font("Arial", &lf);
255 DeleteObject(hfont);
257 memset(&lf, 'A', sizeof(lf));
258 hfont = CreateFontIndirectA(&lf);
259 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
261 lf.lfFaceName[LF_FACESIZE - 1] = 0;
262 check_font("AAA...", &lf, hfont);
263 DeleteObject(hfont);
266 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
268 if (type & RASTER_FONTTYPE)
270 LOGFONTA *lf = (LOGFONTA *)lParam;
271 *lf = *elf;
272 return 0; /* stop enumeration */
275 return 1; /* continue enumeration */
278 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
280 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
281 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
282 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
283 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
284 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
285 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
286 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
287 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
288 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
289 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
290 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
291 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
292 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
293 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
294 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
295 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
296 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
297 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
298 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
299 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
302 static void test_font_metrics(const char *context,
303 HDC hdc, HFONT hfont, LONG lfHeight,
304 LONG lfWidth, const char *test_str,
305 INT test_str_len, const TEXTMETRICA *tm_orig,
306 const SIZE *size_orig, INT width_of_A_orig,
307 INT scale_x, INT scale_y)
309 LOGFONTA lf;
310 OUTLINETEXTMETRICA otm;
311 TEXTMETRICA tm;
312 SIZE size;
313 INT width_of_A, cx, cy;
314 UINT ret;
316 if (!hfont)
317 return;
319 if (context) winetest_push_context("%s", context);
320 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
322 GetObjectA(hfont, sizeof(lf), &lf);
324 if (GetOutlineTextMetricsA(hdc, 0, NULL))
326 otm.otmSize = sizeof(otm) / 2;
327 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
328 ok(ret == sizeof(otm)/2 /* XP */ ||
329 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
331 memset(&otm, 0x1, sizeof(otm));
332 otm.otmSize = sizeof(otm);
333 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
334 ok(ret == sizeof(otm) /* XP */ ||
335 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
337 memset(&tm, 0x2, sizeof(tm));
338 ret = GetTextMetricsA(hdc, &tm);
339 ok(ret, "GetTextMetricsA failed\n");
340 /* the structure size is aligned */
341 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
343 ok(0, "tm != otm\n");
344 compare_tm(&tm, &otm.otmTextMetrics);
347 tm = otm.otmTextMetrics;
348 if (0) /* these metrics are scaled too, but with rounding errors */
350 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
351 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
353 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
354 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
355 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
356 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
357 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
358 if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)
359 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
361 else
363 ret = GetTextMetricsA(hdc, &tm);
364 ok(ret, "GetTextMetricsA failed\n");
367 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
368 cy = tm.tmHeight / tm_orig->tmHeight;
369 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
370 lfHeight, scale_x, scale_y, cx, cy);
371 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
372 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
373 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
374 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
375 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
377 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
378 if (lf.lfHeight)
380 if (lf.lfWidth)
381 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
383 else
384 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
386 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
388 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
389 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
391 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
393 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);
394 if (context) winetest_pop_context();
397 /* Test how GDI scales bitmap font metrics */
398 static void test_bitmap_font(void)
400 static const char test_str[11] = "Test String";
401 HDC hdc;
402 LOGFONTA bitmap_lf;
403 HFONT hfont, old_hfont;
404 TEXTMETRICA tm_orig;
405 SIZE size_orig;
406 INT ret, i, width_orig, height_orig, scale, lfWidth;
408 hdc = CreateCompatibleDC(0);
410 /* "System" has only 1 pixel size defined, otherwise the test breaks */
411 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
412 if (ret)
414 ReleaseDC(0, hdc);
415 skip("no bitmap fonts were found, skipping the test\n");
416 return;
419 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
421 height_orig = bitmap_lf.lfHeight;
422 lfWidth = bitmap_lf.lfWidth;
424 hfont = create_font("bitmap", &bitmap_lf);
425 old_hfont = SelectObject(hdc, hfont);
426 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
427 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
428 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
429 SelectObject(hdc, old_hfont);
430 DeleteObject(hfont);
432 bitmap_lf.lfHeight = 0;
433 bitmap_lf.lfWidth = 4;
434 hfont = create_font("bitmap", &bitmap_lf);
435 old_hfont = SelectObject(hdc, hfont);
436 test_font_metrics("bitmap", hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
437 SelectObject(hdc, old_hfont);
438 DeleteObject(hfont);
440 bitmap_lf.lfHeight = height_orig;
441 bitmap_lf.lfWidth = lfWidth;
443 /* test fractional scaling */
444 for (i = 1; i <= height_orig * 6; i++)
446 INT nearest_height;
448 bitmap_lf.lfHeight = i;
449 hfont = create_font("fractional", &bitmap_lf);
450 scale = (i + height_orig - 1) / height_orig;
451 nearest_height = scale * height_orig;
452 /* Only jump to the next height if the difference <= 25% original height */
453 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
454 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
455 so we'll not test this particular height. */
456 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
457 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
458 old_hfont = SelectObject(hdc, hfont);
459 winetest_push_context("height %i", i);
460 test_font_metrics(NULL, hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
461 winetest_pop_context();
462 SelectObject(hdc, old_hfont);
463 DeleteObject(hfont);
466 /* test integer scaling 3x2 */
467 bitmap_lf.lfHeight = height_orig * 2;
468 bitmap_lf.lfWidth *= 3;
469 hfont = create_font("3x2", &bitmap_lf);
470 old_hfont = SelectObject(hdc, hfont);
471 test_font_metrics("bitmap 3x2", hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
472 SelectObject(hdc, old_hfont);
473 DeleteObject(hfont);
475 /* test integer scaling 3x3 */
476 bitmap_lf.lfHeight = height_orig * 3;
477 bitmap_lf.lfWidth = 0;
478 hfont = create_font("3x3", &bitmap_lf);
479 old_hfont = SelectObject(hdc, hfont);
480 test_font_metrics("bitmap 3x3", hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
481 SelectObject(hdc, old_hfont);
482 DeleteObject(hfont);
484 DeleteDC(hdc);
487 /* Test how GDI scales outline font metrics */
488 static void test_outline_font(void)
490 static const char test_str[11] = "Test String";
491 HDC hdc, hdc_2;
492 LOGFONTA lf;
493 HFONT hfont, old_hfont, old_hfont_2;
494 OUTLINETEXTMETRICA otm;
495 SIZE size_orig;
496 INT width_orig, height_orig, lfWidth;
497 XFORM xform;
498 GLYPHMETRICS gm;
499 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
500 POINT pt;
501 INT ret;
503 if (!is_truetype_font_installed("Arial"))
505 skip("Arial is not installed\n");
506 return;
509 hdc = CreateCompatibleDC(0);
511 memset(&lf, 0, sizeof(lf));
512 strcpy(lf.lfFaceName, "Arial");
513 lf.lfHeight = 72;
514 hfont = create_font("outline", &lf);
515 old_hfont = SelectObject(hdc, hfont);
516 otm.otmSize = sizeof(otm);
517 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
518 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
519 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
521 test_font_metrics("outline", hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
522 SelectObject(hdc, old_hfont);
523 DeleteObject(hfont);
525 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
526 lf.lfHeight = otm.otmEMSquare;
527 lf.lfHeight = -lf.lfHeight;
528 hfont = create_font("outline", &lf);
529 old_hfont = SelectObject(hdc, hfont);
530 otm.otmSize = sizeof(otm);
531 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
532 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
533 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
534 SelectObject(hdc, old_hfont);
535 DeleteObject(hfont);
537 height_orig = otm.otmTextMetrics.tmHeight;
538 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
540 /* test integer scaling 3x2 */
541 lf.lfHeight = height_orig * 2;
542 lf.lfWidth = lfWidth * 3;
543 hfont = create_font("3x2", &lf);
544 old_hfont = SelectObject(hdc, hfont);
545 test_font_metrics("outline 3x2", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
546 SelectObject(hdc, old_hfont);
547 DeleteObject(hfont);
549 /* test integer scaling 3x3 */
550 lf.lfHeight = height_orig * 3;
551 lf.lfWidth = lfWidth * 3;
552 hfont = create_font("3x3", &lf);
553 old_hfont = SelectObject(hdc, hfont);
554 test_font_metrics("outline 3x3", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
555 SelectObject(hdc, old_hfont);
556 DeleteObject(hfont);
558 /* test integer scaling 1x1 */
559 lf.lfHeight = height_orig * 1;
560 lf.lfWidth = lfWidth * 1;
561 hfont = create_font("1x1", &lf);
562 old_hfont = SelectObject(hdc, hfont);
563 test_font_metrics("outline 1x1", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
564 SelectObject(hdc, old_hfont);
565 DeleteObject(hfont);
567 /* test integer scaling 1x1 */
568 lf.lfHeight = height_orig;
569 lf.lfWidth = 0;
570 hfont = create_font("1x1", &lf);
571 old_hfont = SelectObject(hdc, hfont);
572 test_font_metrics("outline 1x0", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
574 /* with an identity matrix */
575 memset(&gm, 0, sizeof(gm));
576 SetLastError(0xdeadbeef);
577 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
578 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
579 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
580 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
581 /* with a custom matrix */
582 memset(&gm, 0, sizeof(gm));
583 SetLastError(0xdeadbeef);
584 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
585 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
586 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
587 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
589 /* Test that changing the DC transformation affects only the font
590 * selected on this DC and doesn't affect the same font selected on
591 * another DC.
593 hdc_2 = CreateCompatibleDC(0);
594 old_hfont_2 = SelectObject(hdc_2, hfont);
595 test_font_metrics("dc2.base", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
597 SetMapMode(hdc, MM_ANISOTROPIC);
599 /* font metrics on another DC should be unchanged */
600 test_font_metrics("dc2.aniso", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
602 /* test restrictions of compatibility mode GM_COMPATIBLE */
603 /* part 1: rescaling only X should not change font scaling on screen.
604 So compressing the X axis by 2 is not done, and this
605 appears as X scaling of 2 that no one requested. */
606 SetWindowExtEx(hdc, 100, 100, NULL);
607 SetViewportExtEx(hdc, 50, 100, NULL);
608 test_font_metrics("xscaling", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
609 /* font metrics on another DC should be unchanged */
610 test_font_metrics("dc2.xscaling", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
612 /* part 2: rescaling only Y should change font scaling.
613 As also X is scaled by a factor of 2, but this is not
614 requested by the DC transformation, we get a scaling factor
615 of 2 in the X coordinate. */
616 SetViewportExtEx(hdc, 100, 200, NULL);
617 test_font_metrics("yscaling", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics("dc2.yscaling", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 /* restore scaling */
622 SetMapMode(hdc, MM_TEXT);
624 /* font metrics on another DC should be unchanged */
625 test_font_metrics("dc2.text", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
627 SelectObject(hdc_2, old_hfont_2);
628 DeleteDC(hdc_2);
630 if (!SetGraphicsMode(hdc, GM_ADVANCED))
632 SelectObject(hdc, old_hfont);
633 DeleteObject(hfont);
634 DeleteDC(hdc);
635 skip("GM_ADVANCED is not supported on this platform\n");
636 return;
639 xform.eM11 = 20.0f;
640 xform.eM12 = 0.0f;
641 xform.eM21 = 0.0f;
642 xform.eM22 = 20.0f;
643 xform.eDx = 0.0f;
644 xform.eDy = 0.0f;
646 SetLastError(0xdeadbeef);
647 ret = SetWorldTransform(hdc, &xform);
648 ok(ret, "SetWorldTransform error %u\n", GetLastError());
650 test_font_metrics("xform", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
652 /* with an identity matrix */
653 memset(&gm, 0, sizeof(gm));
654 SetLastError(0xdeadbeef);
655 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
656 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
657 pt.x = width_orig; pt.y = 0;
658 LPtoDP(hdc, &pt, 1);
659 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
660 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
661 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
662 /* with a custom matrix */
663 memset(&gm, 0, sizeof(gm));
664 SetLastError(0xdeadbeef);
665 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
666 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
667 pt.x = width_orig; pt.y = 0;
668 LPtoDP(hdc, &pt, 1);
669 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
670 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
671 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
673 SetLastError(0xdeadbeef);
674 ret = SetMapMode(hdc, MM_LOMETRIC);
675 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
677 test_font_metrics("lometric", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
679 /* with an identity matrix */
680 memset(&gm, 0, sizeof(gm));
681 SetLastError(0xdeadbeef);
682 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
683 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
684 pt.x = width_orig; pt.y = 0;
685 LPtoDP(hdc, &pt, 1);
686 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
687 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
688 /* with a custom matrix */
689 memset(&gm, 0, sizeof(gm));
690 SetLastError(0xdeadbeef);
691 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
692 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
693 pt.x = width_orig; pt.y = 0;
694 LPtoDP(hdc, &pt, 1);
695 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
696 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
698 SetLastError(0xdeadbeef);
699 ret = SetMapMode(hdc, MM_TEXT);
700 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
702 test_font_metrics("text", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
704 /* with an identity matrix */
705 memset(&gm, 0, sizeof(gm));
706 SetLastError(0xdeadbeef);
707 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
708 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
709 pt.x = width_orig; pt.y = 0;
710 LPtoDP(hdc, &pt, 1);
711 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
712 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
713 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
714 /* with a custom matrix */
715 memset(&gm, 0, sizeof(gm));
716 SetLastError(0xdeadbeef);
717 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
718 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
719 pt.x = width_orig; pt.y = 0;
720 LPtoDP(hdc, &pt, 1);
721 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
722 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
723 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
725 SelectObject(hdc, old_hfont);
726 DeleteObject(hfont);
727 DeleteDC(hdc);
730 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
732 LOGFONTA *lf = (LOGFONTA *)lParam;
734 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
736 *lf = *elf;
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL is_CJK(void)
744 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
751 static const struct font_data
753 const char face_name[LF_FACESIZE];
754 int weight, height, ascent, descent, int_leading, ext_leading;
755 int ave_char_width, max_char_width, dpi;
756 BYTE first_char, last_char, def_char, break_char;
757 DWORD ansi_bitfield;
758 const WORD *skip_lang_id;
759 int scaled_height;
760 } fd[] =
762 { "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 },
763 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
764 { "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 },
765 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
766 { "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 },
767 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
768 { "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 },
769 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
770 { "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 },
771 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
773 { "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 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
775 { "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 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
777 { "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 },
778 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
779 { "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 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
781 { "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 },
782 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
784 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
785 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
786 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
787 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
788 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
789 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
790 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
791 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
792 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
793 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
794 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
795 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
796 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
797 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
798 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
799 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
801 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
802 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
803 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
804 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
805 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
806 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
807 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
808 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
809 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
810 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
811 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
812 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
814 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
815 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
816 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
817 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
818 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
819 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
820 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
821 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
822 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
823 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
824 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
825 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
826 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
827 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
828 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
829 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
830 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
833 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
834 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
835 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
836 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
837 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
838 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
839 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
840 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
841 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
842 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
844 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
845 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
846 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
848 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
849 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
850 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
852 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
853 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
854 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
856 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
857 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
859 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
860 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
861 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
862 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
863 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
864 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
865 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
866 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
867 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
868 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
869 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
870 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
871 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
872 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
873 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
874 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
875 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
876 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
877 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
878 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
879 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
881 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
882 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
883 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
884 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
885 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
886 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
887 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
888 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
889 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
890 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
891 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
892 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
894 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
895 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
896 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
898 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
900 /* FIXME: add "Terminal" */
902 static const int font_log_pixels[] = { 96, 120 };
903 HDC hdc;
904 LOGFONTA lf;
905 HFONT hfont, old_hfont;
906 TEXTMETRICA tm;
907 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
908 char face_name[LF_FACESIZE];
909 CHARSETINFO csi;
911 trace("system language id %04x\n", system_lang_id);
913 expected_cs = GetACP();
914 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
916 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
917 return;
919 expected_cs = csi.ciCharset;
920 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
922 hdc = CreateCompatibleDC(0);
923 ok(hdc != NULL, "failed to create hdc\n");
925 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
926 GetDeviceCaps(hdc, LOGPIXELSY));
928 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
929 diff = 32768;
930 font_res = 0;
931 for (i = 0; i < ARRAY_SIZE(font_log_pixels); i++)
933 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
934 if (new_diff < diff)
936 diff = new_diff;
937 font_res = font_log_pixels[i];
940 trace("best font resolution is %d\n", font_res);
942 for (i = 0; i < ARRAY_SIZE(fd); i++)
944 int bit, height;
946 memset(&lf, 0, sizeof(lf));
948 height = fd[i].height & ~FH_SCALE;
949 lf.lfHeight = height;
950 strcpy(lf.lfFaceName, fd[i].face_name);
952 for(bit = 0; bit < 32; bit++)
954 GLYPHMETRICS gm;
955 DWORD fs[2];
956 BOOL bRet;
958 fs[0] = 1L << bit;
959 fs[1] = 0;
960 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
961 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
963 lf.lfCharSet = csi.ciCharset;
964 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
965 if (fd[i].height & FH_SCALE)
966 ok(ret, "scaled font height %d should not be enumerated\n", height);
967 else
969 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
971 todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */
972 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
975 if (ret && !(fd[i].height & FH_SCALE))
976 continue;
978 hfont = create_font(lf.lfFaceName, &lf);
979 old_hfont = SelectObject(hdc, hfont);
981 SetLastError(0xdeadbeef);
982 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
983 ok(ret, "GetTextFace error %u\n", GetLastError());
985 if (strcmp(face_name, fd[i].face_name) != 0)
987 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
988 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
989 SelectObject(hdc, old_hfont);
990 DeleteObject(hfont);
991 continue;
994 memset(&gm, 0, sizeof(gm));
995 SetLastError(0xdeadbeef);
996 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
997 todo_wine
998 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
999 ret = GetLastError();
1000 ok(ret == ERROR_CAN_NOT_COMPLETE || ret == 0xdeadbeef /* Win10 */, "Unexpected error %d.\n", ret);
1002 bRet = GetTextMetricsA(hdc, &tm);
1003 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1005 SetLastError(0xdeadbeef);
1006 ret = GetTextCharset(hdc);
1007 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1008 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1009 else
1010 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1012 if(fd[i].dpi == tm.tmDigitizedAspectX)
1014 int skipme = 0;
1015 if (fd[i].skip_lang_id)
1017 int si = 0;
1018 skipme = 0;
1019 while(!skipme && fd[i].skip_lang_id[si])
1020 if (fd[i].skip_lang_id[si++] == system_lang_id)
1021 skipme = 1;
1023 if (!skipme)
1025 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1026 if (fd[i].height & FH_SCALE)
1027 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);
1028 else
1029 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);
1030 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1031 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1032 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);
1033 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);
1034 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);
1035 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1036 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1037 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1038 make default char test fail */
1039 if (tm.tmCharSet == lf.lfCharSet)
1040 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1041 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1042 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);
1044 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1045 that make the max width bigger */
1046 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1047 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);
1049 else
1050 skip("Skipping font metrics test for system langid 0x%x\n",
1051 system_lang_id);
1053 SelectObject(hdc, old_hfont);
1054 DeleteObject(hfont);
1058 DeleteDC(hdc);
1061 static void test_GdiGetCharDimensions(void)
1063 HDC hdc;
1064 TEXTMETRICW tm;
1065 LONG ret;
1066 SIZE size;
1067 LONG avgwidth, height;
1068 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1070 if (!pGdiGetCharDimensions)
1072 win_skip("GdiGetCharDimensions not available on this platform\n");
1073 return;
1076 hdc = CreateCompatibleDC(NULL);
1078 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1079 avgwidth = ((size.cx / 26) + 1) / 2;
1081 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1082 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1083 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1085 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1086 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1088 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1089 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1091 height = 0;
1092 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1093 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1094 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1096 DeleteDC(hdc);
1099 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1100 const TEXTMETRICA *lpntme,
1101 DWORD FontType, LPARAM lParam)
1103 if (FontType & TRUETYPE_FONTTYPE)
1105 HFONT hfont;
1107 hfont = CreateFontIndirectA(lpelfe);
1108 if (hfont)
1110 *(HFONT *)lParam = hfont;
1111 return 0;
1115 return 1;
1118 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, const ABC *base_abci, const ABC *base_abcw, const ABCFLOAT *base_abcf)
1120 ABC abc[1];
1121 ABCFLOAT abcf[1];
1122 BOOL ret = FALSE;
1124 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1125 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1126 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1127 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1128 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1130 ret = GetCharABCWidthsW(hdc, 'i', 'i', abc);
1131 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1132 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1133 ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1134 ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1136 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1137 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1138 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1139 ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1140 ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1143 static void test_GetCharABCWidths(void)
1145 BOOL ret;
1146 HDC hdc;
1147 LOGFONTA lf;
1148 HFONT hfont;
1149 ABC abc[1];
1150 ABC abcw[1];
1151 ABCFLOAT abcf[1];
1152 WORD glyphs[1];
1153 DWORD nb;
1154 HWND hwnd;
1155 static const struct
1157 UINT first;
1158 UINT last;
1159 } range[] =
1161 {0xff, 0xff},
1162 {0x100, 0x100},
1163 {0xff, 0x100},
1164 {0x1ff, 0xff00},
1165 {0xffff, 0xffff},
1166 {0x10000, 0x10000},
1167 {0xffff, 0x10000},
1168 {0xffffff, 0xffffff},
1169 {0x1000000, 0x1000000},
1170 {0xffffff, 0x1000000},
1171 {0xffffffff, 0xffffffff},
1172 {0x00, 0xff}
1174 static const struct
1176 UINT cs;
1177 UINT a;
1178 UINT w;
1179 BOOL r[ARRAY_SIZE(range)];
1180 } c[] =
1182 {ANSI_CHARSET, 0x30, 0x30,
1183 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1184 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1185 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1186 {HANGEUL_CHARSET, 0x8141, 0xac02,
1187 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1188 {GB2312_CHARSET, 0x8141, 0x4e04,
1189 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1190 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1191 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1193 UINT i;
1195 if (!pGetCharABCWidthsFloatW)
1197 win_skip("GetCharABCWidthsFloatW is not available on this platform\n");
1198 return;
1201 memset(&lf, 0, sizeof(lf));
1202 strcpy(lf.lfFaceName, "System");
1203 lf.lfHeight = 20;
1205 hfont = CreateFontIndirectA(&lf);
1206 hdc = GetDC(0);
1207 hfont = SelectObject(hdc, hfont);
1209 nb = pGetGlyphIndicesW(hdc, L"i", 1, glyphs, 0);
1210 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1212 ret = GetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1213 ok(!ret, "GetCharABCWidthsI should have failed\n");
1215 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1216 ok(!ret, "GetCharABCWidthsI should have failed\n");
1218 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1219 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1221 ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
1222 ok(!ret, "GetCharABCWidthsW should have failed\n");
1224 ret = GetCharABCWidthsW(hdc, 'a', 'a', NULL);
1225 ok(!ret, "GetCharABCWidthsW should have failed\n");
1227 ret = GetCharABCWidthsW(hdc, 'a', 'a', abc);
1228 ok(!ret, "GetCharABCWidthsW should have failed\n");
1230 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1231 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1233 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1234 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1236 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1237 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1239 hfont = SelectObject(hdc, hfont);
1240 DeleteObject(hfont);
1242 for (i = 0; i < ARRAY_SIZE(c); ++i)
1244 ABC a[2], w[2];
1245 ABC full[256];
1246 UINT code = 0x41, j;
1248 lf.lfFaceName[0] = '\0';
1249 lf.lfCharSet = c[i].cs;
1250 lf.lfPitchAndFamily = 0;
1251 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1253 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1254 continue;
1257 memset(a, 0, sizeof a);
1258 memset(w, 0, sizeof w);
1259 hfont = SelectObject(hdc, hfont);
1260 ok(GetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) && GetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w)
1261 && !memcmp(a, w, sizeof(a)),
1262 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1264 memset(a, 0xbb, sizeof a);
1265 ret = GetCharABCWidthsA(hdc, code, code, a);
1266 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1267 memset(full, 0xcc, sizeof full);
1268 ret = GetCharABCWidthsA(hdc, 0x00, code, full);
1269 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1270 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1271 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1273 for (j = 0; j < ARRAY_SIZE(range); ++j)
1275 memset(full, 0xdd, sizeof full);
1276 ret = GetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1277 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1278 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1279 if (ret)
1281 UINT last = range[j].last - range[j].first;
1282 ret = GetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1283 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1284 "GetCharABCWidthsA %x should match. codepage = %u\n",
1285 range[j].last, c[i].cs);
1289 hfont = SelectObject(hdc, hfont);
1290 DeleteObject(hfont);
1293 memset(&lf, 0, sizeof(lf));
1294 strcpy(lf.lfFaceName, "Tahoma");
1295 lf.lfHeight = 200;
1296 hfont = CreateFontIndirectA(&lf);
1298 /* test empty glyph's metrics */
1299 hfont = SelectObject(hdc, hfont);
1300 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1301 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1302 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1303 ret = GetCharABCWidthsW(hdc, ' ', ' ', abcw);
1304 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1305 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1307 /* 1) prepare unrotated font metrics */
1308 ret = GetCharABCWidthsW(hdc, 'a', 'a', abcw);
1309 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1310 DeleteObject(SelectObject(hdc, hfont));
1312 /* 2) get rotated font metrics */
1313 lf.lfEscapement = lf.lfOrientation = 900;
1314 hfont = CreateFontIndirectA(&lf);
1315 hfont = SelectObject(hdc, hfont);
1316 ret = GetCharABCWidthsW(hdc, 'a', 'a', abc);
1317 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1319 /* 3) compare ABC results */
1320 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1321 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1322 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1323 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1324 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1325 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1327 DeleteObject(SelectObject(hdc, hfont));
1329 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1330 in various widths. */
1331 for (i = 1; i <= 2; i++)
1333 UINT j;
1334 UINT code;
1336 memset(&lf, 0, sizeof(lf));
1337 lf.lfHeight = 20;
1338 if (i == 1)
1340 strcpy(lf.lfFaceName, "Tahoma");
1341 code = 'a';
1343 else
1345 strcpy(lf.lfFaceName, "Times New Roman");
1346 lf.lfItalic = TRUE;
1347 code = 'f';
1349 if (!is_truetype_font_installed(lf.lfFaceName))
1351 skip("%s is not installed\n", lf.lfFaceName);
1352 continue;
1354 for (j = 1; j <= 80; j++)
1356 GLYPHMETRICS gm;
1358 lf.lfWidth = j;
1359 hfont = CreateFontIndirectA(&lf);
1360 hfont = SelectObject(hdc, hfont);
1362 nb = GetGlyphOutlineA(hdc, code, GGO_METRICS, &gm, 0, NULL, &mat);
1363 ok(nb, "GetGlyphOutlineA should have succeeded at width %d\n", i);
1365 ret = GetCharABCWidthsA(hdc, code, code, abc);
1366 ok(ret, "GetCharABCWidthsA should have succeeded at width %d\n", i);
1368 ok(abc[0].abcA == gm.gmptGlyphOrigin.x,
1369 "abcA(%d) and gmptGlyphOrigin.x(%d) values are different at width %d\n",
1370 abc[0].abcA, gm.gmptGlyphOrigin.x, i);
1371 ok(abc[0].abcB == gm.gmBlackBoxX,
1372 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1373 abc[0].abcB, gm.gmBlackBoxX, i);
1374 DeleteObject(SelectObject(hdc, hfont));
1377 ReleaseDC(NULL, hdc);
1379 /* ABC sign test for a variety of transforms */
1380 memset(&lf, 0, sizeof(lf));
1381 strcpy(lf.lfFaceName, "Tahoma");
1382 lf.lfHeight = 20;
1383 hfont = CreateFontIndirectA(&lf);
1384 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1385 0, 0, 0, NULL);
1386 hdc = GetDC(hwnd);
1387 SetMapMode(hdc, MM_ANISOTROPIC);
1388 SelectObject(hdc, hfont);
1390 nb = pGetGlyphIndicesW(hdc, L"i", 1, glyphs, 0);
1391 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1393 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1394 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1395 ret = GetCharABCWidthsW(hdc, 'i', 'i', abcw);
1396 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1397 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1398 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1400 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf);
1401 SetWindowExtEx(hdc, -1, -1, NULL);
1402 SetGraphicsMode(hdc, GM_COMPATIBLE);
1403 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf);
1404 SetGraphicsMode(hdc, GM_ADVANCED);
1405 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf);
1406 SetWindowExtEx(hdc, 1, 1, NULL);
1407 SetGraphicsMode(hdc, GM_COMPATIBLE);
1408 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf);
1409 SetGraphicsMode(hdc, GM_ADVANCED);
1410 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf);
1412 ReleaseDC(hwnd, hdc);
1413 DestroyWindow(hwnd);
1415 /* RTL layout */
1416 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1417 0, 0, 0, NULL);
1418 hdc = GetDC(hwnd);
1419 SetMapMode(hdc, MM_ANISOTROPIC);
1420 SelectObject(hdc, hfont);
1422 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf);
1423 SetWindowExtEx(hdc, -1, -1, NULL);
1424 SetGraphicsMode(hdc, GM_COMPATIBLE);
1425 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf);
1426 SetGraphicsMode(hdc, GM_ADVANCED);
1427 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf);
1428 SetWindowExtEx(hdc, 1, 1, NULL);
1429 SetGraphicsMode(hdc, GM_COMPATIBLE);
1430 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf);
1431 SetGraphicsMode(hdc, GM_ADVANCED);
1432 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf);
1434 ReleaseDC(hwnd, hdc);
1435 DestroyWindow(hwnd);
1436 DeleteObject(hfont);
1439 static void test_text_extents(void)
1441 static const WCHAR wt[] = L"One\ntwo 3";
1442 LPINT extents;
1443 INT i, len, fit1, fit2, extents2[3];
1444 LOGFONTA lf;
1445 TEXTMETRICA tm;
1446 HDC hdc;
1447 HFONT hfont;
1448 SIZE sz;
1449 SIZE sz1, sz2;
1450 BOOL ret;
1452 memset(&lf, 0, sizeof(lf));
1453 strcpy(lf.lfFaceName, "Arial");
1454 lf.lfHeight = 20;
1456 hfont = CreateFontIndirectA(&lf);
1457 hdc = GetDC(0);
1458 hfont = SelectObject(hdc, hfont);
1459 GetTextMetricsA(hdc, &tm);
1460 ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1461 ok(ret, "got %d\n", ret);
1462 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1464 memset(&sz, 0xcc, sizeof(sz));
1465 ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1466 ok(ret, "got %d\n", ret);
1467 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1469 memset(&sz, 0xcc, sizeof(sz));
1470 ret = GetTextExtentPointA(hdc, "", 0, &sz);
1471 ok(ret, "got %d\n", ret);
1472 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1474 SetLastError(0xdeadbeef);
1475 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1476 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1478 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1479 hfont = SelectObject(hdc, hfont);
1480 DeleteObject(hfont);
1481 ReleaseDC(0, hdc);
1482 return;
1485 memset(&sz, 0xcc, sizeof(sz));
1486 ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1487 ok(ret, "got %d\n", ret);
1488 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1490 memset(&sz, 0xcc, sizeof(sz));
1491 ret = GetTextExtentPointW(hdc, L"", 0, &sz);
1492 ok(ret, "got %d\n", ret);
1493 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1495 len = lstrlenW(wt);
1496 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1497 extents[0] = 1; /* So that the increasing sequence test will fail
1498 if the extents array is untouched. */
1499 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1500 GetTextExtentPointW(hdc, wt, len, &sz2);
1501 ok(sz1.cy == sz2.cy,
1502 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1503 /* Because of the '\n' in the string GetTextExtentExPoint and
1504 GetTextExtentPoint return different widths under Win2k, but
1505 under WinXP they return the same width. So we don't test that
1506 here. */
1508 for (i = 1; i < len; ++i)
1509 ok(extents[i-1] <= extents[i],
1510 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1512 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1513 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1514 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1515 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1516 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1517 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1518 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1519 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1520 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1521 ok(extents[0] == extents[2] && extents[1] == extents[3],
1522 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1523 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1524 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1525 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1527 /* extents functions fail with -ve counts (the interesting case being -1) */
1528 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1529 ok(ret == FALSE, "got %d\n", ret);
1530 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1531 ok(ret == FALSE, "got %d\n", ret);
1532 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1533 ok(ret == FALSE, "got %d\n", ret);
1535 /* max_extent = 0 succeeds and returns zero */
1536 fit1 = fit2 = -215;
1537 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1538 ok(ret == TRUE ||
1539 broken(ret == FALSE), /* NT4, 2k */
1540 "got %d\n", ret);
1541 ok(fit1 == 0 ||
1542 broken(fit1 == -215), /* NT4, 2k */
1543 "fit = %d\n", fit1);
1544 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1545 ok(ret == TRUE, "got %d\n", ret);
1546 ok(fit2 == 0, "fit = %d\n", fit2);
1548 /* max_extent = -1 is interpreted as a very large width that will
1549 * definitely fit our three characters */
1550 fit1 = fit2 = -215;
1551 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1552 ok(ret == TRUE, "got %d\n", ret);
1553 ok(fit1 == 3, "fit = %d\n", fit1);
1554 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1555 ok(ret == TRUE, "got %d\n", ret);
1556 ok(fit2 == 3, "fit = %d\n", fit2);
1558 /* max_extent = -2 is interpreted similarly, but the Ansi version
1559 * rejects it while the Unicode one accepts it */
1560 fit1 = fit2 = -215;
1561 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1562 ok(ret == FALSE, "got %d\n", ret);
1563 ok(fit1 == -215, "fit = %d\n", fit1);
1564 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1565 ok(ret == TRUE, "got %d\n", ret);
1566 ok(fit2 == 3, "fit = %d\n", fit2);
1568 hfont = SelectObject(hdc, hfont);
1569 DeleteObject(hfont);
1571 /* non-MM_TEXT mapping mode */
1572 lf.lfHeight = 2000;
1573 hfont = CreateFontIndirectA(&lf);
1574 hfont = SelectObject(hdc, hfont);
1576 SetMapMode( hdc, MM_HIMETRIC );
1577 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1578 ok(ret, "got %d\n", ret);
1579 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1581 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1582 ok(ret, "got %d\n", ret);
1583 ok(fit1 == 2, "got %d\n", fit1);
1584 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1585 for(i = 0; i < 2; i++)
1586 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1588 hfont = SelectObject(hdc, hfont);
1589 DeleteObject(hfont);
1590 HeapFree(GetProcessHeap(), 0, extents);
1591 ReleaseDC(NULL, hdc);
1594 static void free_font(void *font)
1596 UnmapViewOfFile(font);
1599 static void *load_font(const char *font_name, DWORD *font_size)
1601 char file_name[MAX_PATH];
1602 HANDLE file, mapping;
1603 void *font;
1605 if (font_name[1] == ':')
1606 strcpy(file_name, font_name);
1607 else
1609 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
1610 strcat(file_name, "\\fonts\\");
1611 strcat(file_name, font_name);
1614 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
1615 if (file == INVALID_HANDLE_VALUE) return NULL;
1617 *font_size = GetFileSize(file, NULL);
1619 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
1620 if (!mapping)
1622 CloseHandle(file);
1623 return NULL;
1626 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
1628 CloseHandle(file);
1629 CloseHandle(mapping);
1630 return font;
1633 static void test_GetGlyphIndices(void)
1635 HDC hdc;
1636 HFONT hfont;
1637 DWORD charcount;
1638 LOGFONTA lf;
1639 DWORD flags = 0;
1640 WCHAR testtext[] = L"Test\xffff";
1641 WCHAR c[] = { 0x25bc /* Black Down-Pointing Triangle */, 0x212a /* Kelvin Sign */ };
1642 WORD glyphs[(sizeof(testtext)/2)-1];
1643 TEXTMETRICA textm;
1644 HFONT hOldFont;
1645 HANDLE rsrc;
1646 DWORD ret, font_size, num_fonts;
1647 void *font;
1648 char ttf_name[MAX_PATH];
1650 if (!pGetGlyphIndicesW) {
1651 win_skip("GetGlyphIndicesW not available on platform\n");
1652 return;
1655 hdc = GetDC(0);
1657 memset(&lf, 0, sizeof(lf));
1658 strcpy(lf.lfFaceName, "System");
1659 lf.lfHeight = 16;
1660 lf.lfCharSet = ANSI_CHARSET;
1662 hfont = CreateFontIndirectA(&lf);
1663 ok(hfont != 0, "CreateFontIndirect failed\n");
1664 hOldFont = SelectObject(hdc, hfont);
1665 ok(GetTextMetricsA(hdc, &textm), "GetTextMetrics failed\n");
1666 if (textm.tmCharSet == ANSI_CHARSET)
1668 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1669 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1670 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1671 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1672 flags = 0;
1673 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1674 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1675 ok(glyphs[4] == textm.tmDefaultChar || glyphs[4] == 0x20 /* CJK Windows */,
1676 "GetGlyphIndicesW should have returned a %04x not %04x\n", textm.tmDefaultChar, glyphs[4]);
1678 else
1679 /* FIXME: Write tests for non-ANSI charsets. */
1680 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1682 DeleteObject(SelectObject(hdc, hOldFont));
1684 memset(&lf, 0, sizeof(lf));
1685 strcpy(lf.lfFaceName, "MS Sans Serif");
1686 lf.lfHeight = -13;
1687 lf.lfCharSet = DEFAULT_CHARSET;
1688 hfont = CreateFontIndirectA(&lf);
1689 ok(hfont != 0, "CreateFontIndirect failed\n");
1690 hOldFont = SelectObject(hdc, hfont);
1691 ok(GetTextMetricsA(hdc, &textm), "GetTextMetrics failed\n");
1693 glyphs[0] = glyphs[1] = 0;
1694 charcount = GetGlyphIndicesW(hdc, c, ARRAY_SIZE(c), glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1695 ok(charcount == ARRAY_SIZE(c), "got %u\n", charcount);
1696 ok(glyphs[0] == 0x001f || glyphs[0] == 0xffff /* Vista */, "got %#x\n", glyphs[0]);
1697 ok(glyphs[1] == 0x001f || glyphs[1] == 0xffff /* Vista */, "got %#x\n", glyphs[1]);
1699 glyphs[0] = glyphs[1] = 0;
1700 charcount = GetGlyphIndicesW(hdc, c, ARRAY_SIZE(c), glyphs, 0);
1701 ok(charcount == ARRAY_SIZE(c), "got %u\n", charcount);
1702 ok(glyphs[0] == textm.tmDefaultChar || glyphs[0] == 0x20 /* CJK Windows */, "got %#x\n", glyphs[0]);
1703 ok(glyphs[1] == textm.tmDefaultChar || glyphs[1] == 0x20 /* CJK Windows */, "got %#x\n", glyphs[1]);
1705 DeleteObject(SelectObject(hdc, hOldFont));
1707 if(!is_font_installed("Tahoma"))
1709 skip("Tahoma is not installed so skipping this test\n");
1710 ReleaseDC(0, hdc);
1711 return;
1713 memset(&lf, 0, sizeof(lf));
1714 strcpy(lf.lfFaceName, "Tahoma");
1715 lf.lfHeight = 20;
1717 hfont = CreateFontIndirectA(&lf);
1718 hOldFont = SelectObject(hdc, hfont);
1719 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1720 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1721 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1722 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1723 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1724 flags = 0;
1725 testtext[0] = textm.tmDefaultChar;
1726 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1727 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1728 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1729 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1730 DeleteObject(SelectObject(hdc, hOldFont));
1732 ret = write_ttf_file("wine_nul.ttf", ttf_name);
1733 ok(ret, "Failed to create test font file.\n");
1734 font = load_font(ttf_name, &font_size);
1735 ok(font != NULL, "Failed to map font file.\n");
1736 num_fonts = 0;
1737 rsrc = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
1738 ok(ret != 0, "Failed to add resource, %d.\n", GetLastError());
1739 ok(num_fonts == 1, "Unexpected number of fonts %u.\n", num_fonts);
1741 memset(&lf, 0, sizeof(lf));
1742 strcpy(lf.lfFaceName, "wine_nul");
1743 lf.lfHeight = 20;
1744 flags = 0;
1745 hfont = CreateFontIndirectA(&lf);
1746 hOldFont = SelectObject(hdc, hfont);
1747 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1748 testtext[0] = 'T';
1749 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1750 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1751 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1752 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1753 DeleteObject(SelectObject(hdc, hOldFont));
1755 ReleaseDC(0, hdc);
1757 ret = pRemoveFontMemResourceEx(rsrc);
1758 ok(ret, "RemoveFontMemResourceEx error %d\n", GetLastError());
1759 free_font(font);
1760 ret = DeleteFileA(ttf_name);
1761 ok(ret, "Failed to delete font file, %d.\n", GetLastError());
1764 static void test_GetKerningPairs(void)
1766 static const struct kerning_data
1768 const char face_name[LF_FACESIZE];
1769 LONG height;
1770 /* some interesting fields from OUTLINETEXTMETRIC */
1771 LONG tmHeight, tmAscent, tmDescent;
1772 UINT otmEMSquare;
1773 INT otmAscent;
1774 INT otmDescent;
1775 UINT otmLineGap;
1776 UINT otmsCapEmHeight;
1777 UINT otmsXHeight;
1778 INT otmMacAscent;
1779 INT otmMacDescent;
1780 UINT otmMacLineGap;
1781 UINT otmusMinimumPPEM;
1782 /* small subset of kerning pairs to test */
1783 DWORD total_kern_pairs;
1784 const KERNINGPAIR kern_pair[26];
1785 } kd[] =
1787 {"Arial", 12, 12, 9, 3,
1788 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1791 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1792 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1793 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1794 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1795 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1796 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1797 {933,970,+1},{933,972,-1}
1800 {"Arial", -34, 39, 32, 7,
1801 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1804 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1805 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1806 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1807 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1808 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1809 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1810 {933,970,+2},{933,972,-3}
1813 { "Arial", 120, 120, 97, 23,
1814 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1817 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1818 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1819 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1820 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1821 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1822 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1823 {933,970,+6},{933,972,-10}
1826 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1827 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1828 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1831 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1832 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1833 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1834 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1835 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1836 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1837 {933,970,+54},{933,972,-83}
1840 #endif
1842 LOGFONTA lf;
1843 HFONT hfont, hfont_old;
1844 KERNINGPAIR *kern_pair;
1845 HDC hdc;
1846 DWORD total_kern_pairs, ret, i, n, matches;
1848 hdc = GetDC(0);
1850 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1851 * which may render this test unusable, so we're trying to avoid that.
1853 SetLastError(0xdeadbeef);
1854 GetKerningPairsW(hdc, 0, NULL);
1855 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1857 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1858 ReleaseDC(0, hdc);
1859 return;
1862 for (i = 0; i < ARRAY_SIZE(kd); i++)
1864 OUTLINETEXTMETRICW otm;
1865 UINT uiRet;
1867 if (!is_font_installed(kd[i].face_name))
1869 skip("%s is not installed so skipping this test\n", kd[i].face_name);
1870 continue;
1873 memset(&lf, 0, sizeof(lf));
1874 strcpy(lf.lfFaceName, kd[i].face_name);
1875 lf.lfHeight = kd[i].height;
1876 hfont = CreateFontIndirectA(&lf);
1877 ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name);
1879 hfont_old = SelectObject(hdc, hfont);
1881 SetLastError(0xdeadbeef);
1882 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1883 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1884 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1886 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1887 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1888 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1889 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1890 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1891 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1893 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1894 kd[i].otmEMSquare, otm.otmEMSquare);
1895 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1896 kd[i].otmAscent, otm.otmAscent);
1897 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1898 kd[i].otmDescent, otm.otmDescent);
1899 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1900 kd[i].otmLineGap, otm.otmLineGap);
1901 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1902 kd[i].otmMacDescent, otm.otmMacDescent);
1903 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1904 kd[i].otmMacAscent, otm.otmMacAscent);
1905 todo_wine
1906 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1907 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1908 todo_wine
1909 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1910 kd[i].otmsXHeight, otm.otmsXHeight);
1911 ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1912 kd[i].otmMacLineGap, otm.otmMacLineGap);
1913 todo_wine
1914 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1915 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1917 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1918 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1920 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1921 * passes on XP.
1923 SetLastError(0xdeadbeef);
1924 ret = GetKerningPairsW(hdc, 0, kern_pair);
1925 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1926 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1927 ok(ret == 0, "got %u, expected 0\n", ret);
1929 ret = GetKerningPairsW(hdc, 100, NULL);
1930 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1932 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1933 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1935 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1936 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1938 matches = 0;
1940 for (n = 0; n < ret; n++)
1942 DWORD j;
1944 for (j = 0; j < kd[i].total_kern_pairs; j++)
1946 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1947 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1949 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1950 "pair %d:%d got %d, expected %d\n",
1951 kern_pair[n].wFirst, kern_pair[n].wSecond,
1952 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1953 matches++;
1958 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1959 matches, kd[i].total_kern_pairs);
1961 HeapFree(GetProcessHeap(), 0, kern_pair);
1963 SelectObject(hdc, hfont_old);
1964 DeleteObject(hfont);
1967 ReleaseDC(0, hdc);
1970 struct font_data
1972 const char face_name[LF_FACESIZE];
1973 int requested_height;
1974 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1975 BOOL exact;
1978 static void test_height( HDC hdc, const struct font_data *fd )
1980 LOGFONTA lf;
1981 HFONT hfont, old_hfont;
1982 TEXTMETRICA tm;
1983 INT ret, i;
1985 for (i = 0; fd[i].face_name[0]; i++)
1987 if (!is_truetype_font_installed(fd[i].face_name))
1989 skip("%s is not installed\n", fd[i].face_name);
1990 continue;
1993 memset(&lf, 0, sizeof(lf));
1994 lf.lfHeight = fd[i].requested_height;
1995 lf.lfWeight = fd[i].weight;
1996 strcpy(lf.lfFaceName, fd[i].face_name);
1998 hfont = CreateFontIndirectA(&lf);
1999 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
2001 old_hfont = SelectObject(hdc, hfont);
2002 ret = GetTextMetricsA(hdc, &tm);
2003 ok(ret, "GetTextMetrics error %d\n", GetLastError());
2004 if(fd[i].dpi == tm.tmDigitizedAspectX)
2006 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);
2007 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);
2008 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);
2009 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);
2010 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);
2011 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);
2014 SelectObject(hdc, old_hfont);
2015 /* force GDI to use new font, otherwise Windows leaks the font reference */
2016 GetTextMetricsA(hdc, &tm);
2017 DeleteObject(hfont);
2021 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
2023 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
2024 DWORD *table = (DWORD *)ttf + 3;
2026 for (i = 0; i < num_tables; i++)
2028 if (table[0] == tag)
2029 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
2030 table += 4;
2032 return NULL;
2035 static void test_height_selection_vdmx( HDC hdc )
2037 static const struct font_data charset_0[] = /* doesn't use VDMX */
2039 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
2040 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
2041 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2042 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2043 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2044 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
2045 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2046 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
2047 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
2048 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
2049 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
2050 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
2051 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
2052 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
2053 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2054 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
2055 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
2056 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
2057 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
2058 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2059 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
2060 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
2061 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
2062 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2063 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
2064 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2065 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2066 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2067 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2068 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2069 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
2070 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
2071 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
2072 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
2073 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
2074 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
2075 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2076 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
2077 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
2078 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
2079 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2080 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
2081 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
2082 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
2083 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
2084 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
2085 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
2086 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
2087 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
2088 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2089 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
2090 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2091 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2094 static const struct font_data charset_1[] = /* Uses VDMX */
2096 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
2097 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
2098 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2099 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2100 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2101 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2102 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2103 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2104 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2105 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2106 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2107 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2108 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2109 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2110 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2111 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2112 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2113 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2114 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2115 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2116 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2117 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2118 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2119 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
2120 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
2121 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
2122 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2123 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2124 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2125 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2126 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2127 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2128 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2129 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2130 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2131 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2132 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2133 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2134 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2135 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2136 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2137 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2138 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2139 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2140 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2141 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2142 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2143 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2144 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2145 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2146 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2147 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2148 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2151 static const struct vdmx_data
2153 WORD version;
2154 BYTE bCharSet;
2155 const struct font_data *fd;
2156 } data[] =
2158 { 0, 0, charset_0 },
2159 { 0, 1, charset_1 },
2160 { 1, 0, charset_0 },
2161 { 1, 1, charset_1 }
2163 int i;
2164 DWORD size, num;
2165 WORD *vdmx_header;
2166 BYTE *ratio_rec;
2167 char ttf_name[MAX_PATH];
2168 void *res, *copy;
2169 BOOL ret;
2171 if (!pAddFontResourceExA)
2173 win_skip("AddFontResourceExA unavailable\n");
2174 return;
2177 for (i = 0; i < ARRAY_SIZE(data); i++)
2179 res = get_res_data( "wine_vdmx.ttf", &size );
2181 copy = HeapAlloc( GetProcessHeap(), 0, size );
2182 memcpy( copy, res, size );
2183 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2184 vdmx_header[0] = GET_BE_WORD( data[i].version );
2185 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2186 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2187 ratio_rec = (BYTE *)&vdmx_header[3];
2188 ratio_rec[0] = data[i].bCharSet;
2190 write_tmp_file( copy, &size, ttf_name );
2191 HeapFree( GetProcessHeap(), 0, copy );
2193 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2194 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2195 if (!num) win_skip("Unable to add ttf font resource\n");
2196 else
2198 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2199 test_height( hdc, data[i].fd );
2200 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2202 ret = DeleteFileA( ttf_name );
2203 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2204 "DeleteFile error %d\n", GetLastError());
2208 static void test_height_selection(void)
2210 static const struct font_data tahoma[] =
2212 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2213 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2214 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2215 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2216 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2217 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2218 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2219 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2220 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2221 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2222 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2224 HDC hdc = CreateCompatibleDC(0);
2225 ok(hdc != NULL, "failed to create hdc\n");
2227 test_height( hdc, tahoma );
2228 test_height_selection_vdmx( hdc );
2230 DeleteDC(hdc);
2233 static UINT get_font_fsselection(LOGFONTA *lf)
2235 OUTLINETEXTMETRICA *otm;
2236 HFONT hfont, hfont_old;
2237 DWORD ret, otm_size;
2238 UINT fsSelection;
2239 HDC hdc;
2241 hdc = GetDC(0);
2242 hfont = CreateFontIndirectA(lf);
2243 ok(hfont != NULL, "failed to create a font\n");
2245 hfont_old = SelectObject(hdc, hfont);
2247 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2248 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2249 otm->otmSize = sizeof(*otm);
2250 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2251 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2252 fsSelection = otm->otmfsSelection;
2253 HeapFree(GetProcessHeap(), 0, otm);
2254 SelectObject(hdc, hfont_old);
2255 DeleteObject(hfont);
2256 ReleaseDC(0, hdc);
2258 return fsSelection;
2261 static void test_GetOutlineTextMetrics(void)
2263 OUTLINETEXTMETRICA *otm;
2264 LOGFONTA lf;
2265 HFONT hfont, hfont_old;
2266 HDC hdc;
2267 DWORD ret, otm_size;
2268 LPSTR unset_ptr;
2269 UINT fsSelection;
2271 /* check fsSelection field with bold simulation */
2272 memset(&lf, 0, sizeof(lf));
2273 strcpy(lf.lfFaceName, "Wingdings");
2274 lf.lfCharSet = SYMBOL_CHARSET;
2276 /* regular face */
2277 fsSelection = get_font_fsselection(&lf);
2278 ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection);
2280 /* face with bold simulation */
2281 lf.lfWeight = FW_BOLD;
2282 fsSelection = get_font_fsselection(&lf);
2283 ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection);
2285 /* check fsSelection field with oblique simulation */
2286 memset(&lf, 0, sizeof(lf));
2287 strcpy(lf.lfFaceName, "Tahoma");
2288 lf.lfHeight = -13;
2289 lf.lfWeight = FW_NORMAL;
2290 lf.lfPitchAndFamily = DEFAULT_PITCH;
2291 lf.lfQuality = PROOF_QUALITY;
2293 /* regular face */
2294 fsSelection = get_font_fsselection(&lf);
2295 ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection);
2297 lf.lfItalic = 1;
2298 /* face with oblique simulation */
2299 fsSelection = get_font_fsselection(&lf);
2300 ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection);
2302 if (!is_font_installed("Arial"))
2304 skip("Arial is not installed\n");
2305 return;
2308 hdc = GetDC(0);
2310 memset(&lf, 0, sizeof(lf));
2311 strcpy(lf.lfFaceName, "Arial");
2312 lf.lfHeight = -13;
2313 lf.lfWeight = FW_NORMAL;
2314 lf.lfPitchAndFamily = DEFAULT_PITCH;
2315 lf.lfQuality = PROOF_QUALITY;
2316 hfont = CreateFontIndirectA(&lf);
2317 ok(hfont != NULL, "failed to create a font\n");
2319 hfont_old = SelectObject(hdc, hfont);
2320 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2322 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2324 memset(otm, 0xAA, otm_size);
2325 SetLastError(0xdeadbeef);
2326 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2327 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2328 ok(ret == 1 /* Win9x */ ||
2329 ret == otm->otmSize /* XP*/,
2330 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2331 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2333 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2334 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2335 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2336 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2339 memset(otm, 0xAA, otm_size);
2340 SetLastError(0xdeadbeef);
2341 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2342 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2343 ok(ret == 1 /* Win9x */ ||
2344 ret == otm->otmSize /* XP*/,
2345 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2346 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2348 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2349 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2350 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2351 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2354 /* ask about truncated data */
2355 memset(otm, 0xAA, otm_size);
2356 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2357 SetLastError(0xdeadbeef);
2358 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2359 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2360 ok(ret == 1 /* Win9x */ ||
2361 ret == otm->otmSize /* XP*/,
2362 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2363 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2365 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2366 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2367 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2369 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2371 /* check handling of NULL pointer */
2372 SetLastError(0xdeadbeef);
2373 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2374 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2376 HeapFree(GetProcessHeap(), 0, otm);
2378 SelectObject(hdc, hfont_old);
2379 DeleteObject(hfont);
2381 ReleaseDC(0, hdc);
2384 static void testJustification(const char *context, HDC hdc, PCSTR str, RECT *clientArea)
2386 INT y,
2387 breakCount,
2388 areaWidth = clientArea->right - clientArea->left,
2389 nErrors = 0, e;
2390 const char *pFirstChar, *pLastChar;
2391 SIZE size;
2392 TEXTMETRICA tm;
2393 struct err
2395 const char *start;
2396 int len;
2397 int GetTextExtentExPointWWidth;
2398 } error[20];
2400 GetTextMetricsA(hdc, &tm);
2401 y = clientArea->top;
2402 do {
2403 breakCount = 0;
2404 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2405 pFirstChar = str;
2407 do {
2408 pLastChar = str;
2410 /* if not at the end of the string, ... */
2411 if (*str == '\0') break;
2412 /* ... add the next word to the current extent */
2413 while (*str != '\0' && *str++ != tm.tmBreakChar);
2414 breakCount++;
2415 SetTextJustification(hdc, 0, 0);
2416 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2417 } while ((int) size.cx < areaWidth);
2419 /* ignore trailing break chars */
2420 breakCount--;
2421 while (*(pLastChar - 1) == tm.tmBreakChar)
2423 pLastChar--;
2424 breakCount--;
2427 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2429 SetTextJustification(hdc, 0, 0);
2430 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2432 /* do not justify the last extent */
2433 if (*str != '\0' && breakCount > 0)
2435 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2436 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2437 if (size.cx != areaWidth && nErrors < ARRAY_SIZE(error) - 1)
2439 error[nErrors].start = pFirstChar;
2440 error[nErrors].len = pLastChar - pFirstChar;
2441 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2442 nErrors++;
2446 y += size.cy;
2447 str = pLastChar;
2448 } while (*str && y < clientArea->bottom);
2450 for (e = 0; e < nErrors; e++)
2452 /* The width returned by GetTextExtentPoint32() is exactly the same
2453 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2454 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2455 "%s: GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2456 context, error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2460 static void test_SetTextJustification(void)
2462 HDC hdc;
2463 RECT clientArea;
2464 LOGFONTA lf;
2465 HFONT hfont;
2466 HWND hwnd;
2467 SIZE size, expect;
2468 int i;
2469 WORD indices[2];
2470 static const char testText[] =
2471 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2472 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2473 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2474 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2475 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2476 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2477 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2479 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2480 GetClientRect( hwnd, &clientArea );
2481 hdc = GetDC( hwnd );
2483 if (!is_font_installed("Times New Roman"))
2485 skip("Times New Roman is not installed\n");
2486 return;
2489 memset(&lf, 0, sizeof lf);
2490 lf.lfCharSet = ANSI_CHARSET;
2491 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2492 lf.lfWeight = FW_DONTCARE;
2493 lf.lfHeight = 20;
2494 lf.lfQuality = DEFAULT_QUALITY;
2495 lstrcpyA(lf.lfFaceName, "Times New Roman");
2496 hfont = create_font("Times New Roman", &lf);
2497 SelectObject(hdc, hfont);
2499 testJustification("default", hdc, testText, &clientArea);
2501 if (!pGetTextExtentExPointI) goto done;
2502 GetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2504 SetTextJustification(hdc, 0, 0);
2505 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2506 GetTextExtentPoint32A(hdc, " ", 3, &size);
2507 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2508 SetTextJustification(hdc, 4, 1);
2509 GetTextExtentPoint32A(hdc, " ", 1, &size);
2510 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2511 SetTextJustification(hdc, 9, 2);
2512 GetTextExtentPoint32A(hdc, " ", 2, &size);
2513 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2514 SetTextJustification(hdc, 7, 3);
2515 GetTextExtentPoint32A(hdc, " ", 3, &size);
2516 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2517 SetTextJustification(hdc, 7, 3);
2518 SetTextCharacterExtra(hdc, 2 );
2519 GetTextExtentPoint32A(hdc, " ", 3, &size);
2520 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2521 SetTextJustification(hdc, 0, 0);
2522 SetTextCharacterExtra(hdc, 0);
2523 size.cx = size.cy = 1234;
2524 GetTextExtentPoint32A(hdc, " ", 0, &size);
2525 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2526 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2527 SetTextJustification(hdc, 5, 1);
2528 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2529 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2530 SetTextJustification(hdc, 0, 0);
2532 SetMapMode( hdc, MM_ANISOTROPIC );
2533 SetWindowExtEx( hdc, 2, 2, NULL );
2534 GetClientRect( hwnd, &clientArea );
2535 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2536 testJustification("2x2", hdc, testText, &clientArea);
2538 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2539 for (i = 0; i < 10; i++)
2541 SetTextCharacterExtra(hdc, i);
2542 GetTextExtentPoint32A(hdc, "A", 1, &size);
2543 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2545 SetTextCharacterExtra(hdc, 0);
2546 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2547 for (i = 0; i < 10; i++)
2549 SetTextCharacterExtra(hdc, i);
2550 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2551 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2553 SetTextCharacterExtra(hdc, 0);
2555 SetViewportExtEx( hdc, 3, 3, NULL );
2556 GetClientRect( hwnd, &clientArea );
2557 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2558 testJustification("3x3", hdc, testText, &clientArea);
2560 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2561 for (i = 0; i < 10; i++)
2563 SetTextCharacterExtra(hdc, i);
2564 GetTextExtentPoint32A(hdc, "A", 1, &size);
2565 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2568 done:
2569 DeleteObject(hfont);
2570 ReleaseDC(hwnd, hdc);
2571 DestroyWindow(hwnd);
2574 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2576 HDC hdc;
2577 LOGFONTA lf;
2578 HFONT hfont, hfont_old;
2579 CHARSETINFO csi;
2580 FONTSIGNATURE fs;
2581 INT cs;
2582 DWORD i, ret;
2583 char name[64];
2585 assert(count <= 128);
2587 memset(&lf, 0, sizeof(lf));
2589 lf.lfCharSet = charset;
2590 lf.lfHeight = 10;
2591 lstrcpyA(lf.lfFaceName, "Arial");
2592 SetLastError(0xdeadbeef);
2593 hfont = CreateFontIndirectA(&lf);
2594 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2596 hdc = GetDC(0);
2597 hfont_old = SelectObject(hdc, hfont);
2599 cs = GetTextCharsetInfo(hdc, &fs, 0);
2600 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2602 SetLastError(0xdeadbeef);
2603 ret = GetTextFaceA(hdc, sizeof(name), name);
2604 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2606 if (charset == SYMBOL_CHARSET)
2608 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2609 ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n");
2611 else
2613 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2614 ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2617 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2619 trace("Can't find codepage for charset %d\n", cs);
2620 ReleaseDC(0, hdc);
2621 return FALSE;
2623 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2625 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2627 skip("Font code page %d, looking for code page %d\n",
2628 pGdiGetCodePage(hdc), code_page);
2629 ReleaseDC(0, hdc);
2630 return FALSE;
2633 if (unicode)
2635 char ansi_buf[128];
2636 WCHAR unicode_buf[128];
2638 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2640 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2642 SetLastError(0xdeadbeef);
2643 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2644 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2645 count, ret, GetLastError());
2647 else
2649 char ansi_buf[128];
2651 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2653 SetLastError(0xdeadbeef);
2654 ret = GetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2655 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2656 count, ret, GetLastError());
2659 SelectObject(hdc, hfont_old);
2660 DeleteObject(hfont);
2662 ReleaseDC(0, hdc);
2664 return TRUE;
2667 static void test_font_charset(void)
2669 static struct charset_data
2671 INT charset;
2672 UINT code_page;
2673 WORD font_idxA[128], font_idxW[128];
2674 } cd[] =
2676 { ANSI_CHARSET, 1252 },
2677 { RUSSIAN_CHARSET, 1251 },
2678 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2680 int i;
2682 if (!pGetGlyphIndicesW)
2684 win_skip("Skipping the font charset test on a Win9x platform\n");
2685 return;
2688 if (!is_font_installed("Arial"))
2690 skip("Arial is not installed\n");
2691 return;
2694 for (i = 0; i < ARRAY_SIZE(cd); i++)
2696 if (cd[i].charset == SYMBOL_CHARSET)
2698 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2700 skip("Symbol or Wingdings is not installed\n");
2701 break;
2704 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2705 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2706 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2709 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2710 if (i > 2)
2712 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2713 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2715 else
2716 skip("Symbol or Wingdings is not installed\n");
2719 static void test_GdiGetCodePage(void)
2721 static const struct _matching_data
2723 UINT current_codepage;
2724 LPCSTR lfFaceName;
2725 UCHAR lfCharSet;
2726 UINT expected_codepage;
2727 } matching_data[] = {
2728 {1251, "Arial", ANSI_CHARSET, 1252},
2729 {1251, "Tahoma", ANSI_CHARSET, 1252},
2731 {1252, "Arial", ANSI_CHARSET, 1252},
2732 {1252, "Tahoma", ANSI_CHARSET, 1252},
2734 {1253, "Arial", ANSI_CHARSET, 1252},
2735 {1253, "Tahoma", ANSI_CHARSET, 1252},
2737 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2738 { 932, "Tahoma", ANSI_CHARSET, 1252},
2739 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2741 { 936, "Arial", ANSI_CHARSET, 936},
2742 { 936, "Tahoma", ANSI_CHARSET, 936},
2743 { 936, "Simsun", ANSI_CHARSET, 936},
2745 { 949, "Arial", ANSI_CHARSET, 949},
2746 { 949, "Tahoma", ANSI_CHARSET, 949},
2747 { 949, "Gulim", ANSI_CHARSET, 949},
2749 { 950, "Arial", ANSI_CHARSET, 950},
2750 { 950, "Tahoma", ANSI_CHARSET, 950},
2751 { 950, "PMingLiU", ANSI_CHARSET, 950},
2753 HDC hdc;
2754 LOGFONTA lf;
2755 HFONT hfont;
2756 UINT acp;
2757 DWORD codepage;
2758 int i;
2760 if (!pGdiGetCodePage)
2762 skip("GdiGetCodePage not available on this platform\n");
2763 return;
2766 acp = GetACP();
2768 for (i = 0; i < ARRAY_SIZE(matching_data); i++)
2770 /* only test data matched current locale codepage */
2771 if (matching_data[i].current_codepage != acp)
2772 continue;
2774 if (!is_font_installed(matching_data[i].lfFaceName))
2776 skip("%s is not installed\n", matching_data[i].lfFaceName);
2777 continue;
2780 hdc = GetDC(0);
2782 memset(&lf, 0, sizeof(lf));
2783 lf.lfHeight = -16;
2784 lf.lfCharSet = matching_data[i].lfCharSet;
2785 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2786 hfont = CreateFontIndirectA(&lf);
2787 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2789 hfont = SelectObject(hdc, hfont);
2790 codepage = pGdiGetCodePage(hdc);
2791 ok(codepage == matching_data[i].expected_codepage,
2792 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2794 hfont = SelectObject(hdc, hfont);
2795 DeleteObject(hfont);
2797 /* CLIP_DFA_DISABLE turns off the font association */
2798 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2799 hfont = CreateFontIndirectA(&lf);
2800 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2802 hfont = SelectObject(hdc, hfont);
2803 codepage = pGdiGetCodePage(hdc);
2804 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2806 hfont = SelectObject(hdc, hfont);
2807 DeleteObject(hfont);
2809 ReleaseDC(NULL, hdc);
2813 static void test_GetFontUnicodeRanges(void)
2815 LOGFONTA lf;
2816 HDC hdc;
2817 HFONT hfont, hfont_old;
2818 DWORD size;
2819 GLYPHSET *gs;
2821 if (!pGetFontUnicodeRanges)
2823 win_skip("GetFontUnicodeRanges not available before W2K\n");
2824 return;
2827 memset(&lf, 0, sizeof(lf));
2828 lstrcpyA(lf.lfFaceName, "Arial");
2829 hfont = create_font("Arial", &lf);
2831 hdc = GetDC(0);
2832 hfont_old = SelectObject(hdc, hfont);
2834 size = pGetFontUnicodeRanges(NULL, NULL);
2835 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2837 size = pGetFontUnicodeRanges(hdc, NULL);
2838 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2840 gs = heap_alloc_zero(size);
2842 size = pGetFontUnicodeRanges(hdc, gs);
2843 ok(size, "GetFontUnicodeRanges failed\n");
2844 ok(gs->cRanges, "Unexpected ranges count.\n");
2846 heap_free(gs);
2848 SelectObject(hdc, hfont_old);
2849 DeleteObject(hfont);
2850 ReleaseDC(NULL, hdc);
2853 struct enum_font_data
2855 int total, size;
2856 LOGFONTA *lf;
2859 struct enum_fullname_data
2861 int total, size;
2862 ENUMLOGFONTA *elf;
2865 struct enum_fullname_data_w
2867 int total, size;
2868 ENUMLOGFONTW *elf;
2871 struct enum_font_dataW
2873 int total, size;
2874 LOGFONTW *lf;
2877 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2879 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2880 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2882 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2884 if (type != TRUETYPE_FONTTYPE) return 1;
2886 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2888 if (efd->total >= efd->size)
2890 efd->size = max( (efd->total + 1) * 2, 256 );
2891 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2892 if (!efd->lf) return 0;
2894 efd->lf[efd->total++] = *lf;
2896 return 1;
2899 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2901 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2902 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2904 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2906 if (type != TRUETYPE_FONTTYPE) return 1;
2908 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2910 if (efd->total >= efd->size)
2912 efd->size = max( (efd->total + 1) * 2, 256 );
2913 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2914 if (!efd->lf) return 0;
2916 efd->lf[efd->total++] = *lf;
2918 return 1;
2921 static void get_charset_stats(struct enum_font_data *efd,
2922 int *ansi_charset, int *symbol_charset,
2923 int *russian_charset)
2925 int i;
2927 *ansi_charset = 0;
2928 *symbol_charset = 0;
2929 *russian_charset = 0;
2931 for (i = 0; i < efd->total; i++)
2933 switch (efd->lf[i].lfCharSet)
2935 case ANSI_CHARSET:
2936 (*ansi_charset)++;
2937 break;
2938 case SYMBOL_CHARSET:
2939 (*symbol_charset)++;
2940 break;
2941 case RUSSIAN_CHARSET:
2942 (*russian_charset)++;
2943 break;
2948 static void get_charset_statsW(struct enum_font_dataW *efd,
2949 int *ansi_charset, int *symbol_charset,
2950 int *russian_charset)
2952 int i;
2954 *ansi_charset = 0;
2955 *symbol_charset = 0;
2956 *russian_charset = 0;
2958 for (i = 0; i < efd->total; i++)
2960 switch (efd->lf[i].lfCharSet)
2962 case ANSI_CHARSET:
2963 (*ansi_charset)++;
2964 break;
2965 case SYMBOL_CHARSET:
2966 (*symbol_charset)++;
2967 break;
2968 case RUSSIAN_CHARSET:
2969 (*russian_charset)++;
2970 break;
2975 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2977 struct enum_font_data efd;
2978 struct enum_font_dataW efdw;
2979 LOGFONTA lf;
2980 HDC hdc;
2981 int i, ret, ansi_charset, symbol_charset, russian_charset;
2983 if (*font_name && !is_truetype_font_installed(font_name))
2985 skip("%s is not installed\n", font_name);
2986 return;
2988 memset( &efd, 0, sizeof(efd) );
2989 memset( &efdw, 0, sizeof(efdw) );
2991 hdc = GetDC(0);
2993 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2994 * while EnumFontFamiliesEx doesn't.
2996 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2999 * Use EnumFontFamiliesW since win98 crashes when the
3000 * second parameter is NULL using EnumFontFamilies
3002 efdw.total = 0;
3003 SetLastError(0xdeadbeef);
3004 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
3005 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
3006 if(ret)
3008 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
3009 ok(efdw.total > 0, "fonts enumerated: NULL\n");
3010 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
3011 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3012 ok(russian_charset > 0 ||
3013 broken(russian_charset == 0), /* NT4 */
3014 "NULL family should enumerate RUSSIAN_CHARSET\n");
3017 efdw.total = 0;
3018 SetLastError(0xdeadbeef);
3019 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
3020 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
3021 if(ret)
3023 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
3024 ok(efdw.total > 0, "fonts enumerated: NULL\n");
3025 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
3026 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3027 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
3031 efd.total = 0;
3032 SetLastError(0xdeadbeef);
3033 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
3034 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
3035 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3036 if (*font_name)
3037 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
3038 else
3039 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
3040 for (i = 0; i < efd.total; i++)
3042 /* FIXME: remove completely once Wine is fixed */
3043 todo_wine_if(efd.lf[i].lfCharSet != font_charset)
3044 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3045 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3046 font_name, efd.lf[i].lfFaceName);
3049 memset(&lf, 0, sizeof(lf));
3050 lf.lfCharSet = ANSI_CHARSET;
3051 strcpy(lf.lfFaceName, font_name);
3052 efd.total = 0;
3053 SetLastError(0xdeadbeef);
3054 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3055 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3056 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3057 if (font_charset == SYMBOL_CHARSET)
3059 if (*font_name)
3060 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
3061 else
3062 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
3064 else
3066 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
3067 for (i = 0; i < efd.total; i++)
3069 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3070 if (*font_name)
3071 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3072 font_name, efd.lf[i].lfFaceName);
3076 /* DEFAULT_CHARSET should enumerate all available charsets */
3077 memset(&lf, 0, sizeof(lf));
3078 lf.lfCharSet = DEFAULT_CHARSET;
3079 strcpy(lf.lfFaceName, font_name);
3080 efd.total = 0;
3081 SetLastError(0xdeadbeef);
3082 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3083 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3084 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3085 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
3086 for (i = 0; i < efd.total; i++)
3088 if (*font_name)
3089 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3090 font_name, efd.lf[i].lfFaceName);
3092 if (*font_name)
3094 switch (font_charset)
3096 case ANSI_CHARSET:
3097 ok(ansi_charset > 0,
3098 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3099 ok(!symbol_charset,
3100 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
3101 ok(russian_charset > 0,
3102 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3103 break;
3104 case SYMBOL_CHARSET:
3105 ok(!ansi_charset,
3106 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
3107 ok(symbol_charset,
3108 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3109 ok(!russian_charset,
3110 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
3111 break;
3112 case DEFAULT_CHARSET:
3113 ok(ansi_charset > 0,
3114 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3115 ok(symbol_charset > 0,
3116 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3117 ok(russian_charset > 0,
3118 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3119 break;
3122 else
3124 ok(ansi_charset > 0,
3125 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3126 ok(symbol_charset > 0,
3127 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3128 ok(russian_charset > 0,
3129 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3132 memset(&lf, 0, sizeof(lf));
3133 lf.lfCharSet = SYMBOL_CHARSET;
3134 strcpy(lf.lfFaceName, font_name);
3135 efd.total = 0;
3136 SetLastError(0xdeadbeef);
3137 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3138 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3139 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3140 if (*font_name && font_charset == ANSI_CHARSET)
3141 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
3142 else
3144 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
3145 for (i = 0; i < efd.total; i++)
3147 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3148 if (*font_name)
3149 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3150 font_name, efd.lf[i].lfFaceName);
3153 ok(!ansi_charset,
3154 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3155 ok(symbol_charset > 0,
3156 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3157 ok(!russian_charset,
3158 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3161 ReleaseDC(0, hdc);
3163 heap_free( efd.lf );
3164 heap_free( efdw.lf );
3167 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
3169 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
3170 LOGFONTA *target = (LOGFONTA *)lParam;
3171 const DWORD valid_bits = 0x003f01ff;
3172 CHARSETINFO csi;
3173 DWORD fs;
3175 if (type != TRUETYPE_FONTTYPE) return TRUE;
3177 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
3178 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
3179 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
3180 *target = *lf;
3181 return FALSE;
3185 return TRUE;
3188 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3190 struct enum_font_data *efd = (struct enum_font_data *)lParam;
3192 if (type != TRUETYPE_FONTTYPE) return 1;
3194 if (efd->total >= efd->size)
3196 efd->size = max( (efd->total + 1) * 2, 256 );
3197 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
3198 if (!efd->lf) return 0;
3200 efd->lf[efd->total++] = *lf;
3202 return 1;
3205 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3207 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3209 if (type != TRUETYPE_FONTTYPE) return 1;
3211 if (efnd->total >= efnd->size)
3213 efnd->size = max( (efnd->total + 1) * 2, 256 );
3214 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
3215 if (!efnd->elf) return 0;
3217 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3219 return 1;
3222 static INT CALLBACK enum_fullname_data_proc_w( const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam )
3224 struct enum_fullname_data_w *efnd = (struct enum_fullname_data_w *)lParam;
3226 if (type != TRUETYPE_FONTTYPE) return 1;
3228 if (efnd->total >= efnd->size)
3230 efnd->size = max( (efnd->total + 1) * 2, 256 );
3231 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
3232 if (!efnd->elf) return 0;
3234 efnd->elf[efnd->total++] = *(ENUMLOGFONTW *)lf;
3236 return 1;
3239 static void test_EnumFontFamiliesEx_default_charset(void)
3241 struct enum_font_data efd;
3242 LOGFONTA target, enum_font;
3243 UINT acp;
3244 HDC hdc;
3245 CHARSETINFO csi;
3247 acp = GetACP();
3248 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3249 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3250 return;
3253 hdc = GetDC(0);
3254 memset(&enum_font, 0, sizeof(enum_font));
3255 enum_font.lfCharSet = csi.ciCharset;
3256 target.lfFaceName[0] = '\0';
3257 target.lfCharSet = csi.ciCharset;
3258 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3259 if (target.lfFaceName[0] == '\0') {
3260 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3261 return;
3263 if (acp == 874 || acp == 1255 || acp == 1256) {
3264 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3265 target.lfCharSet = ANSI_CHARSET;
3268 memset(&efd, 0, sizeof(efd));
3269 memset(&enum_font, 0, sizeof(enum_font));
3270 strcpy(enum_font.lfFaceName, target.lfFaceName);
3271 enum_font.lfCharSet = DEFAULT_CHARSET;
3272 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3273 ReleaseDC(0, hdc);
3275 if (efd.total < 2)
3276 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3277 else
3278 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3279 "(%s) got charset %d expected %d\n",
3280 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3282 heap_free(efd.lf);
3283 return;
3286 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3288 HFONT hfont, hfont_prev;
3289 DWORD ret;
3290 GLYPHMETRICS gm1, gm2;
3291 LOGFONTA lf2 = *lf;
3292 WORD idx;
3294 /* negative widths are handled just as positive ones */
3295 lf2.lfWidth = -lf->lfWidth;
3297 SetLastError(0xdeadbeef);
3298 hfont = CreateFontIndirectA(lf);
3299 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3300 check_font("original", lf, hfont);
3302 hfont_prev = SelectObject(hdc, hfont);
3304 ret = GetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3305 if (ret == GDI_ERROR || idx == 0xffff)
3307 SelectObject(hdc, hfont_prev);
3308 DeleteObject(hfont);
3309 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3310 return;
3313 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3314 memset(&gm1, 0xab, sizeof(gm1));
3315 SetLastError(0xdeadbeef);
3316 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3317 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3319 SelectObject(hdc, hfont_prev);
3320 DeleteObject(hfont);
3322 SetLastError(0xdeadbeef);
3323 hfont = CreateFontIndirectA(&lf2);
3324 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3325 check_font("negative width", &lf2, hfont);
3327 hfont_prev = SelectObject(hdc, hfont);
3329 memset(&gm2, 0xbb, sizeof(gm2));
3330 SetLastError(0xdeadbeef);
3331 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3332 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3334 SelectObject(hdc, hfont_prev);
3335 DeleteObject(hfont);
3337 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3338 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3339 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3340 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3341 gm1.gmCellIncX == gm2.gmCellIncX &&
3342 gm1.gmCellIncY == gm2.gmCellIncY,
3343 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3344 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3345 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3346 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3347 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3350 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3351 #include "pshpack2.h"
3352 typedef struct
3354 USHORT version;
3355 SHORT xAvgCharWidth;
3356 USHORT usWeightClass;
3357 USHORT usWidthClass;
3358 SHORT fsType;
3359 SHORT ySubscriptXSize;
3360 SHORT ySubscriptYSize;
3361 SHORT ySubscriptXOffset;
3362 SHORT ySubscriptYOffset;
3363 SHORT ySuperscriptXSize;
3364 SHORT ySuperscriptYSize;
3365 SHORT ySuperscriptXOffset;
3366 SHORT ySuperscriptYOffset;
3367 SHORT yStrikeoutSize;
3368 SHORT yStrikeoutPosition;
3369 SHORT sFamilyClass;
3370 PANOSE panose;
3371 ULONG ulUnicodeRange1;
3372 ULONG ulUnicodeRange2;
3373 ULONG ulUnicodeRange3;
3374 ULONG ulUnicodeRange4;
3375 CHAR achVendID[4];
3376 USHORT fsSelection;
3377 USHORT usFirstCharIndex;
3378 USHORT usLastCharIndex;
3379 /* According to the Apple spec, original version didn't have the below fields,
3380 * version numbers were taken from the OpenType spec.
3382 /* version 0 (TrueType 1.5) */
3383 USHORT sTypoAscender;
3384 USHORT sTypoDescender;
3385 USHORT sTypoLineGap;
3386 USHORT usWinAscent;
3387 USHORT usWinDescent;
3388 /* version 1 (TrueType 1.66) */
3389 ULONG ulCodePageRange1;
3390 ULONG ulCodePageRange2;
3391 /* version 2 (OpenType 1.2) */
3392 SHORT sxHeight;
3393 SHORT sCapHeight;
3394 USHORT usDefaultChar;
3395 USHORT usBreakChar;
3396 USHORT usMaxContext;
3397 /* version 4 (OpenType 1.6) */
3398 USHORT usLowerOpticalPointSize;
3399 USHORT usUpperOpticalPointSize;
3400 } TT_OS2_V4;
3401 #include "poppack.h"
3403 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3405 typedef struct
3407 USHORT version;
3408 USHORT num_tables;
3409 } cmap_header;
3411 typedef struct
3413 USHORT plat_id;
3414 USHORT enc_id;
3415 ULONG offset;
3416 } cmap_encoding_record;
3418 typedef struct
3420 USHORT format;
3421 USHORT length;
3422 USHORT language;
3424 BYTE glyph_ids[256];
3425 } cmap_format_0;
3427 typedef struct
3429 USHORT format;
3430 USHORT length;
3431 USHORT language;
3433 USHORT seg_countx2;
3434 USHORT search_range;
3435 USHORT entry_selector;
3436 USHORT range_shift;
3438 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3439 /* Then follows:
3440 USHORT pad;
3441 USHORT start_count[seg_countx2 / 2];
3442 USHORT id_delta[seg_countx2 / 2];
3443 USHORT id_range_offset[seg_countx2 / 2];
3444 USHORT glyph_ids[];
3446 } cmap_format_4;
3448 typedef struct
3450 USHORT end_count;
3451 USHORT start_count;
3452 USHORT id_delta;
3453 USHORT id_range_offset;
3454 } cmap_format_4_seg;
3456 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V4 *os2, WORD family, const char *name)
3458 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3459 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3460 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3461 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3462 os2->panose.bWeight, os2->panose.bProportion);
3465 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3467 int i;
3468 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3470 *first = 256;
3472 for(i = 0; i < 256; i++)
3474 if(cmap->glyph_ids[i] == 0) continue;
3475 *last = i;
3476 if(*first == 256) *first = i;
3478 if(*first == 256) return FALSE;
3479 return TRUE;
3482 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3484 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3485 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3486 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3487 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3488 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3491 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3493 int i;
3494 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3495 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3497 *first = 0x10000;
3499 for(i = 0; i < seg_count; i++)
3501 cmap_format_4_seg seg;
3503 get_seg4(cmap, i, &seg);
3505 if(seg.start_count > 0xfffe) break;
3507 if(*first == 0x10000) *first = seg.start_count;
3509 *last = min(seg.end_count, 0xfffe);
3512 if(*first == 0x10000) return FALSE;
3513 return TRUE;
3516 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3518 USHORT i;
3519 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3521 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3523 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3524 return (BYTE *)header + GET_BE_DWORD(record->offset);
3525 record++;
3527 return NULL;
3530 typedef enum
3532 cmap_none,
3533 cmap_ms_unicode,
3534 cmap_ms_symbol
3535 } cmap_type;
3537 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3539 LONG size, ret;
3540 cmap_header *header;
3541 void *cmap;
3542 BOOL r = FALSE;
3543 WORD format;
3545 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3546 ok(size != GDI_ERROR, "no cmap table found\n");
3547 if(size == GDI_ERROR) return FALSE;
3549 header = HeapAlloc(GetProcessHeap(), 0, size);
3550 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3551 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3552 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3554 cmap = get_cmap(header, 3, 1);
3555 if(cmap)
3556 *cmap_type = cmap_ms_unicode;
3557 else
3559 cmap = get_cmap(header, 3, 0);
3560 if(cmap) *cmap_type = cmap_ms_symbol;
3562 if(!cmap)
3564 *cmap_type = cmap_none;
3565 goto end;
3568 format = GET_BE_WORD(*(WORD *)cmap);
3569 switch(format)
3571 case 0:
3572 r = get_first_last_from_cmap0(cmap, first, last);
3573 break;
3574 case 4:
3575 r = get_first_last_from_cmap4(cmap, first, last, size);
3576 break;
3577 default:
3578 skip("unhandled cmap format %d\n", format);
3579 break;
3582 end:
3583 HeapFree(GetProcessHeap(), 0, header);
3584 return r;
3587 #define TT_PLATFORM_APPLE_UNICODE 0
3588 #define TT_PLATFORM_MACINTOSH 1
3589 #define TT_PLATFORM_MICROSOFT 3
3590 #define TT_APPLE_ID_DEFAULT 0
3591 #define TT_APPLE_ID_ISO_10646 2
3592 #define TT_APPLE_ID_UNICODE_2_0 3
3593 #define TT_MS_ID_SYMBOL_CS 0
3594 #define TT_MS_ID_UNICODE_CS 1
3595 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3596 #define TT_NAME_ID_FONT_FAMILY 1
3597 #define TT_NAME_ID_FONT_SUBFAMILY 2
3598 #define TT_NAME_ID_UNIQUE_ID 3
3599 #define TT_NAME_ID_FULL_NAME 4
3600 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3602 typedef struct sfnt_name
3604 USHORT platform_id;
3605 USHORT encoding_id;
3606 USHORT language_id;
3607 USHORT name_id;
3608 USHORT length;
3609 USHORT offset;
3610 } sfnt_name;
3612 static const LANGID mac_langid_table[] =
3614 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3615 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3616 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3617 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3618 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3619 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3620 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3621 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3622 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3623 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3624 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3625 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3626 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3627 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3628 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3629 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3630 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3631 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3632 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3633 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3634 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3635 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3636 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3637 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3638 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3639 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3640 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3641 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3642 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3643 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3644 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3645 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3646 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3647 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3648 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3649 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3650 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3651 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3652 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3653 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3654 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3655 0, /* TT_MAC_LANGID_YIDDISH */
3656 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3657 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3658 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3659 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3660 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3661 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3662 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3663 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3664 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3665 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3666 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3667 0, /* TT_MAC_LANGID_MOLDAVIAN */
3668 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3669 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3670 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3671 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3672 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3673 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3674 0, /* TT_MAC_LANGID_KURDISH */
3675 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3676 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3677 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3678 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3679 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3680 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3681 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3682 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3683 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3684 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3685 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3686 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3687 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3688 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3689 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3690 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3691 0, /* TT_MAC_LANGID_BURMESE */
3692 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3693 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3694 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3695 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3696 0, /* TT_MAC_LANGID_TAGALOG */
3697 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3698 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3699 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3700 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3701 0, /* TT_MAC_LANGID_GALLA */
3702 0, /* TT_MAC_LANGID_SOMALI */
3703 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3704 0, /* TT_MAC_LANGID_RUANDA */
3705 0, /* TT_MAC_LANGID_RUNDI */
3706 0, /* TT_MAC_LANGID_CHEWA */
3707 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3708 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3709 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3710 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3711 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3712 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3713 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3714 0, /* TT_MAC_LANGID_LATIN */
3715 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3716 0, /* TT_MAC_LANGID_GUARANI */
3717 0, /* TT_MAC_LANGID_AYMARA */
3718 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3719 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3720 0, /* TT_MAC_LANGID_DZONGKHA */
3721 0, /* TT_MAC_LANGID_JAVANESE */
3722 0, /* TT_MAC_LANGID_SUNDANESE */
3723 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3724 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3725 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3726 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3727 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3728 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3729 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3730 0, /* TT_MAC_LANGID_TONGAN */
3731 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3732 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3733 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3736 static inline WORD get_mac_code_page( const sfnt_name *name )
3738 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3739 return 10000 + GET_BE_WORD(name->encoding_id);
3742 static int match_name_table_language( const sfnt_name *name, LANGID lang )
3744 LANGID name_lang;
3745 int res = 0;
3747 switch (GET_BE_WORD(name->platform_id))
3749 case TT_PLATFORM_MICROSOFT:
3750 res += 5; /* prefer the Microsoft name */
3751 switch (GET_BE_WORD(name->encoding_id))
3753 case TT_MS_ID_UNICODE_CS:
3754 case TT_MS_ID_SYMBOL_CS:
3755 name_lang = GET_BE_WORD(name->language_id);
3756 break;
3757 default:
3758 return 0;
3760 break;
3761 case TT_PLATFORM_MACINTOSH:
3762 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3763 if (GET_BE_WORD(name->language_id) >= ARRAY_SIZE(mac_langid_table)) return 0;
3764 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3765 break;
3766 case TT_PLATFORM_APPLE_UNICODE:
3767 res += 2; /* prefer Unicode encodings */
3768 switch (GET_BE_WORD(name->encoding_id))
3770 case TT_APPLE_ID_DEFAULT:
3771 case TT_APPLE_ID_ISO_10646:
3772 case TT_APPLE_ID_UNICODE_2_0:
3773 if (GET_BE_WORD(name->language_id) >= ARRAY_SIZE(mac_langid_table)) return 0;
3774 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3775 break;
3776 default:
3777 return 0;
3779 break;
3780 default:
3781 return 0;
3783 if (name_lang == lang) res += 30;
3784 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3785 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3786 return res;
3789 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3791 struct sfnt_name_header
3793 USHORT format;
3794 USHORT number_of_record;
3795 USHORT storage_offset;
3796 } *header;
3797 sfnt_name *entry;
3798 BOOL r = FALSE;
3799 LONG size, offset, length;
3800 LONG c, ret;
3801 WCHAR *name;
3802 BYTE *data;
3803 USHORT i;
3804 int res, best_lang = 0, best_index = -1;
3806 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3807 ok(size != GDI_ERROR, "no name table found\n");
3808 if(size == GDI_ERROR) return FALSE;
3810 data = HeapAlloc(GetProcessHeap(), 0, size);
3811 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3812 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3814 header = (void *)data;
3815 header->format = GET_BE_WORD(header->format);
3816 header->number_of_record = GET_BE_WORD(header->number_of_record);
3817 header->storage_offset = GET_BE_WORD(header->storage_offset);
3818 if (header->format != 0)
3820 skip("got format %u\n", header->format);
3821 goto out;
3823 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3825 skip("number records out of range: %d\n", header->number_of_record);
3826 goto out;
3828 if (header->storage_offset >= size)
3830 skip("storage_offset %u > size %u\n", header->storage_offset, size);
3831 goto out;
3834 entry = (void *)&header[1];
3835 for (i = 0; i < header->number_of_record; i++)
3837 if (GET_BE_WORD(entry[i].name_id) != name_id) continue;
3838 res = match_name_table_language( &entry[i], language_id);
3839 if (res > best_lang)
3841 best_lang = res;
3842 best_index = i;
3846 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset);
3847 length = GET_BE_WORD(entry[best_index].length);
3848 if (offset + length > size)
3850 skip("entry %d is out of range\n", best_index);
3851 goto out;
3853 if (length >= out_size)
3855 skip("buffer too small for entry %d\n", best_index);
3856 goto out;
3859 name = (WCHAR *)(data + offset);
3860 for (c = 0; c < length / 2; c++)
3861 out_buf[c] = GET_BE_WORD(name[c]);
3862 out_buf[c] = 0;
3864 r = TRUE;
3866 out:
3867 HeapFree(GetProcessHeap(), 0, data);
3868 return r;
3871 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3873 HDC hdc;
3874 HFONT hfont, hfont_old;
3875 TEXTMETRICA tmA;
3876 TT_OS2_V4 tt_os2;
3877 LONG size, ret;
3878 const char *font_name = lf->lfFaceName;
3879 DWORD cmap_first = 0, cmap_last = 0;
3880 UINT ascent, descent, cell_height;
3881 cmap_type cmap_type;
3882 BOOL sys_lang_non_english;
3884 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3885 hdc = GetDC(0);
3887 SetLastError(0xdeadbeef);
3888 hfont = CreateFontIndirectA(lf);
3889 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3891 hfont_old = SelectObject(hdc, hfont);
3893 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3894 if (size == GDI_ERROR)
3896 trace("OS/2 chunk was not found\n");
3897 goto end_of_test;
3899 if (size > sizeof(tt_os2))
3901 trace("got too large OS/2 chunk of size %u\n", size);
3902 size = sizeof(tt_os2);
3905 memset(&tt_os2, 0, sizeof(tt_os2));
3906 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3907 ok(ret >= TT_OS2_V0_SIZE && ret <= size, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE,
3908 size, ret);
3910 SetLastError(0xdeadbeef);
3911 ret = GetTextMetricsA(hdc, &tmA);
3912 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3914 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3916 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3918 else
3920 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3921 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3922 UINT os2_first_char, os2_last_char, default_char, break_char;
3923 USHORT version;
3924 TEXTMETRICW tmW;
3926 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3927 descent = abs((SHORT)GET_BE_WORD(tt_os2.usWinDescent));
3928 cell_height = ascent + descent;
3929 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3930 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3932 /* NEWTEXTMETRIC's scaling method is different from TEXTMETRIC's */
3933 #define SCALE_NTM(value) (MulDiv(ntm->tmHeight, (value), cell_height))
3934 size = MulDiv(32, ntm->ntmCellHeight, ntm->ntmSizeEM);
3935 ok(ntm->tmHeight == size, "%s: ntm->tmHeight %d != %d (%u/%u)\n",
3936 font_name, ntm->tmHeight, size, ntm->ntmCellHeight, ntm->ntmSizeEM);
3937 size = SCALE_NTM(ntm->ntmAvgWidth);
3938 ok(ntm->tmAveCharWidth == size, "%s: ntm->tmAveCharWidth %d != %d (%u/%u,%d)\n",
3939 font_name, ntm->tmAveCharWidth, size, ntm->ntmAvgWidth, cell_height, ntm->tmHeight);
3940 size = SCALE_NTM(ascent);
3941 ok(ntm->tmAscent == size, "%s: ntm->tmAscent %d != %d (%u/%u,%d)\n",
3942 font_name, ntm->tmAscent, size, ascent, cell_height, ntm->tmHeight);
3943 size = ntm->tmHeight - ntm->tmAscent;
3944 ok(ntm->tmDescent == size, "%s: ntm->tmDescent %d != %d (%u/%u,%d)\n",
3945 font_name, ntm->tmDescent, size, descent, cell_height, ntm->tmHeight);
3946 size = SCALE_NTM(cell_height - ntm->ntmSizeEM);
3947 ok(ntm->tmInternalLeading == size, "%s: ntm->tmInternalLeading %d != %d (%u/%u,%d)\n",
3948 font_name, ntm->tmInternalLeading, size, cell_height - ntm->ntmSizeEM, cell_height, ntm->tmHeight);
3949 #undef SCALE_NTM
3951 version = GET_BE_WORD(tt_os2.version);
3953 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3954 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3955 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3956 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3958 if (winetest_debug > 1)
3959 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3960 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3961 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3963 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3965 expect_first_W = 0;
3966 switch(GetACP())
3968 case 1255: /* Hebrew */
3969 expect_last_W = 0xf896;
3970 break;
3971 case 1257: /* Baltic */
3972 expect_last_W = 0xf8fd;
3973 break;
3974 default:
3975 expect_last_W = 0xf0ff;
3977 expect_break_W = 0x20;
3978 expect_default_W = expect_break_W - 1;
3979 expect_first_A = 0x1e;
3980 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3982 else
3984 expect_first_W = cmap_first;
3985 expect_last_W = cmap_last;
3986 if(os2_first_char <= 1)
3987 expect_break_W = os2_first_char + 2;
3988 else if(os2_first_char > 0xff)
3989 expect_break_W = 0x20;
3990 else
3991 expect_break_W = os2_first_char;
3992 expect_default_W = expect_break_W - 1;
3993 expect_first_A = expect_default_W - 1;
3994 expect_last_A = min(expect_last_W, 0xff);
3996 expect_break_A = expect_break_W;
3997 expect_default_A = expect_default_W;
3999 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
4000 todo_wine_if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
4001 ok(tmA.tmFirstChar == expect_first_A ||
4002 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
4003 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
4004 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
4005 ok(tmA.tmLastChar == expect_last_A ||
4006 tmA.tmLastChar == 0xff /* win9x */,
4007 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
4008 else
4009 skip("tmLastChar is DBCS lead byte\n");
4010 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
4011 font_name, tmA.tmBreakChar, expect_break_A);
4012 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
4013 "A: tmDefaultChar for %s got %02x expected %02x\n",
4014 font_name, tmA.tmDefaultChar, expect_default_A);
4017 SetLastError(0xdeadbeef);
4018 ret = GetTextMetricsW(hdc, &tmW);
4019 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
4020 "GetTextMetricsW error %u\n", GetLastError());
4021 if (ret)
4023 /* Wine uses the os2 first char */
4024 todo_wine_if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
4025 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
4026 font_name, tmW.tmFirstChar, expect_first_W);
4028 /* Wine uses the os2 last char */
4029 todo_wine_if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
4030 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
4031 font_name, tmW.tmLastChar, expect_last_W);
4032 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
4033 font_name, tmW.tmBreakChar, expect_break_W);
4034 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
4035 "W: tmDefaultChar for %s got %02x expected %02x\n",
4036 font_name, tmW.tmDefaultChar, expect_default_W);
4038 /* Test the aspect ratio while we have tmW */
4039 ret = GetDeviceCaps(hdc, LOGPIXELSX);
4040 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
4041 tmW.tmDigitizedAspectX, ret);
4042 ret = GetDeviceCaps(hdc, LOGPIXELSY);
4043 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
4044 tmW.tmDigitizedAspectX, ret);
4048 /* test FF_ values */
4049 switch(tt_os2.panose.bFamilyType)
4051 case PAN_ANY:
4052 case PAN_NO_FIT:
4053 case PAN_FAMILY_TEXT_DISPLAY:
4054 case PAN_FAMILY_PICTORIAL:
4055 default:
4056 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
4057 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
4059 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
4060 break;
4062 switch(tt_os2.panose.bSerifStyle)
4064 case PAN_ANY:
4065 case PAN_NO_FIT:
4066 default:
4067 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
4068 break;
4070 case PAN_SERIF_COVE:
4071 case PAN_SERIF_OBTUSE_COVE:
4072 case PAN_SERIF_SQUARE_COVE:
4073 case PAN_SERIF_OBTUSE_SQUARE_COVE:
4074 case PAN_SERIF_SQUARE:
4075 case PAN_SERIF_THIN:
4076 case PAN_SERIF_BONE:
4077 case PAN_SERIF_EXAGGERATED:
4078 case PAN_SERIF_TRIANGLE:
4079 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
4080 break;
4082 case PAN_SERIF_NORMAL_SANS:
4083 case PAN_SERIF_OBTUSE_SANS:
4084 case PAN_SERIF_PERP_SANS:
4085 case PAN_SERIF_FLARED:
4086 case PAN_SERIF_ROUNDED:
4087 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
4088 break;
4090 break;
4092 case PAN_FAMILY_SCRIPT:
4093 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
4094 break;
4096 case PAN_FAMILY_DECORATIVE:
4097 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
4098 break;
4101 test_negative_width(hdc, lf);
4103 end_of_test:
4104 SelectObject(hdc, hfont_old);
4105 DeleteObject(hfont);
4107 ReleaseDC(0, hdc);
4110 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4112 INT *enumed = (INT *)lParam;
4114 if (type == TRUETYPE_FONTTYPE)
4116 (*enumed)++;
4117 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
4119 return 1;
4122 static void test_GetTextMetrics(void)
4124 LOGFONTA lf;
4125 HDC hdc;
4126 INT enumed;
4128 hdc = GetDC(0);
4130 memset(&lf, 0, sizeof(lf));
4131 lf.lfCharSet = DEFAULT_CHARSET;
4132 enumed = 0;
4133 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
4135 ReleaseDC(0, hdc);
4138 static void test_nonexistent_font(void)
4140 static const struct
4142 const char *name;
4143 int charset;
4144 } font_subst[] =
4146 { "Times New Roman Baltic", 186 },
4147 { "Times New Roman CE", 238 },
4148 { "Times New Roman CYR", 204 },
4149 { "Times New Roman Greek", 161 },
4150 { "Times New Roman TUR", 162 }
4152 static const struct
4154 const char *name;
4155 int charset;
4156 } shell_subst[] =
4158 { "MS Shell Dlg", 186 },
4159 { "MS Shell Dlg", 238 },
4160 { "MS Shell Dlg", 204 },
4161 { "MS Shell Dlg", 161 },
4162 { "MS Shell Dlg", 162 }
4164 LOGFONTA lf;
4165 HDC hdc;
4166 HFONT hfont;
4167 CHARSETINFO csi;
4168 INT cs, expected_cs, i, ret;
4169 char buf[LF_FACESIZE];
4171 expected_cs = GetACP();
4172 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
4174 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
4175 return;
4177 expected_cs = csi.ciCharset;
4178 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
4180 hdc = CreateCompatibleDC(0);
4182 for (i = 0; i < ARRAY_SIZE(shell_subst); i++)
4184 ret = is_font_installed(shell_subst[i].name);
4185 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4186 ret = is_truetype_font_installed(shell_subst[i].name);
4187 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4189 memset(&lf, 0, sizeof(lf));
4190 lf.lfHeight = -13;
4191 lf.lfWeight = FW_REGULAR;
4192 strcpy(lf.lfFaceName, shell_subst[i].name);
4193 hfont = CreateFontIndirectA(&lf);
4194 hfont = SelectObject(hdc, hfont);
4195 GetTextFaceA(hdc, sizeof(buf), buf);
4196 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4197 cs = GetTextCharset(hdc);
4198 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name);
4200 DeleteObject(SelectObject(hdc, hfont));
4202 memset(&lf, 0, sizeof(lf));
4203 lf.lfHeight = -13;
4204 lf.lfWeight = FW_DONTCARE;
4205 strcpy(lf.lfFaceName, shell_subst[i].name);
4206 hfont = CreateFontIndirectA(&lf);
4207 hfont = SelectObject(hdc, hfont);
4208 GetTextFaceA(hdc, sizeof(buf), buf);
4209 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4210 cs = GetTextCharset(hdc);
4211 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name);
4212 DeleteObject(SelectObject(hdc, hfont));
4215 if (!is_truetype_font_installed("Arial") ||
4216 !is_truetype_font_installed("Times New Roman"))
4218 DeleteDC(hdc);
4219 skip("Arial or Times New Roman not installed\n");
4220 return;
4223 memset(&lf, 0, sizeof(lf));
4224 lf.lfHeight = 100;
4225 lf.lfWeight = FW_REGULAR;
4226 lf.lfCharSet = ANSI_CHARSET;
4227 lf.lfPitchAndFamily = FF_SWISS;
4228 strcpy(lf.lfFaceName, "Nonexistent font");
4229 hfont = CreateFontIndirectA(&lf);
4230 hfont = SelectObject(hdc, hfont);
4231 GetTextFaceA(hdc, sizeof(buf), buf);
4232 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4233 cs = GetTextCharset(hdc);
4234 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4235 DeleteObject(SelectObject(hdc, hfont));
4237 memset(&lf, 0, sizeof(lf));
4238 lf.lfHeight = -13;
4239 lf.lfWeight = FW_DONTCARE;
4240 strcpy(lf.lfFaceName, "Nonexistent font");
4241 hfont = CreateFontIndirectA(&lf);
4242 hfont = SelectObject(hdc, hfont);
4243 GetTextFaceA(hdc, sizeof(buf), buf);
4244 todo_wine /* Wine uses Arial for all substitutions */
4245 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
4246 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
4247 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4248 "Got %s\n", buf);
4249 cs = GetTextCharset(hdc);
4250 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
4251 DeleteObject(SelectObject(hdc, hfont));
4253 memset(&lf, 0, sizeof(lf));
4254 lf.lfHeight = -13;
4255 lf.lfWeight = FW_REGULAR;
4256 strcpy(lf.lfFaceName, "Nonexistent font");
4257 hfont = CreateFontIndirectA(&lf);
4258 hfont = SelectObject(hdc, hfont);
4259 GetTextFaceA(hdc, sizeof(buf), buf);
4260 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4261 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
4262 cs = GetTextCharset(hdc);
4263 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4264 DeleteObject(SelectObject(hdc, hfont));
4266 memset(&lf, 0, sizeof(lf));
4267 lf.lfHeight = -13;
4268 lf.lfWeight = FW_DONTCARE;
4269 strcpy(lf.lfFaceName, "Times New Roman");
4270 hfont = CreateFontIndirectA(&lf);
4271 hfont = SelectObject(hdc, hfont);
4272 GetTextFaceA(hdc, sizeof(buf), buf);
4273 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
4274 cs = GetTextCharset(hdc);
4275 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4276 DeleteObject(SelectObject(hdc, hfont));
4278 for (i = 0; i < ARRAY_SIZE(font_subst); i++)
4280 ret = is_font_installed(font_subst[i].name);
4281 todo_wine
4282 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4283 "%s should be enumerated\n", font_subst[i].name);
4284 ret = is_truetype_font_installed(font_subst[i].name);
4285 todo_wine
4286 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4287 "%s should be enumerated\n", font_subst[i].name);
4289 memset(&lf, 0, sizeof(lf));
4290 lf.lfHeight = -13;
4291 lf.lfWeight = FW_REGULAR;
4292 strcpy(lf.lfFaceName, font_subst[i].name);
4293 hfont = CreateFontIndirectA(&lf);
4294 hfont = SelectObject(hdc, hfont);
4295 cs = GetTextCharset(hdc);
4296 if (font_subst[i].charset == expected_cs)
4298 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4299 GetTextFaceA(hdc, sizeof(buf), buf);
4300 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
4302 else
4304 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
4305 GetTextFaceA(hdc, sizeof(buf), buf);
4306 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4307 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
4309 DeleteObject(SelectObject(hdc, hfont));
4311 memset(&lf, 0, sizeof(lf));
4312 lf.lfHeight = -13;
4313 lf.lfWeight = FW_DONTCARE;
4314 strcpy(lf.lfFaceName, font_subst[i].name);
4315 hfont = CreateFontIndirectA(&lf);
4316 hfont = SelectObject(hdc, hfont);
4317 GetTextFaceA(hdc, sizeof(buf), buf);
4318 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
4319 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
4320 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
4321 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4322 "got %s for font %s\n", buf, font_subst[i].name);
4323 cs = GetTextCharset(hdc);
4324 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4325 DeleteObject(SelectObject(hdc, hfont));
4328 DeleteDC(hdc);
4331 struct font_realization_info
4333 DWORD size;
4334 DWORD flags;
4335 DWORD cache_num;
4336 DWORD instance_id;
4337 DWORD unk;
4338 WORD face_index;
4339 WORD simulations;
4342 struct file_info
4344 FILETIME time;
4345 LARGE_INTEGER size;
4346 WCHAR path[MAX_PATH];
4349 static void test_RealizationInfo(void)
4351 struct realization_info_t
4353 DWORD flags;
4354 DWORD cache_num;
4355 DWORD instance_id;
4358 struct file_info file_info;
4359 HDC hdc;
4360 DWORD info[4], info2[32], read;
4361 HFONT hfont, hfont_old;
4362 SIZE_T needed;
4363 LOGFONTA lf;
4364 HANDLE h;
4365 BYTE file[16], data[14];
4366 FILETIME time;
4367 LARGE_INTEGER size;
4368 BOOL r;
4370 if(!pGdiRealizationInfo)
4372 win_skip("GdiRealizationInfo not available\n");
4373 return;
4376 hdc = GetDC(0);
4378 memset(info, 0xcc, sizeof(info));
4379 r = pGdiRealizationInfo(hdc, info);
4380 ok(r != 0, "ret 0\n");
4381 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
4382 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4384 if (!is_truetype_font_installed("Tahoma"))
4386 skip("skipping GdiRealizationInfo with truetype font\n");
4387 goto end;
4390 memset(&lf, 0, sizeof(lf));
4391 strcpy(lf.lfFaceName, "Tahoma");
4392 lf.lfHeight = 20;
4393 lf.lfWeight = FW_BOLD;
4394 lf.lfItalic = 1;
4395 hfont = CreateFontIndirectA(&lf);
4396 hfont_old = SelectObject(hdc, hfont);
4398 memset(info, 0xcc, sizeof(info));
4399 r = pGdiRealizationInfo(hdc, info);
4400 ok(r != 0, "ret 0\n");
4401 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
4402 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4404 if (pGetFontRealizationInfo)
4406 struct font_realization_info *fri = (struct font_realization_info*)info2;
4407 struct realization_info_t *ri = (struct realization_info_t*)info;
4409 /* The first DWORD represents a struct size. On a
4410 newly rebooted system setting this to < 16 results
4411 in GetFontRealizationInfo failing. However there
4412 appears to be some caching going on which results
4413 in calls after a successful call also succeeding even
4414 if the size < 16. This means we can't reliably test
4415 this behaviour. */
4417 memset(info2, 0xcc, sizeof(info2));
4418 info2[0] = 16;
4419 r = pGetFontRealizationInfo(hdc, info2);
4420 ok(r != 0, "ret 0\n");
4421 /* We may get the '24' version here if that has been previously
4422 requested. */
4423 ok(fri->size == 16 || fri->size == 24, "got %d\n", info2[0]);
4424 ok(fri->flags == ri->flags, "flags mismatch\n");
4425 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4426 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4427 ok(info2[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2[6]);
4429 memset(info2, 0xcc, sizeof(info2));
4430 info2[0] = 28;
4431 r = pGetFontRealizationInfo(hdc, info2);
4432 ok(r == FALSE, "got %d\n", r);
4434 memset(info2, 0xcc, sizeof(info2));
4435 info2[0] = 24;
4436 r = pGetFontRealizationInfo(hdc, info2);
4437 ok(r != 0, "ret 0\n");
4438 ok(fri->size == 24, "got %d\n", fri->size);
4439 ok(fri->flags == ri->flags, "flags mismatch\n");
4440 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4441 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4442 ok(fri->simulations == 0x2, "got simulations flags 0x%04x\n", fri->simulations);
4443 ok(fri->face_index == 0, "got wrong face index %u\n", fri->face_index);
4444 ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4446 /* Test GetFontFileInfo() */
4447 /* invalid font id */
4448 SetLastError(0xdeadbeef);
4449 r = pGetFontFileInfo(0xabababab, 0, &file_info, sizeof(file_info), &needed);
4450 ok(r == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "ret %d gle %d\n", r, GetLastError());
4452 needed = 0;
4453 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed);
4454 ok(r != 0, "Failed to get font file info, error %d.\n", GetLastError());
4456 if (r)
4458 ok(needed > 0 && needed < sizeof(file_info), "Unexpected required size.\n");
4460 h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
4461 ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError());
4463 GetFileTime(h, NULL, NULL, &time);
4464 ok(!CompareFileTime(&file_info.time, &time), "time mismatch\n");
4465 GetFileSizeEx(h, &size);
4466 ok(file_info.size.QuadPart == size.QuadPart, "size mismatch\n");
4468 /* Read first 16 bytes from the file */
4469 ReadFile(h, file, sizeof(file), &read, NULL);
4470 CloseHandle(h);
4472 /* shorter buffer */
4473 SetLastError(0xdeadbeef);
4474 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, needed - 1, &needed);
4475 ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %d\n", r, GetLastError());
4478 /* Get bytes 2 - 16 using GetFontFileData */
4479 r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data));
4480 ok(r != 0, "ret 0 gle %d\n", GetLastError());
4482 ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n");
4485 DeleteObject(SelectObject(hdc, hfont_old));
4487 end:
4488 ReleaseDC(0, hdc);
4491 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4492 the nul in the count of characters copied when the face name buffer is not
4493 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4494 always includes it. */
4495 static void test_GetTextFace(void)
4497 static const char faceA[] = "Tahoma";
4498 static const WCHAR faceW[] = L"Tahoma";
4499 LOGFONTA fA = {0};
4500 LOGFONTW fW = {0};
4501 char bufA[LF_FACESIZE];
4502 WCHAR bufW[LF_FACESIZE];
4503 HFONT f, g;
4504 HDC dc;
4505 int n;
4507 if(!is_font_installed("Tahoma"))
4509 skip("Tahoma is not installed so skipping this test\n");
4510 return;
4513 /* 'A' case. */
4514 memcpy(fA.lfFaceName, faceA, sizeof faceA);
4515 f = CreateFontIndirectA(&fA);
4516 ok(f != NULL, "CreateFontIndirectA failed\n");
4518 dc = GetDC(NULL);
4519 g = SelectObject(dc, f);
4520 n = GetTextFaceA(dc, sizeof bufA, bufA);
4521 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
4522 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
4524 /* Play with the count arg. */
4525 bufA[0] = 'x';
4526 n = GetTextFaceA(dc, 0, bufA);
4527 ok(n == 0, "GetTextFaceA returned %d\n", n);
4528 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4530 bufA[0] = 'x';
4531 n = GetTextFaceA(dc, 1, bufA);
4532 ok(n == 0, "GetTextFaceA returned %d\n", n);
4533 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4535 bufA[0] = 'x'; bufA[1] = 'y';
4536 n = GetTextFaceA(dc, 2, bufA);
4537 ok(n == 1, "GetTextFaceA returned %d\n", n);
4538 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
4540 n = GetTextFaceA(dc, 0, NULL);
4541 ok(n == sizeof faceA ||
4542 broken(n == 0), /* win98, winMe */
4543 "GetTextFaceA returned %d\n", n);
4545 DeleteObject(SelectObject(dc, g));
4546 ReleaseDC(NULL, dc);
4548 /* 'W' case. */
4549 memcpy(fW.lfFaceName, faceW, sizeof faceW);
4550 SetLastError(0xdeadbeef);
4551 f = CreateFontIndirectW(&fW);
4552 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
4554 win_skip("CreateFontIndirectW is not implemented\n");
4555 return;
4557 ok(f != NULL, "CreateFontIndirectW failed\n");
4559 dc = GetDC(NULL);
4560 g = SelectObject(dc, f);
4561 n = GetTextFaceW(dc, ARRAY_SIZE(bufW), bufW);
4562 ok(n == ARRAY_SIZE(faceW), "GetTextFaceW returned %d\n", n);
4563 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
4565 /* Play with the count arg. */
4566 bufW[0] = 'x';
4567 n = GetTextFaceW(dc, 0, bufW);
4568 ok(n == 0, "GetTextFaceW returned %d\n", n);
4569 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4571 bufW[0] = 'x';
4572 n = GetTextFaceW(dc, 1, bufW);
4573 ok(n == 1, "GetTextFaceW returned %d\n", n);
4574 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4576 bufW[0] = 'x'; bufW[1] = 'y';
4577 n = GetTextFaceW(dc, 2, bufW);
4578 ok(n == 2, "GetTextFaceW returned %d\n", n);
4579 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4581 n = GetTextFaceW(dc, 0, NULL);
4582 ok(n == ARRAY_SIZE(faceW), "GetTextFaceW returned %d\n", n);
4584 DeleteObject(SelectObject(dc, g));
4585 ReleaseDC(NULL, dc);
4588 static void test_orientation(void)
4590 static const char test_str[11] = "Test String";
4591 HDC hdc;
4592 LOGFONTA lf;
4593 HFONT hfont, old_hfont;
4594 SIZE size;
4596 if (!is_truetype_font_installed("Arial"))
4598 skip("Arial is not installed\n");
4599 return;
4602 hdc = CreateCompatibleDC(0);
4603 memset(&lf, 0, sizeof(lf));
4604 lstrcpyA(lf.lfFaceName, "Arial");
4605 lf.lfHeight = 72;
4606 lf.lfOrientation = lf.lfEscapement = 900;
4607 hfont = create_font("orientation", &lf);
4608 old_hfont = SelectObject(hdc, hfont);
4609 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4610 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4611 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4612 SelectObject(hdc, old_hfont);
4613 DeleteObject(hfont);
4614 DeleteDC(hdc);
4617 static void test_oemcharset(void)
4619 HDC hdc;
4620 LOGFONTA lf, clf;
4621 HFONT hfont, old_hfont;
4622 int charset;
4624 hdc = CreateCompatibleDC(0);
4625 ZeroMemory(&lf, sizeof(lf));
4626 lf.lfHeight = 12;
4627 lf.lfCharSet = OEM_CHARSET;
4628 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4629 lstrcpyA(lf.lfFaceName, "Terminal");
4630 hfont = CreateFontIndirectA(&lf);
4631 old_hfont = SelectObject(hdc, hfont);
4632 charset = GetTextCharset(hdc);
4633 todo_wine
4634 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4635 hfont = SelectObject(hdc, old_hfont);
4636 GetObjectA(hfont, sizeof(clf), &clf);
4637 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4638 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4639 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4640 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4641 DeleteObject(hfont);
4642 DeleteDC(hdc);
4645 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4646 const TEXTMETRICA *lpntme,
4647 DWORD FontType, LPARAM lParam)
4649 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4650 CHARSETINFO csi;
4651 LOGFONTA lf = *lpelfe;
4652 HFONT hfont;
4653 DWORD found_subset;
4655 /* skip bitmap, proportional or vertical font */
4656 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4657 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4658 lf.lfFaceName[0] == '@')
4659 return 1;
4661 /* skip linked font */
4662 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4663 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4664 return 1;
4666 /* skip linked font, like SimSun-ExtB */
4667 switch (lpelfe->lfCharSet) {
4668 case SHIFTJIS_CHARSET:
4669 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4670 break;
4671 case GB2312_CHARSET:
4672 case CHINESEBIG5_CHARSET:
4673 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4674 break;
4675 case HANGEUL_CHARSET:
4676 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4677 break;
4678 default:
4679 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4680 break;
4682 if (!found_subset)
4683 return 1;
4685 /* test with an odd height */
4686 lf.lfHeight = -19;
4687 lf.lfWidth = 0;
4688 hfont = CreateFontIndirectA(&lf);
4689 if (hfont)
4691 *(HFONT *)lParam = hfont;
4692 return 0;
4694 return 1;
4697 static void test_GetGlyphOutline(void)
4699 HDC hdc;
4700 GLYPHMETRICS gm, gm2;
4701 LOGFONTA lf;
4702 HFONT hfont, old_hfont;
4703 INT ret, ret2;
4704 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4705 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4706 static const struct
4708 UINT cs;
4709 UINT a;
4710 UINT w;
4711 } c[] =
4713 {ANSI_CHARSET, 0x30, 0x30},
4714 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4715 {HANGEUL_CHARSET, 0x8141, 0xac02},
4716 {GB2312_CHARSET, 0x8141, 0x4e04},
4717 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4719 UINT i;
4721 if (!is_truetype_font_installed("Tahoma"))
4723 skip("Tahoma is not installed\n");
4724 return;
4727 hdc = CreateCompatibleDC(0);
4728 memset(&lf, 0, sizeof(lf));
4729 lf.lfHeight = 72;
4730 lstrcpyA(lf.lfFaceName, "Tahoma");
4731 SetLastError(0xdeadbeef);
4732 hfont = CreateFontIndirectA(&lf);
4733 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4734 old_hfont = SelectObject(hdc, hfont);
4736 memset(&gm, 0, sizeof(gm));
4737 SetLastError(0xdeadbeef);
4738 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4739 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4741 memset(&gm, 0, sizeof(gm));
4742 SetLastError(0xdeadbeef);
4743 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4744 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4745 ok(GetLastError() == 0xdeadbeef ||
4746 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4747 "expected 0xdeadbeef, got %u\n", GetLastError());
4749 memset(&gm, 0, sizeof(gm));
4750 SetLastError(0xdeadbeef);
4751 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4752 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4753 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4755 memset(&gm, 0, sizeof(gm));
4756 SetLastError(0xdeadbeef);
4757 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4758 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4760 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4761 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4764 /* test for needed buffer size request on space char */
4765 memset(&gm, 0, sizeof(gm));
4766 SetLastError(0xdeadbeef);
4767 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4768 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4770 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4771 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX);
4772 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY);
4775 /* requesting buffer size for space char + error */
4776 memset(&gm, 0, sizeof(gm));
4777 SetLastError(0xdeadbeef);
4778 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4779 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4781 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4782 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4783 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX);
4784 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY);
4787 /* test GetGlyphOutline with a buffer too small */
4788 SetLastError(0xdeadbeef);
4789 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat);
4790 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4791 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4793 for (i = 0; i < ARRAY_SIZE(fmt); ++i)
4795 DWORD dummy;
4797 memset(&gm, 0xab, sizeof(gm));
4798 SetLastError(0xdeadbeef);
4799 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4800 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4802 if (fmt[i] == GGO_METRICS)
4803 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4804 else
4805 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4806 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4807 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4810 memset(&gm, 0xab, sizeof(gm));
4811 SetLastError(0xdeadbeef);
4812 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4813 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4815 if (fmt[i] == GGO_METRICS)
4816 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4817 else
4818 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4819 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4820 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4823 memset(&gm, 0xab, sizeof(gm));
4824 SetLastError(0xdeadbeef);
4825 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4826 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4828 if (fmt[i] == GGO_METRICS)
4829 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4830 else
4831 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4832 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4833 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4836 memset(&gm, 0xab, sizeof(gm));
4837 SetLastError(0xdeadbeef);
4838 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4839 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4841 if (fmt[i] == GGO_METRICS) {
4842 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4843 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4844 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4846 else
4848 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4849 memset(&gm2, 0xab, sizeof(gm2));
4850 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4851 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4856 SelectObject(hdc, old_hfont);
4857 DeleteObject(hfont);
4859 for (i = 0; i < ARRAY_SIZE(c); ++i)
4861 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4862 TEXTMETRICA tm;
4864 lf.lfFaceName[0] = '\0';
4865 lf.lfCharSet = c[i].cs;
4866 lf.lfPitchAndFamily = 0;
4867 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4869 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4870 continue;
4873 old_hfont = SelectObject(hdc, hfont);
4875 /* expected to ignore superfluous bytes (single-byte character) */
4876 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4877 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4878 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4880 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4881 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4882 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4884 /* expected to ignore superfluous bytes (double-byte character) */
4885 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4886 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4887 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4888 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4890 /* expected to match wide-char version results */
4891 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4892 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4894 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4896 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4897 continue;
4899 DeleteObject(SelectObject(hdc, hfont));
4900 if (c[i].a <= 0xff)
4902 DeleteObject(SelectObject(hdc, old_hfont));
4903 continue;
4906 ret = GetObjectA(hfont, sizeof lf, &lf);
4907 ok(ret > 0, "GetObject error %u\n", GetLastError());
4909 ret = GetTextMetricsA(hdc, &tm);
4910 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4911 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4912 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4913 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4914 "expected %d, got %d (%s:%d)\n",
4915 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4917 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4918 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4919 ok(gm2.gmCellIncY == -lf.lfHeight,
4920 "expected %d, got %d (%s:%d)\n",
4921 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4923 lf.lfItalic = TRUE;
4924 hfont = CreateFontIndirectA(&lf);
4925 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4926 DeleteObject(SelectObject(hdc, hfont));
4927 ret = GetTextMetricsA(hdc, &tm);
4928 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4929 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4930 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4931 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4932 "expected %d, got %d (%s:%d)\n",
4933 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4935 lf.lfItalic = FALSE;
4936 lf.lfEscapement = lf.lfOrientation = 2700;
4937 hfont = CreateFontIndirectA(&lf);
4938 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4939 DeleteObject(SelectObject(hdc, hfont));
4940 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4941 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4942 ok(gm2.gmCellIncY == -lf.lfHeight,
4943 "expected %d, got %d (%s:%d)\n",
4944 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4946 hfont = SelectObject(hdc, old_hfont);
4947 DeleteObject(hfont);
4950 DeleteDC(hdc);
4953 /* bug #9995: there is a limit to the character width that can be specified */
4954 static void test_GetTextMetrics2(const char *fontname, int font_height)
4956 HFONT of, hf;
4957 HDC hdc;
4958 TEXTMETRICA tm;
4959 BOOL ret;
4960 int ave_width, height, width, ratio;
4962 if (!is_truetype_font_installed( fontname)) {
4963 skip("%s is not installed\n", fontname);
4964 return;
4966 hdc = CreateCompatibleDC(0);
4967 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4968 /* select width = 0 */
4969 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4970 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4971 DEFAULT_QUALITY, VARIABLE_PITCH,
4972 fontname);
4973 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4974 of = SelectObject( hdc, hf);
4975 ret = GetTextMetricsA( hdc, &tm);
4976 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4977 height = tm.tmHeight;
4978 ave_width = tm.tmAveCharWidth;
4979 SelectObject( hdc, of);
4980 DeleteObject( hf);
4982 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4984 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4985 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4986 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4987 ok(hf != 0, "CreateFont failed\n");
4988 of = SelectObject(hdc, hf);
4989 ret = GetTextMetricsA(hdc, &tm);
4990 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4991 SelectObject(hdc, of);
4992 DeleteObject(hf);
4994 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4995 break;
4998 DeleteDC(hdc);
5000 ratio = width / height;
5002 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
5005 static void test_GetCharacterPlacement(void)
5007 GCP_RESULTSA result;
5008 DWORD size, size2;
5009 WCHAR glyphs[20];
5010 int pos[20];
5011 HDC hdc;
5013 hdc = CreateCompatibleDC(0);
5014 ok(!!hdc, "CreateCompatibleDC failed\n");
5016 memset(&result, 0, sizeof(result));
5017 result.lStructSize = sizeof(result);
5018 result.lpCaretPos = pos;
5019 result.lpGlyphs = glyphs;
5020 result.nGlyphs = 20;
5022 pos[0] = -1;
5023 glyphs[0] = '!';
5024 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, &result, 0);
5025 ok(size, "GetCharacterPlacementA failed!\n");
5026 ok(result.nGlyphs == 9, "Unexpected number of glyphs %u\n", result.nGlyphs);
5027 ok(glyphs[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs, 1));
5028 ok(pos[0] == 0, "Unexpected caret position %d\n", pos[0]);
5030 pos[0] = -1;
5031 glyphs[0] = '!';
5032 result.nGlyphs = 20;
5033 size2 = GetCharacterPlacementA(hdc, "Wine Test", 0, 0, &result, 0);
5034 ok(!size2, "Expected GetCharacterPlacementA to fail\n");
5035 ok(result.nGlyphs == 20, "Unexpected number of glyphs %u\n", result.nGlyphs);
5036 ok(glyphs[0] == '!', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs, 1));
5037 ok(pos[0] == -1, "Unexpected caret position %d\n", pos[0]);
5039 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, NULL, 0);
5040 ok(size2, "GetCharacterPlacementA failed!\n");
5041 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
5043 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, NULL, GCP_REORDER);
5044 ok(size2, "GetCharacterPlacementA failed!\n");
5045 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
5047 pos[0] = -1;
5048 glyphs[0] = '!';
5049 result.nGlyphs = 20;
5050 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, &result, GCP_REORDER);
5051 ok(size, "GetCharacterPlacementA failed!\n");
5052 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
5053 ok(result.nGlyphs == 9, "Unexpected number of glyphs %u\n", result.nGlyphs);
5054 ok(glyphs[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs, 1));
5055 todo_wine ok(pos[0] == 0, "Unexpected caret position %d\n", pos[0]);
5057 DeleteDC(hdc);
5060 static void test_CreateFontIndirect(void)
5062 LOGFONTA lf, getobj_lf;
5063 int ret, i;
5064 HFONT hfont;
5065 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
5067 memset(&lf, 0, sizeof(lf));
5068 lf.lfCharSet = ANSI_CHARSET;
5069 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5070 lf.lfHeight = 16;
5071 lf.lfWidth = 16;
5072 lf.lfQuality = DEFAULT_QUALITY;
5073 lf.lfItalic = FALSE;
5074 lf.lfWeight = FW_DONTCARE;
5076 for (i = 0; i < ARRAY_SIZE(TestName); i++)
5078 lstrcpyA(lf.lfFaceName, TestName[i]);
5079 hfont = CreateFontIndirectA(&lf);
5080 ok(hfont != 0, "CreateFontIndirectA failed\n");
5081 SetLastError(0xdeadbeef);
5082 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
5083 ok(ret, "GetObject failed: %d\n", GetLastError());
5084 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
5085 ok(lf.lfWeight == getobj_lf.lfWeight ||
5086 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
5087 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
5088 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
5089 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
5090 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
5091 DeleteObject(hfont);
5095 static void test_CreateFontIndirectEx(void)
5097 ENUMLOGFONTEXDVA lfex;
5098 HFONT hfont;
5100 if (!pCreateFontIndirectExA)
5102 win_skip("CreateFontIndirectExA is not available\n");
5103 return;
5106 if (!is_truetype_font_installed("Arial"))
5108 skip("Arial is not installed\n");
5109 return;
5112 SetLastError(0xdeadbeef);
5113 hfont = pCreateFontIndirectExA(NULL);
5114 ok(hfont == NULL, "got %p\n", hfont);
5115 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
5117 memset(&lfex, 0, sizeof(lfex));
5118 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
5119 hfont = pCreateFontIndirectExA(&lfex);
5120 ok(hfont != 0, "CreateFontIndirectEx failed\n");
5121 if (hfont)
5122 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
5123 DeleteObject(hfont);
5126 static void test_realization_info(const char *name, DWORD size, BOOL is_memory_resource)
5128 struct font_realization_info info;
5129 struct file_info file_info;
5130 HFONT hfont, hfont_prev;
5131 SIZE_T needed;
5132 LOGFONTA lf;
5133 BYTE *data;
5134 BOOL ret;
5135 HDC hdc;
5137 if (!pGetFontRealizationInfo)
5138 return;
5140 memset(&lf, 0, sizeof(lf));
5141 lf.lfHeight = 72;
5142 strcpy(lf.lfFaceName, name);
5144 hfont = CreateFontIndirectA(&lf);
5145 ok(hfont != 0, "Failed to create a font, %u.\n", GetLastError());
5147 hdc = GetDC(NULL);
5149 hfont_prev = SelectObject(hdc, hfont);
5150 ok(hfont_prev != NULL, "Failed to select font.\n");
5152 memset(&info, 0xcc, sizeof(info));
5153 info.size = sizeof(info);
5154 ret = pGetFontRealizationInfo(hdc, (DWORD *)&info);
5155 ok(ret != 0, "Unexpected return value %d.\n", ret);
5157 ok((info.flags & 0xf) == 0x3, "Unexpected flags %#x.\n", info.flags);
5158 ok(info.cache_num != 0, "Unexpected cache num %u.\n", info.cache_num);
5159 ok(info.instance_id != 0, "Unexpected instance id %u.\n", info.instance_id);
5160 ok(info.simulations == 0, "Unexpected simulations %#x.\n", info.simulations);
5161 ok(info.face_index == 0, "Unexpected face index %u.\n", info.face_index);
5163 ret = pGetFontFileInfo(info.instance_id, 0, NULL, 0, NULL);
5164 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n",
5165 ret, GetLastError());
5167 needed = 0;
5168 ret = pGetFontFileInfo(info.instance_id, 0, NULL, 0, &needed);
5169 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n",
5170 ret, GetLastError());
5172 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, 0, NULL);
5173 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n",
5174 ret, GetLastError());
5176 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, needed - 1, NULL);
5177 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %d.\n",
5178 ret, GetLastError());
5180 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, needed, NULL);
5181 ok(ret != 0, "Failed to get font file info, ret %d gle %d.\n", ret, GetLastError());
5183 memset(&file_info, 0xcc, sizeof(file_info));
5184 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, sizeof(file_info), NULL);
5185 ok(ret != 0, "Failed to get font file info, ret %d gle %d.\n", ret, GetLastError());
5186 if (ret)
5188 ok(is_memory_resource ? file_info.size.QuadPart == size : file_info.size.QuadPart > 0, "Unexpected file size.\n");
5189 ok(is_memory_resource ? !file_info.path[0] : file_info.path[0], "Unexpected file path %s.\n",
5190 wine_dbgstr_w(file_info.path));
5193 size = file_info.size.LowPart;
5194 data = HeapAlloc(GetProcessHeap(), 0, size + 16);
5196 memset(data, 0xcc, size);
5197 ret = pGetFontFileData(info.instance_id, 0, 0, data, size);
5198 ok(ret != 0, "Failed to get font file data, %d\n", GetLastError());
5199 ok(*(DWORD *)data == 0x00000100, "Unexpected sfnt header version %#x.\n", *(DWORD *)data);
5200 ok(*(WORD *)(data + 4) == 0x0e00, "Unexpected table count %#x.\n", *(WORD *)(data + 4));
5202 /* Larger than font data size. */
5203 memset(data, 0xcc, size);
5204 ret = pGetFontFileData(info.instance_id, 0, 0, data, size + 16);
5205 ok(ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected return value %d, error %d\n",
5206 ret, GetLastError());
5207 ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD *)data);
5209 /* With offset. */
5210 memset(data, 0xcc, size);
5211 ret = pGetFontFileData(info.instance_id, 0, 16, data, size - 16);
5212 ok(ret != 0, "Failed to get font file data, %d\n", GetLastError());
5213 ok(*(DWORD *)data == 0x1000000, "Unexpected buffer contents %#x.\n", *(DWORD *)data);
5215 memset(data, 0xcc, size);
5216 ret = pGetFontFileData(info.instance_id, 0, 16, data, size);
5217 ok(ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected return value %d, error %d\n",
5218 ret, GetLastError());
5219 ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD *)data);
5221 /* Zero buffer size. */
5222 memset(data, 0xcc, size);
5223 ret = pGetFontFileData(info.instance_id, 0, 16, data, 0);
5224 todo_wine
5225 ok(ret == 0 && GetLastError() == ERROR_NOACCESS, "Unexpected return value %d, error %d\n", ret, GetLastError());
5226 ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD *)data);
5228 HeapFree(GetProcessHeap(), 0, data);
5230 SelectObject(hdc, hfont_prev);
5231 DeleteObject(hfont);
5232 ReleaseDC(NULL, hdc);
5235 static void test_AddFontMemResource(void)
5237 char ttf_name[MAX_PATH];
5238 void *font;
5239 DWORD font_size, num_fonts;
5240 HANDLE ret;
5241 BOOL bRet;
5243 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
5245 win_skip("AddFontMemResourceEx is not available on this platform\n");
5246 return;
5249 SetLastError(0xdeadbeef);
5250 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
5251 ok(!ret, "AddFontMemResourceEx should fail\n");
5252 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5253 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5254 GetLastError());
5256 SetLastError(0xdeadbeef);
5257 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
5258 ok(!ret, "AddFontMemResourceEx should fail\n");
5259 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5260 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5261 GetLastError());
5263 SetLastError(0xdeadbeef);
5264 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
5265 ok(!ret, "AddFontMemResourceEx should fail\n");
5266 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5267 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5268 GetLastError());
5270 SetLastError(0xdeadbeef);
5271 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
5272 ok(!ret, "AddFontMemResourceEx should fail\n");
5273 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5274 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5275 GetLastError());
5277 /* Now with scalable font */
5278 bRet = write_ttf_file("wine_test.ttf", ttf_name);
5279 ok(bRet, "Failed to create test font file.\n");
5281 font = load_font(ttf_name, &font_size);
5282 ok(font != NULL, "Failed to map font file.\n");
5284 bRet = is_truetype_font_installed("wine_test");
5285 ok(!bRet, "Font wine_test should not be enumerated.\n");
5287 num_fonts = 0;
5288 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
5289 ok(ret != 0, "Failed to add resource, %d.\n", GetLastError());
5290 ok(num_fonts == 1, "Unexpected number of fonts %u.\n", num_fonts);
5292 bRet = is_truetype_font_installed("wine_test");
5293 todo_wine
5294 ok(!bRet, "Font wine_test should not be enumerated.\n");
5296 test_realization_info("wine_test", font_size, TRUE);
5298 bRet = pRemoveFontMemResourceEx(ret);
5299 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
5301 free_font(font);
5303 bRet = DeleteFileA(ttf_name);
5304 ok(bRet, "Failed to delete font file, %d.\n", GetLastError());
5306 font = load_font("sserife.fon", &font_size);
5307 if (!font)
5309 skip("Unable to locate and load font sserife.fon\n");
5310 return;
5313 SetLastError(0xdeadbeef);
5314 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
5315 ok(!ret, "AddFontMemResourceEx should fail\n");
5316 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5317 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5318 GetLastError());
5320 SetLastError(0xdeadbeef);
5321 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
5322 ok(!ret, "AddFontMemResourceEx should fail\n");
5323 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5324 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5325 GetLastError());
5327 num_fonts = 0xdeadbeef;
5328 SetLastError(0xdeadbeef);
5329 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
5330 ok(!ret, "AddFontMemResourceEx should fail\n");
5331 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5332 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5333 GetLastError());
5334 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5336 if (0) /* hangs under windows 2000 */
5338 num_fonts = 0xdeadbeef;
5339 SetLastError(0xdeadbeef);
5340 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
5341 ok(!ret, "AddFontMemResourceEx should fail\n");
5342 ok(GetLastError() == 0xdeadbeef,
5343 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5344 GetLastError());
5345 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5348 num_fonts = 0xdeadbeef;
5349 SetLastError(0xdeadbeef);
5350 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
5351 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
5352 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5353 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
5355 free_font(font);
5357 SetLastError(0xdeadbeef);
5358 bRet = pRemoveFontMemResourceEx(ret);
5359 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
5361 /* test invalid pointer to number of loaded fonts */
5362 font = load_font("sserife.fon", &font_size);
5363 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
5365 SetLastError(0xdeadbeef);
5366 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
5367 ok(!ret, "AddFontMemResourceEx should fail\n");
5368 ok(GetLastError() == 0xdeadbeef,
5369 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5370 GetLastError());
5372 SetLastError(0xdeadbeef);
5373 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
5374 ok(!ret, "AddFontMemResourceEx should fail\n");
5375 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5376 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5377 GetLastError());
5379 free_font(font);
5382 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5384 LOGFONTA *lf;
5386 if (type != TRUETYPE_FONTTYPE) return 1;
5388 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5390 lf = (LOGFONTA *)lparam;
5391 *lf = *elf;
5392 return 0;
5395 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5397 int ret;
5398 LOGFONTA *lf;
5400 if (type != TRUETYPE_FONTTYPE) return 1;
5402 lf = (LOGFONTA *)lparam;
5403 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
5404 if(ret == 0)
5406 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5407 *lf = *elf;
5408 return 0;
5410 return 1;
5413 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5415 return lparam;
5418 static void test_EnumFonts(void)
5420 int ret;
5421 LOGFONTA lf;
5422 HDC hdc;
5424 if (!is_truetype_font_installed("Arial"))
5426 skip("Arial is not installed\n");
5427 return;
5430 /* Windows uses localized font face names, so Arial Bold won't be found */
5431 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
5433 skip("User locale is not English, skipping the test\n");
5434 return;
5437 hdc = CreateCompatibleDC(0);
5439 /* check that the enumproc's retval is returned */
5440 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
5441 ok(ret == 0xcafe, "got %08x\n", ret);
5443 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
5444 ok(!ret, "font Arial is not enumerated\n");
5445 ret = strcmp(lf.lfFaceName, "Arial");
5446 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5447 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5449 strcpy(lf.lfFaceName, "Arial");
5450 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5451 ok(!ret, "font Arial is not enumerated\n");
5452 ret = strcmp(lf.lfFaceName, "Arial");
5453 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5454 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5456 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
5457 ok(!ret, "font Arial Bold is not enumerated\n");
5458 ret = strcmp(lf.lfFaceName, "Arial");
5459 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5460 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5462 strcpy(lf.lfFaceName, "Arial Bold");
5463 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5464 ok(ret, "font Arial Bold should not be enumerated\n");
5466 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
5467 ok(!ret, "font Arial Bold Italic is not enumerated\n");
5468 ret = strcmp(lf.lfFaceName, "Arial");
5469 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5470 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5472 strcpy(lf.lfFaceName, "Arial Bold Italic");
5473 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5474 ok(ret, "font Arial Bold Italic should not be enumerated\n");
5476 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
5477 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5479 strcpy(lf.lfFaceName, "Arial Italic Bold");
5480 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5481 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5483 DeleteDC(hdc);
5486 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5488 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5490 if (0) /* Disabled to limit console spam */
5491 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5492 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5494 if (type != TRUETYPE_FONTTYPE) return 1;
5495 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1;
5497 if (efnd->total >= efnd->size)
5499 efnd->size = max( (efnd->total + 1) * 2, 256 );
5500 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5501 if (!efnd->elf) return 0;
5503 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5504 return 0;
5507 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5509 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5511 if (0) /* Disabled to limit console spam */
5512 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5513 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5515 if (type != TRUETYPE_FONTTYPE) return 1;
5516 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1;
5518 if (efnd->total >= efnd->size)
5520 efnd->size = max( (efnd->total + 1) * 2, 256 );
5521 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5522 if (!efnd->elf) return 0;
5524 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5525 return 0;
5528 static void test_EnumFonts_subst(void)
5530 int ret;
5531 LOGFONTA lf;
5532 HDC hdc;
5533 struct enum_fullname_data efnd;
5535 ret = is_font_installed("MS Shell Dlg");
5536 ok(ret, "MS Shell Dlg should be enumerated\n");
5537 ret = is_truetype_font_installed("MS Shell Dlg");
5538 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n");
5540 ret = is_font_installed("MS Shell Dlg 2");
5541 ok(ret, "MS Shell Dlg 2 should be enumerated\n");
5542 ret = is_truetype_font_installed("MS Shell Dlg 2");
5543 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5545 hdc = CreateCompatibleDC(0);
5547 memset(&efnd, 0, sizeof(efnd));
5548 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5549 ok(ret, "MS Shell Dlg should not be enumerated\n");
5550 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n");
5552 memset(&lf, 0, sizeof(lf));
5553 lf.lfCharSet = DEFAULT_CHARSET;
5555 efnd.total = 0;
5556 strcpy(lf.lfFaceName, "MS Shell Dlg");
5557 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5558 ok(!ret, "MS Shell Dlg should be enumerated\n");
5559 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n");
5560 if (efnd.total)
5562 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
5563 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5564 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg");
5565 ok(ret, "did not expect MS Shell Dlg\n");
5568 efnd.total = 0;
5569 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5570 ok(ret, "MS Shell Dlg 2 should not be enumerated\n");
5571 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n");
5573 efnd.total = 0;
5574 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
5575 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5576 ok(!ret, "MS Shell Dlg 2 should be enumerated\n");
5577 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n");
5578 if (efnd.total)
5580 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
5581 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5582 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
5583 ok(ret, "did not expect MS Shell Dlg 2\n");
5586 heap_free(efnd.elf);
5587 DeleteDC(hdc);
5590 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5592 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
5593 const char *fullname = (const char *)lParam;
5595 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
5597 return 1;
5600 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
5602 HDC hdc = GetDC(0);
5603 BOOL ret = FALSE;
5605 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
5606 ret = TRUE;
5608 ReleaseDC(0, hdc);
5609 return ret;
5612 static void test_fullname(void)
5614 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5615 WCHAR bufW[LF_FULLFACESIZE];
5616 char bufA[LF_FULLFACESIZE];
5617 HFONT hfont, of;
5618 LOGFONTA lf;
5619 HDC hdc;
5620 int i;
5621 DWORD ret;
5623 hdc = CreateCompatibleDC(0);
5624 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5626 memset(&lf, 0, sizeof(lf));
5627 lf.lfCharSet = ANSI_CHARSET;
5628 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5629 lf.lfHeight = 16;
5630 lf.lfWidth = 16;
5631 lf.lfQuality = DEFAULT_QUALITY;
5632 lf.lfItalic = FALSE;
5633 lf.lfWeight = FW_DONTCARE;
5635 for (i = 0; i < ARRAY_SIZE(TestName); i++)
5637 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
5639 skip("%s is not installed\n", TestName[i]);
5640 continue;
5643 lstrcpyA(lf.lfFaceName, TestName[i]);
5644 hfont = CreateFontIndirectA(&lf);
5645 ok(hfont != 0, "CreateFontIndirectA failed\n");
5647 of = SelectObject(hdc, hfont);
5648 bufW[0] = 0;
5649 bufA[0] = 0;
5650 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
5651 ok(ret, "face full name could not be read\n");
5652 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
5653 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
5654 SelectObject(hdc, of);
5655 DeleteObject(hfont);
5657 DeleteDC(hdc);
5660 static WCHAR *prepend_at(WCHAR *family)
5662 if (!family)
5663 return NULL;
5665 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
5666 family[0] = '@';
5667 return family;
5670 static void test_fullname2_helper(const char *Family)
5672 char *FamilyName, *FaceName, *StyleName, *otmStr;
5673 struct enum_fullname_data efnd;
5674 WCHAR *bufW;
5675 char *bufA;
5676 HFONT hfont, of;
5677 LOGFONTA lf;
5678 HDC hdc;
5679 int i;
5680 DWORD otm_size, ret, buf_size;
5681 OUTLINETEXTMETRICA *otm;
5682 BOOL want_vertical, get_vertical;
5683 want_vertical = ( Family[0] == '@' );
5685 hdc = CreateCompatibleDC(0);
5686 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5688 memset(&lf, 0, sizeof(lf));
5689 lf.lfCharSet = DEFAULT_CHARSET;
5690 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5691 lf.lfHeight = 16;
5692 lf.lfWidth = 16;
5693 lf.lfQuality = DEFAULT_QUALITY;
5694 lf.lfItalic = FALSE;
5695 lf.lfWeight = FW_DONTCARE;
5696 strcpy(lf.lfFaceName, Family);
5697 memset(&efnd, 0, sizeof(efnd));
5698 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
5699 if (efnd.total == 0)
5700 skip("%s is not installed\n", lf.lfFaceName);
5702 for (i = 0; i < efnd.total; i++)
5704 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
5705 FaceName = (char *)efnd.elf[i].elfFullName;
5706 StyleName = (char *)efnd.elf[i].elfStyle;
5708 get_vertical = ( FamilyName[0] == '@' );
5709 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
5711 lstrcpyA(lf.lfFaceName, FaceName);
5712 hfont = CreateFontIndirectA(&lf);
5713 ok(hfont != 0, "CreateFontIndirectA failed\n");
5715 of = SelectObject(hdc, hfont);
5716 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
5717 ok(buf_size != GDI_ERROR, "no name table found\n");
5718 if (buf_size == GDI_ERROR) continue;
5720 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
5721 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
5723 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5724 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5725 memset(otm, 0, otm_size);
5726 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
5727 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
5728 if (ret == 0) continue;
5730 bufW[0] = 0;
5731 bufA[0] = 0;
5732 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
5733 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5734 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
5735 if (want_vertical) bufW = prepend_at(bufW);
5736 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5737 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
5738 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
5739 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
5741 bufW[0] = 0;
5742 bufA[0] = 0;
5743 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
5744 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5745 ok(ret, "FULL_NAME (face name) could not be read\n");
5746 if (want_vertical) bufW = prepend_at(bufW);
5747 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5748 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
5749 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
5750 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
5752 bufW[0] = 0;
5753 bufA[0] = 0;
5754 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
5755 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5756 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
5757 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5758 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
5759 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
5760 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
5762 bufW[0] = 0;
5763 bufA[0] = 0;
5764 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
5765 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5766 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
5767 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5768 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
5769 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
5771 SelectObject(hdc, of);
5772 DeleteObject(hfont);
5774 HeapFree(GetProcessHeap(), 0, otm);
5775 HeapFree(GetProcessHeap(), 0, bufW);
5776 HeapFree(GetProcessHeap(), 0, bufA);
5778 heap_free(efnd.elf);
5779 DeleteDC(hdc);
5782 static void test_fullname2(void)
5784 test_fullname2_helper("Arial");
5785 test_fullname2_helper("DejaVu Sans");
5786 test_fullname2_helper("Lucida Sans");
5787 test_fullname2_helper("Tahoma");
5788 test_fullname2_helper("Webdings");
5789 test_fullname2_helper("Wingdings");
5790 test_fullname2_helper("SimSun");
5791 test_fullname2_helper("NSimSun");
5792 test_fullname2_helper("MingLiu");
5793 test_fullname2_helper("PMingLiu");
5794 test_fullname2_helper("WenQuanYi Micro Hei");
5795 test_fullname2_helper("MS UI Gothic");
5796 test_fullname2_helper("Ume UI Gothic");
5797 test_fullname2_helper("MS Gothic");
5798 test_fullname2_helper("Ume Gothic");
5799 test_fullname2_helper("MS PGothic");
5800 test_fullname2_helper("Ume P Gothic");
5801 test_fullname2_helper("Gulim");
5802 test_fullname2_helper("Batang");
5803 test_fullname2_helper("UnBatang");
5804 test_fullname2_helper("UnDotum");
5805 test_fullname2_helper("@SimSun");
5806 test_fullname2_helper("@NSimSun");
5807 test_fullname2_helper("@MingLiu");
5808 test_fullname2_helper("@PMingLiu");
5809 test_fullname2_helper("@WenQuanYi Micro Hei");
5810 test_fullname2_helper("@MS UI Gothic");
5811 test_fullname2_helper("@Ume UI Gothic");
5812 test_fullname2_helper("@MS Gothic");
5813 test_fullname2_helper("@Ume Gothic");
5814 test_fullname2_helper("@MS PGothic");
5815 test_fullname2_helper("@Ume P Gothic");
5816 test_fullname2_helper("@Gulim");
5817 test_fullname2_helper("@Batang");
5818 test_fullname2_helper("@UnBatang");
5819 test_fullname2_helper("@UnDotum");
5823 static void test_GetGlyphOutline_empty_contour(void)
5825 HDC hdc;
5826 LOGFONTA lf;
5827 HFONT hfont, hfont_prev;
5828 TTPOLYGONHEADER *header;
5829 GLYPHMETRICS gm;
5830 char buf[1024];
5831 DWORD ret;
5833 memset(&lf, 0, sizeof(lf));
5834 lf.lfHeight = 72;
5835 lstrcpyA(lf.lfFaceName, "wine_test");
5837 hfont = CreateFontIndirectA(&lf);
5838 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5840 hdc = GetDC(NULL);
5842 hfont_prev = SelectObject(hdc, hfont);
5843 ok(hfont_prev != NULL, "SelectObject failed\n");
5845 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5846 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5848 header = (TTPOLYGONHEADER*)buf;
5849 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5850 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5851 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5852 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5853 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5854 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5855 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5856 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5858 SelectObject(hdc, hfont_prev);
5859 DeleteObject(hfont);
5860 ReleaseDC(NULL, hdc);
5863 static void test_GetGlyphOutline_metric_clipping(void)
5865 HDC hdc;
5866 LOGFONTA lf;
5867 HFONT hfont, hfont_prev;
5868 GLYPHMETRICS gm;
5869 TEXTMETRICA tm;
5870 TEXTMETRICW tmW;
5871 DWORD ret;
5873 memset(&lf, 0, sizeof(lf));
5874 lf.lfHeight = 72;
5875 lstrcpyA(lf.lfFaceName, "wine_test");
5877 SetLastError(0xdeadbeef);
5878 hfont = CreateFontIndirectA(&lf);
5879 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5881 hdc = GetDC(NULL);
5883 hfont_prev = SelectObject(hdc, hfont);
5884 ok(hfont_prev != NULL, "SelectObject failed\n");
5886 SetLastError(0xdeadbeef);
5887 ret = GetTextMetricsA(hdc, &tm);
5888 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5890 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5891 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5892 "Glyph top(%d) exceeds ascent(%d)\n",
5893 gm.gmptGlyphOrigin.y, tm.tmAscent);
5894 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5895 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5896 "Glyph bottom(%d) exceeds descent(%d)\n",
5897 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5899 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5900 GetTextMetricsW(hdc, &tmW);
5901 todo_wine
5902 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5904 SelectObject(hdc, hfont_prev);
5905 DeleteObject(hfont);
5906 ReleaseDC(NULL, hdc);
5909 static void test_GetGlyphOutline_character(void)
5911 HFONT hfont, hfont_old;
5912 LOGFONTA lf;
5913 HDC hdc;
5914 DWORD ret;
5915 GLYPHMETRICS gm1, gm2, gmn;
5916 char test_chars[] = { 'A', 'D', '!', '\0' };
5917 char *current_char;
5919 memset(&lf, 0, sizeof(lf));
5920 lf.lfHeight = 72;
5921 lstrcpyA(lf.lfFaceName, "wine_test");
5923 hfont = CreateFontIndirectA(&lf);
5924 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5926 hdc = GetDC(NULL);
5928 hfont_old = SelectObject(hdc, hfont);
5929 ok(hfont_old != NULL, "SelectObject failed\n");
5931 ret = GetGlyphOutlineW(hdc, 'Z', GGO_METRICS, &gmn, 0, NULL, &mat);
5932 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed to default to .notdef for character 'Z'\n");
5934 for (current_char = test_chars; *current_char != '\0'; current_char++)
5936 ret = GetGlyphOutlineW(hdc, *current_char, GGO_METRICS, &gm1, 0, NULL, &mat);
5937 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed for '%c'\n", *current_char);
5938 ok(memcmp(&gm1, &gmn, sizeof(gmn)) != 0, "the test character '%c' matches .notdef\n", *current_char);
5940 ret = GetGlyphOutlineW(hdc, 0x10000 + *current_char, GGO_METRICS, &gm2, 0, NULL, &mat);
5941 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed for 0x10000 + '%c'\n", *current_char);
5942 ok(memcmp(&gm1, &gm2, sizeof(gmn)) == 0, "GetGlyphOutlineW returned wrong metrics for character 0x10000 + '%c'\n", *current_char);
5945 ret = GetGlyphOutlineW(hdc, 0x3, GGO_METRICS|GGO_GLYPH_INDEX, &gm1, 0, NULL, &mat);
5946 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed for glyph index 0x3\n");
5948 ret = GetGlyphOutlineW(hdc, 0xFFFF, GGO_METRICS|GGO_GLYPH_INDEX, &gm2, 0, NULL, &mat);
5949 ok(ret == GDI_ERROR, "GetGlyphOutlineW for nonexistent glyph index 0xFFFF has succeeded\n");
5951 ret = GetGlyphOutlineW(hdc, 0x10003, GGO_METRICS|GGO_GLYPH_INDEX, &gm2, 0, NULL, &mat);
5952 ok(ret != GDI_ERROR, "GetGlyphOutlineW for index 0x10003 has failed\n");
5953 ok(memcmp(&gm1, &gm2, sizeof(gmn)) == 0, "GetGlyphOutlineW returned wrong metrics for glyph 0x10003\n");
5955 SelectObject(hdc, hfont_old);
5956 DeleteObject(hfont);
5957 ReleaseDC(NULL, hdc);
5960 static void test_fstype_fixup(void)
5962 HDC hdc;
5963 LOGFONTA lf;
5964 HFONT hfont, hfont_prev;
5965 DWORD ret;
5966 OUTLINETEXTMETRICA *otm;
5967 DWORD otm_size;
5969 memset(&lf, 0, sizeof(lf));
5970 lf.lfHeight = 72;
5971 lstrcpyA(lf.lfFaceName, "wine_test");
5973 SetLastError(0xdeadbeef);
5974 hfont = CreateFontIndirectA(&lf);
5975 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5977 hdc = GetDC(NULL);
5979 hfont_prev = SelectObject(hdc, hfont);
5980 ok(hfont_prev != NULL, "SelectObject failed\n");
5982 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5983 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5984 otm->otmSize = sizeof(*otm);
5985 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
5986 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
5988 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5989 valid bits are 1, 2, 3, 8, 9. */
5990 ok((otm->otmfsType & ~0x30e) == 0, "fsType %#x\n", otm->otmfsType);
5992 HeapFree(GetProcessHeap(), 0, otm);
5994 SelectObject(hdc, hfont_prev);
5995 DeleteObject(hfont);
5996 ReleaseDC(NULL, hdc);
5999 static void test_CreateScalableFontResource(void)
6001 char ttf_name[MAX_PATH];
6002 char tmp_path[MAX_PATH];
6003 char fot_name[MAX_PATH];
6004 char *file_part;
6005 DWORD ret;
6006 int i;
6008 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
6010 win_skip("AddFontResourceExA is not available on this platform\n");
6011 return;
6014 if (!write_ttf_file("wine_test.ttf", ttf_name))
6016 skip("Failed to create ttf file for testing\n");
6017 return;
6020 trace("created %s\n", ttf_name);
6022 ret = is_truetype_font_installed("wine_test");
6023 ok(!ret, "font wine_test should not be enumerated\n");
6025 ret = GetTempPathA(MAX_PATH, tmp_path);
6026 ok(ret, "GetTempPath() error %d\n", GetLastError());
6027 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
6028 ok(ret, "GetTempFileName() error %d\n", GetLastError());
6030 ret = GetFileAttributesA(fot_name);
6031 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
6033 SetLastError(0xdeadbeef);
6034 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
6035 ok(!ret, "CreateScalableFontResource() should fail\n");
6036 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
6038 SetLastError(0xdeadbeef);
6039 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
6040 ok(!ret, "CreateScalableFontResource() should fail\n");
6041 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
6043 file_part = strrchr(ttf_name, '\\');
6044 SetLastError(0xdeadbeef);
6045 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
6046 ok(!ret, "CreateScalableFontResource() should fail\n");
6047 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
6049 SetLastError(0xdeadbeef);
6050 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
6051 ok(!ret, "CreateScalableFontResource() should fail\n");
6052 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
6054 SetLastError(0xdeadbeef);
6055 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
6056 ok(!ret, "CreateScalableFontResource() should fail\n");
6057 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
6059 ret = DeleteFileA(fot_name);
6060 ok(ret, "DeleteFile() error %d\n", GetLastError());
6062 ret = pRemoveFontResourceExA(fot_name, 0, 0);
6063 ok(!ret, "RemoveFontResourceEx() should fail\n");
6065 /* test public font resource */
6066 SetLastError(0xdeadbeef);
6067 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
6068 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
6070 ret = is_truetype_font_installed("wine_test");
6071 ok(!ret, "font wine_test should not be enumerated\n");
6073 SetLastError(0xdeadbeef);
6074 ret = pAddFontResourceExA(fot_name, 0, 0);
6075 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
6077 ret = is_truetype_font_installed("wine_test");
6078 ok(ret, "font wine_test should be enumerated\n");
6080 test_GetGlyphOutline_empty_contour();
6081 test_GetGlyphOutline_metric_clipping();
6082 test_GetGlyphOutline_character();
6083 test_fstype_fixup();
6085 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
6086 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
6088 SetLastError(0xdeadbeef);
6089 ret = pRemoveFontResourceExA(fot_name, 0, 0);
6090 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
6092 ret = is_truetype_font_installed("wine_test");
6093 ok(!ret, "font wine_test should not be enumerated\n");
6095 ret = pRemoveFontResourceExA(fot_name, 0, 0);
6096 ok(!ret, "RemoveFontResourceEx() should fail\n");
6098 /* test refcounting */
6099 for (i = 0; i < 5; i++)
6101 SetLastError(0xdeadbeef);
6102 ret = pAddFontResourceExA(fot_name, 0, 0);
6103 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
6105 for (i = 0; i < 5; i++)
6107 SetLastError(0xdeadbeef);
6108 ret = pRemoveFontResourceExA(fot_name, 0, 0);
6109 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
6111 ret = pRemoveFontResourceExA(fot_name, 0, 0);
6112 ok(!ret, "RemoveFontResourceEx() should fail\n");
6114 DeleteFileA(fot_name);
6116 /* test hidden font resource */
6117 SetLastError(0xdeadbeef);
6118 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
6119 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
6121 ret = is_truetype_font_installed("wine_test");
6122 ok(!ret, "font wine_test should not be enumerated\n");
6124 SetLastError(0xdeadbeef);
6125 ret = pAddFontResourceExA(fot_name, 0, 0);
6126 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
6128 ret = is_truetype_font_installed("wine_test");
6129 todo_wine
6130 ok(!ret, "font wine_test should not be enumerated\n");
6132 /* XP allows removing a private font added with 0 flags */
6133 SetLastError(0xdeadbeef);
6134 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
6135 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
6137 ret = is_truetype_font_installed("wine_test");
6138 ok(!ret, "font wine_test should not be enumerated\n");
6140 ret = pRemoveFontResourceExA(fot_name, 0, 0);
6141 ok(!ret, "RemoveFontResourceEx() should fail\n");
6143 DeleteFileA(fot_name);
6144 DeleteFileA(ttf_name);
6147 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
6149 LOGFONTA lf;
6150 HFONT hfont, hfont_prev;
6151 HDC hdc;
6152 char facename[100];
6153 DWORD ret;
6154 static const WCHAR str[] = { 0x2025 };
6156 *installed = is_truetype_font_installed(name);
6158 lf.lfHeight = -18;
6159 lf.lfWidth = 0;
6160 lf.lfEscapement = 0;
6161 lf.lfOrientation = 0;
6162 lf.lfWeight = FW_DONTCARE;
6163 lf.lfItalic = 0;
6164 lf.lfUnderline = 0;
6165 lf.lfStrikeOut = 0;
6166 lf.lfCharSet = DEFAULT_CHARSET;
6167 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
6168 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6169 lf.lfQuality = DEFAULT_QUALITY;
6170 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6171 strcpy(lf.lfFaceName, name);
6173 hfont = CreateFontIndirectA(&lf);
6174 ok(hfont != NULL, "CreateFontIndirectA failed\n");
6176 hdc = GetDC(NULL);
6178 hfont_prev = SelectObject(hdc, hfont);
6179 ok(hfont_prev != NULL, "SelectObject failed\n");
6181 ret = GetTextFaceA(hdc, sizeof facename, facename);
6182 ok(ret, "GetTextFaceA failed\n");
6183 *selected = !strcmp(facename, name);
6185 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
6186 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
6187 if (!*selected)
6188 memset(gm, 0, sizeof *gm);
6190 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
6191 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
6193 SelectObject(hdc, hfont_prev);
6194 DeleteObject(hfont);
6195 ReleaseDC(NULL, hdc);
6198 static void check_vertical_metrics(const char *face)
6200 LOGFONTA lf;
6201 HFONT hfont, hfont_prev;
6202 HDC hdc;
6203 DWORD ret;
6204 GLYPHMETRICS rgm, vgm;
6205 const UINT code = 0x5EAD, height = 1000;
6206 WORD idx;
6207 ABC abc, vabc;
6208 OUTLINETEXTMETRICA otm;
6209 USHORT numOfLongVerMetrics;
6211 hdc = GetDC(NULL);
6213 memset(&lf, 0, sizeof(lf));
6214 strcpy(lf.lfFaceName, face);
6215 lf.lfHeight = -height;
6216 lf.lfCharSet = DEFAULT_CHARSET;
6217 lf.lfEscapement = lf.lfOrientation = 900;
6218 hfont = CreateFontIndirectA(&lf);
6219 hfont_prev = SelectObject(hdc, hfont);
6220 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
6221 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
6222 ret = GetCharABCWidthsW(hdc, code, code, &abc);
6223 ok(ret, "GetCharABCWidthsW failed\n");
6224 DeleteObject(SelectObject(hdc, hfont_prev));
6226 memset(&lf, 0, sizeof(lf));
6227 strcpy(lf.lfFaceName, "@");
6228 strcat(lf.lfFaceName, face);
6229 lf.lfHeight = -height;
6230 lf.lfCharSet = DEFAULT_CHARSET;
6231 hfont = CreateFontIndirectA(&lf);
6232 hfont_prev = SelectObject(hdc, hfont);
6233 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
6234 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
6235 ret = GetCharABCWidthsW(hdc, code, code, &vabc);
6236 ok(ret, "GetCharABCWidthsW failed\n");
6237 ok(vabc.abcA == vgm.gmptGlyphOrigin.x, "expected %d, got %d\n",
6238 vabc.abcA, vgm.gmptGlyphOrigin.x);
6239 ok(vabc.abcB == vgm.gmBlackBoxX, "expected %d, got %d\n",
6240 vabc.abcB, vgm.gmBlackBoxX);
6241 ok(vabc.abcA + vabc.abcB + vabc.abcC == vgm.gmCellIncX,
6242 "expected %d, got %d\n",
6243 vabc.abcA + vabc.abcB + vabc.abcC, vgm.gmCellIncX);
6245 memset(&otm, 0, sizeof(otm));
6246 otm.otmSize = sizeof(otm);
6247 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
6248 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
6250 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
6251 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
6252 int offset;
6253 SHORT topSideBearing;
6255 if (!pGetGlyphIndicesW) {
6256 win_skip("GetGlyphIndices is not available on this platform\n");
6258 else {
6259 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
6260 ok(ret != 0, "GetGlyphIndicesW failed\n");
6261 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
6262 if (numOfLongVerMetrics > idx)
6263 offset = idx * 2 + 1;
6264 else
6265 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
6266 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
6267 &topSideBearing, sizeof(SHORT));
6268 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
6269 topSideBearing = GET_BE_WORD(topSideBearing);
6270 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
6271 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
6272 "expected %d, got %d\n",
6273 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
6276 else
6278 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
6279 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
6280 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
6283 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
6284 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
6285 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6286 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
6288 DeleteObject(SelectObject(hdc, hfont_prev));
6289 ReleaseDC(NULL, hdc);
6292 static void test_vertical_font(void)
6294 char ttf_name[MAX_PATH];
6295 int num, i;
6296 BOOL ret, installed, selected;
6297 GLYPHMETRICS gm;
6298 WORD hgi, vgi;
6299 const char* face_list[] = {
6300 "@WineTestVertical", /* has vmtx table */
6301 "@Ume Gothic", /* doesn't have vmtx table */
6302 "@MS UI Gothic", /* has vmtx table, available on native */
6305 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
6307 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
6308 return;
6311 if (!write_ttf_file("vertical.ttf", ttf_name))
6313 skip("Failed to create ttf file for testing\n");
6314 return;
6317 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
6318 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6320 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
6321 ok(installed, "WineTestVertical is not installed\n");
6322 ok(selected, "WineTestVertical is not selected\n");
6323 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6324 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6325 gm.gmBlackBoxX, gm.gmBlackBoxY);
6327 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
6328 ok(installed, "@WineTestVertical is not installed\n");
6329 ok(selected, "@WineTestVertical is not selected\n");
6330 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6331 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6332 gm.gmBlackBoxX, gm.gmBlackBoxY);
6334 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
6336 for (i = 0; i < ARRAY_SIZE(face_list); i++) {
6337 const char* face = face_list[i];
6338 if (!is_truetype_font_installed(face)) {
6339 skip("%s is not installed\n", face);
6340 continue;
6342 check_vertical_metrics(&face[1]);
6345 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
6346 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
6348 DeleteFileA(ttf_name);
6351 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
6352 DWORD type, LPARAM lParam)
6354 if (lf->lfFaceName[0] == '@') {
6355 return 0;
6357 return 1;
6360 static void test_east_asian_font_selection(void)
6362 HDC hdc;
6363 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
6364 GB2312_CHARSET, CHINESEBIG5_CHARSET };
6365 size_t i;
6367 hdc = GetDC(NULL);
6369 for (i = 0; i < ARRAY_SIZE(charset); i++)
6371 LOGFONTA lf;
6372 HFONT hfont;
6373 char face_name[LF_FACESIZE];
6374 int ret;
6376 memset(&lf, 0, sizeof lf);
6377 lf.lfFaceName[0] = '\0';
6378 lf.lfCharSet = charset[i];
6380 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
6382 skip("Vertical font for charset %u is not installed\n", charset[i]);
6383 continue;
6386 hfont = CreateFontIndirectA(&lf);
6387 hfont = SelectObject(hdc, hfont);
6388 memset(face_name, 0, sizeof face_name);
6389 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6390 ok(ret && face_name[0] != '@',
6391 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
6392 DeleteObject(SelectObject(hdc, hfont));
6394 memset(&lf, 0, sizeof lf);
6395 strcpy(lf.lfFaceName, "@");
6396 lf.lfCharSet = charset[i];
6397 hfont = CreateFontIndirectA(&lf);
6398 hfont = SelectObject(hdc, hfont);
6399 memset(face_name, 0, sizeof face_name);
6400 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6401 ok(ret && face_name[0] == '@',
6402 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
6403 DeleteObject(SelectObject(hdc, hfont));
6405 ReleaseDC(NULL, hdc);
6408 static int get_font_dpi(const LOGFONTA *lf, int *height)
6410 HDC hdc = CreateCompatibleDC(0);
6411 HFONT hfont;
6412 TEXTMETRICA tm;
6413 int ret;
6415 hfont = CreateFontIndirectA(lf);
6416 ok(hfont != 0, "CreateFontIndirect failed\n");
6418 SelectObject(hdc, hfont);
6419 ret = GetTextMetricsA(hdc, &tm);
6420 ok(ret, "GetTextMetrics failed\n");
6421 ret = tm.tmDigitizedAspectX;
6422 if (height) *height = tm.tmHeight;
6424 DeleteDC(hdc);
6425 DeleteObject(hfont);
6427 return ret;
6430 static void test_stock_fonts(void)
6432 static const int font[] =
6434 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
6435 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6437 static const struct test_data
6439 int charset, weight, height, height_pixels, dpi;
6440 const char face_name[LF_FACESIZE];
6441 WORD lang_id;
6442 } td[][17] =
6444 { /* ANSI_FIXED_FONT */
6445 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
6446 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_HEBREW},
6447 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
6448 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
6449 { 0 }
6451 { /* ANSI_VAR_FONT */
6452 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
6453 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
6454 { 0 }
6456 { /* SYSTEM_FONT */
6457 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6458 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6459 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6460 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6461 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6462 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6463 { 0 }
6465 { /* DEVICE_DEFAULT_FONT */
6466 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6467 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6468 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6469 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6470 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6471 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6472 { 0 }
6474 { /* DEFAULT_GUI_FONT */
6475 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6476 { SHIFTJIS_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6477 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
6478 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
6479 { HANGEUL_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6480 { HANGEUL_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6481 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
6482 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
6483 { GB2312_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6484 { GB2312_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6485 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
6486 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
6487 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
6488 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
6489 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6490 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6491 { 0 }
6494 int i, j;
6496 for (i = 0; i < ARRAY_SIZE(font); i++)
6498 HFONT hfont;
6499 LOGFONTA lf;
6500 int ret, height;
6502 hfont = GetStockObject(font[i]);
6503 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
6505 ret = GetObjectA(hfont, sizeof(lf), &lf);
6506 if (ret != sizeof(lf))
6508 /* NT4 */
6509 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
6510 continue;
6513 for (j = 0; td[i][j].face_name[0] != 0; j++)
6515 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) ||
6516 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) ||
6517 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name)))
6519 continue;
6522 ret = get_font_dpi(&lf, &height);
6523 if (ret != td[i][j].dpi)
6525 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6526 i, j, lf.lfFaceName, ret, td[i][j].dpi);
6527 continue;
6530 /* FIXME: Remove once Wine is fixed */
6531 todo_wine_if (td[i][j].dpi != 96 &&
6532 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6533 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
6534 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6535 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
6536 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6538 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
6539 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
6540 if (td[i][j].face_name[0] == '?')
6542 /* Wine doesn't have this font, skip this case for now.
6543 Actually, the face name is localized on Windows and varies
6544 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6545 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
6547 else
6549 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);
6551 break;
6556 static void test_max_height(void)
6558 HDC hdc;
6559 LOGFONTA lf;
6560 HFONT hfont, hfont_old;
6561 TEXTMETRICA tm1, tm;
6562 BOOL r;
6563 LONG invalid_height[] = { -65536, -123456, 123456 };
6564 size_t i;
6566 memset(&tm1, 0, sizeof(tm1));
6567 memset(&lf, 0, sizeof(lf));
6568 strcpy(lf.lfFaceName, "Tahoma");
6569 lf.lfHeight = -1;
6571 hdc = GetDC(NULL);
6573 /* get 1 ppem value */
6574 hfont = CreateFontIndirectA(&lf);
6575 hfont_old = SelectObject(hdc, hfont);
6576 r = GetTextMetricsA(hdc, &tm1);
6577 ok(r, "GetTextMetrics failed\n");
6578 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6579 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6580 DeleteObject(SelectObject(hdc, hfont_old));
6582 /* test the largest value */
6583 lf.lfHeight = -((1 << 16) - 1);
6584 hfont = CreateFontIndirectA(&lf);
6585 hfont_old = SelectObject(hdc, hfont);
6586 memset(&tm, 0, sizeof(tm));
6587 r = GetTextMetricsA(hdc, &tm);
6588 ok(r, "GetTextMetrics failed\n");
6589 ok(tm.tmHeight > tm1.tmHeight,
6590 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6591 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
6592 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6593 DeleteObject(SelectObject(hdc, hfont_old));
6595 /* test an invalid value */
6596 for (i = 0; i < ARRAY_SIZE(invalid_height); i++) {
6597 lf.lfHeight = invalid_height[i];
6598 hfont = CreateFontIndirectA(&lf);
6599 hfont_old = SelectObject(hdc, hfont);
6600 memset(&tm, 0, sizeof(tm));
6601 r = GetTextMetricsA(hdc, &tm);
6602 ok(r, "GetTextMetrics failed\n");
6603 ok(tm.tmHeight == tm1.tmHeight,
6604 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6605 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
6606 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6607 DeleteObject(SelectObject(hdc, hfont_old));
6610 ReleaseDC(NULL, hdc);
6611 return;
6614 static void test_vertical_order(void)
6616 struct enum_font_data efd;
6617 LOGFONTA lf;
6618 HDC hdc;
6619 int i, j;
6621 hdc = CreateCompatibleDC(0);
6622 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6624 memset(&lf, 0, sizeof(lf));
6625 lf.lfCharSet = DEFAULT_CHARSET;
6626 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6627 lf.lfHeight = 16;
6628 lf.lfWidth = 16;
6629 lf.lfQuality = DEFAULT_QUALITY;
6630 lf.lfItalic = FALSE;
6631 lf.lfWeight = FW_DONTCARE;
6632 memset( &efd, 0, sizeof(efd) );
6633 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
6634 for (i = 0; i < efd.total; i++)
6636 if (efd.lf[i].lfFaceName[0] != '@') continue;
6637 for (j = 0; j < efd.total; j++)
6639 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
6641 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
6642 break;
6646 heap_free( efd.lf );
6647 DeleteDC( hdc );
6650 static void test_GetCharWidth32(void)
6652 BOOL ret;
6653 HDC hdc;
6654 LOGFONTA lf;
6655 HFONT hfont;
6656 INT bufferA;
6657 INT bufferW;
6658 HWND hwnd;
6660 if (!pGetCharWidth32W)
6662 win_skip("GetCharWidth32W not available on this platform\n");
6663 return;
6666 memset(&lf, 0, sizeof(lf));
6667 strcpy(lf.lfFaceName, "System");
6668 lf.lfHeight = 20;
6670 hfont = CreateFontIndirectA(&lf);
6671 hdc = GetDC(0);
6672 hfont = SelectObject(hdc, hfont);
6674 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6675 ok(ret, "GetCharWidth32W should have succeeded\n");
6676 ret = GetCharWidth32A(hdc, 'a', 'a', &bufferA);
6677 ok(ret, "GetCharWidth32A should have succeeded\n");
6678 ok (bufferA == bufferW, "Widths should be the same\n");
6679 ok (bufferA > 0," Width should be greater than zero\n");
6681 hfont = SelectObject(hdc, hfont);
6682 DeleteObject(hfont);
6683 ReleaseDC(NULL, hdc);
6685 memset(&lf, 0, sizeof(lf));
6686 strcpy(lf.lfFaceName, "Tahoma");
6687 lf.lfHeight = 20;
6689 hfont = CreateFontIndirectA(&lf);
6690 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
6691 0, 0, 0, NULL);
6692 hdc = GetDC(hwnd);
6693 SetMapMode( hdc, MM_ANISOTROPIC );
6694 SelectObject(hdc, hfont);
6696 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6697 ok(ret, "GetCharWidth32W should have succeeded\n");
6698 ok (bufferW > 0," Width should be greater than zero\n");
6699 SetWindowExtEx(hdc, -1,-1,NULL);
6700 SetGraphicsMode(hdc, GM_COMPATIBLE);
6701 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6702 ok(ret, "GetCharWidth32W should have succeeded\n");
6703 ok (bufferW > 0," Width should be greater than zero\n");
6704 SetGraphicsMode(hdc, GM_ADVANCED);
6705 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6706 ok(ret, "GetCharWidth32W should have succeeded\n");
6707 ok (bufferW > 0," Width should be greater than zero\n");
6708 SetWindowExtEx(hdc, 1,1,NULL);
6709 SetGraphicsMode(hdc, GM_COMPATIBLE);
6710 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6711 ok(ret, "GetCharWidth32W should have succeeded\n");
6712 ok (bufferW > 0," Width should be greater than zero\n");
6713 SetGraphicsMode(hdc, GM_ADVANCED);
6714 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6715 ok(ret, "GetCharWidth32W should have succeeded\n");
6716 ok (bufferW > 0," Width should be greater than zero\n");
6718 ReleaseDC(hwnd, hdc);
6719 DestroyWindow(hwnd);
6721 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
6722 0, 0, 0, NULL);
6723 hdc = GetDC(hwnd);
6724 SetMapMode( hdc, MM_ANISOTROPIC );
6725 SelectObject(hdc, hfont);
6727 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6728 ok(ret, "GetCharWidth32W should have succeeded\n");
6729 ok (bufferW > 0," Width should be greater than zero\n");
6730 SetWindowExtEx(hdc, -1,-1,NULL);
6731 SetGraphicsMode(hdc, GM_COMPATIBLE);
6732 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6733 ok(ret, "GetCharWidth32W should have succeeded\n");
6734 ok (bufferW > 0," Width should be greater than zero\n");
6735 SetGraphicsMode(hdc, GM_ADVANCED);
6736 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6737 ok(ret, "GetCharWidth32W should have succeeded\n");
6738 ok (bufferW > 0," Width should be greater than zero\n");
6739 SetWindowExtEx(hdc, 1,1,NULL);
6740 SetGraphicsMode(hdc, GM_COMPATIBLE);
6741 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6742 ok(ret, "GetCharWidth32W should have succeeded\n");
6743 ok (bufferW > 0," Width should be greater than zero\n");
6744 SetGraphicsMode(hdc, GM_ADVANCED);
6745 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6746 ok(ret, "GetCharWidth32W should have succeeded\n");
6747 ok (bufferW > 0," Width should be greater than zero\n");
6749 ReleaseDC(hwnd, hdc);
6750 DestroyWindow(hwnd);
6751 DeleteObject(hfont);
6754 static void test_fake_bold_font(void)
6756 static const MAT2 x2_mat = { {0,2}, {0,0}, {0,0}, {0,2} };
6757 HDC hdc;
6758 LOGFONTA lf;
6759 BOOL ret;
6760 struct glyph_data {
6761 TEXTMETRICA tm;
6762 ABC abc;
6763 INT w;
6764 GLYPHMETRICS gm;
6765 } data[4];
6766 int i;
6767 DWORD r;
6769 /* Test outline font */
6770 memset(&lf, 0, sizeof(lf));
6771 strcpy(lf.lfFaceName, "Wingdings");
6772 lf.lfCharSet = SYMBOL_CHARSET;
6774 hdc = GetDC(NULL);
6776 for (i = 0; i <= 1; i++)
6778 HFONT hfont, hfont_old;
6780 lf.lfWeight = i ? FW_BOLD : FW_NORMAL;
6781 hfont = CreateFontIndirectA(&lf);
6782 hfont_old = SelectObject(hdc, hfont);
6784 ret = GetTextMetricsA(hdc, &data[i].tm);
6785 ok(ret, "got %d\n", ret);
6786 ret = GetCharABCWidthsA(hdc, 0x76, 0x76, &data[i].abc);
6787 ok(ret, "got %d\n", ret);
6788 data[i].w = data[i].abc.abcA + data[i].abc.abcB + data[i].abc.abcC;
6789 r = GetGlyphOutlineA(hdc, 0x76, GGO_METRICS, &data[i].gm, 0, NULL, &x2_mat);
6790 ok(r != GDI_ERROR, "got %d\n", ret);
6792 SelectObject(hdc, hfont_old);
6793 DeleteObject(hfont);
6795 ReleaseDC(NULL, hdc);
6797 /* compare results (outline) */
6798 ok(data[0].tm.tmHeight == data[1].tm.tmHeight,
6799 "expected %d, got %d\n", data[0].tm.tmHeight, data[1].tm.tmHeight);
6800 ok(data[0].tm.tmAscent == data[1].tm.tmAscent,
6801 "expected %d, got %d\n", data[0].tm.tmAscent, data[1].tm.tmAscent);
6802 ok(data[0].tm.tmDescent == data[1].tm.tmDescent,
6803 "expected %d, got %d\n", data[0].tm.tmDescent, data[1].tm.tmDescent);
6804 ok(data[0].tm.tmAveCharWidth + 1 == data[1].tm.tmAveCharWidth,
6805 "expected %d, got %d\n", data[0].tm.tmAveCharWidth + 1, data[1].tm.tmAveCharWidth);
6806 ok(data[0].tm.tmMaxCharWidth + 1 == data[1].tm.tmMaxCharWidth,
6807 "expected %d, got %d\n", data[0].tm.tmMaxCharWidth + 1, data[1].tm.tmMaxCharWidth);
6808 ok(data[0].tm.tmOverhang == data[1].tm.tmOverhang,
6809 "expected %d, got %d\n", data[0].tm.tmOverhang, data[1].tm.tmOverhang);
6810 ok(data[0].w + 1 == data[1].w,
6811 "expected %d, got %d\n", data[0].w + 1, data[1].w);
6813 ok(data[0].gm.gmCellIncX + 1 == data[1].gm.gmCellIncX,
6814 "expected %d, got %d\n", data[0].gm.gmCellIncX + 1, data[1].gm.gmCellIncX);
6815 ok(data[0].gm.gmCellIncY == data[1].gm.gmCellIncY,
6816 "expected %d, got %d\n", data[0].gm.gmCellIncY, data[1].gm.gmCellIncY);
6818 /* Test bitmap font */
6819 memset(&data, 0xaa, sizeof(data));
6820 memset(&lf, 0, sizeof(lf));
6821 strcpy(lf.lfFaceName, "Courier");
6822 lf.lfCharSet = ANSI_CHARSET;
6824 hdc = GetDC(NULL);
6826 for (i = 0; i < 4; i++)
6828 HFONT hfont, hfont_old;
6830 lf.lfWeight = (i % 2) ? FW_BOLD : FW_NORMAL;
6831 lf.lfHeight = (i > 1) ? data[0].tm.tmHeight * x2_mat.eM11.value : 0;
6832 hfont = CreateFontIndirectA(&lf);
6833 hfont_old = SelectObject(hdc, hfont);
6835 ret = GetTextMetricsA(hdc, &data[i].tm);
6836 ok(ret, "got %d\n", ret);
6837 ret = GetCharWidth32A(hdc, 0x76, 0x76, &data[i].w);
6838 ok(ret, "got %d\n", ret);
6840 SelectObject(hdc, hfont_old);
6841 DeleteObject(hfont);
6843 ReleaseDC(NULL, hdc);
6845 /* compare results (bitmap) */
6846 for (i = 0; i < 4; i+=2)
6848 int diff = (i > 1) ? x2_mat.eM11.value : 1;
6849 if (data[i].tm.tmPitchAndFamily & TMPF_TRUETYPE)
6851 skip("TrueType font is selected (expected a bitmap one)\n");
6852 continue;
6854 ok(data[i].tm.tmHeight == data[i+1].tm.tmHeight,
6855 "expected %d, got %d\n", data[i].tm.tmHeight, data[i+1].tm.tmHeight);
6856 ok(data[i].tm.tmAscent == data[i+1].tm.tmAscent,
6857 "expected %d, got %d\n", data[i].tm.tmAscent, data[i+1].tm.tmAscent);
6858 ok(data[i].tm.tmDescent == data[i+1].tm.tmDescent,
6859 "expected %d, got %d\n", data[i].tm.tmDescent, data[i+1].tm.tmDescent);
6860 ok(data[i+1].tm.tmAveCharWidth - data[i].tm.tmAveCharWidth == diff,
6861 "expected %d, got %d\n", diff, data[i+1].tm.tmAveCharWidth - data[i].tm.tmAveCharWidth);
6862 ok(data[i+1].tm.tmMaxCharWidth - data[i].tm.tmMaxCharWidth == diff,
6863 "expected %d, got %d\n", diff, data[i+1].tm.tmMaxCharWidth - data[i].tm.tmMaxCharWidth);
6864 ok(data[i].tm.tmOverhang == 0,
6865 "expected 0, got %d\n", data[i].tm.tmOverhang);
6866 ok(data[i+1].tm.tmOverhang == 1,
6867 "expected 1, got %d\n", data[i+1].tm.tmOverhang);
6868 ok(data[i].w + 1 == data[i+1].w,
6869 "expected %d, got %d\n", data[i].w + 1, data[i+1].w);
6873 static void test_bitmap_font_glyph_index(void)
6875 const WCHAR text[] = L"#!/bin/sh";
6876 const struct {
6877 LPCSTR face;
6878 BYTE charset;
6879 } bitmap_font_list[] = {
6880 { "Courier", ANSI_CHARSET },
6881 { "Small Fonts", ANSI_CHARSET },
6882 { "Fixedsys", DEFAULT_CHARSET },
6883 { "System", DEFAULT_CHARSET }
6885 HDC hdc;
6886 LOGFONTA lf;
6887 HFONT hFont;
6888 CHAR facename[LF_FACESIZE];
6889 BITMAPINFO bmi;
6890 HBITMAP hBmp[2];
6891 void *pixels[2];
6892 int i, j;
6893 DWORD ret;
6894 BITMAP bmp;
6895 TEXTMETRICA tm;
6896 CHARSETINFO ci;
6897 BYTE chr = '\xA9';
6899 if (!pGetGlyphIndicesW) {
6900 win_skip("GetGlyphIndices is unavailable\n");
6901 return;
6904 hdc = CreateCompatibleDC(0);
6905 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6907 memset(&bmi, 0, sizeof(bmi));
6908 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
6909 bmi.bmiHeader.biBitCount = 32;
6910 bmi.bmiHeader.biPlanes = 1;
6911 bmi.bmiHeader.biWidth = 128;
6912 bmi.bmiHeader.biHeight = 32;
6913 bmi.bmiHeader.biCompression = BI_RGB;
6915 for (i = 0; i < ARRAY_SIZE(bitmap_font_list); i++) {
6916 memset(&lf, 0, sizeof(lf));
6917 lf.lfCharSet = bitmap_font_list[i].charset;
6918 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
6919 hFont = CreateFontIndirectA(&lf);
6920 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
6921 hFont = SelectObject(hdc, hFont);
6922 ret = GetTextMetricsA(hdc, &tm);
6923 ok(ret, "GetTextMetric failed\n");
6924 ret = GetTextFaceA(hdc, sizeof(facename), facename);
6925 ok(ret, "GetTextFace failed\n");
6926 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
6927 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
6928 continue;
6930 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
6931 skip("expected %s, got %s\n", lf.lfFaceName, facename);
6932 continue;
6935 for (j = 0; j < 2; j++) {
6936 HBITMAP hBmpPrev;
6937 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
6938 ok(hBmp[j] != NULL, "Can't create DIB\n");
6939 hBmpPrev = SelectObject(hdc, hBmp[j]);
6940 switch (j) {
6941 case 0:
6942 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
6943 break;
6944 case 1:
6946 int len = lstrlenW(text);
6947 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
6948 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
6949 ok(ret, "GetGlyphIndices failed\n");
6950 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
6951 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
6952 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
6953 HeapFree(GetProcessHeap(), 0, indices);
6954 break;
6957 ok(ret, "ExtTextOutW failed\n");
6958 SelectObject(hdc, hBmpPrev);
6961 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
6962 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6963 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6965 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
6966 if (!ret) {
6967 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6968 goto next;
6970 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
6971 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
6972 goto next;
6975 for (j = 0; j < 2; j++) {
6976 HBITMAP hBmpPrev;
6977 WORD code;
6978 hBmpPrev = SelectObject(hdc, hBmp[j]);
6979 switch (j) {
6980 case 0:
6981 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6982 break;
6983 case 1:
6984 ret = GetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6985 ok(ret, "GetGlyphIndices failed\n");
6986 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6987 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6988 break;
6990 ok(ret, "ExtTextOutA failed\n");
6991 SelectObject(hdc, hBmpPrev);
6994 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6995 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6996 next:
6997 for (j = 0; j < 2; j++)
6998 DeleteObject(hBmp[j]);
6999 hFont = SelectObject(hdc, hFont);
7000 DeleteObject(hFont);
7003 DeleteDC(hdc);
7006 static void test_GetCharWidthI(void)
7008 static const char *teststr = "wine ";
7009 HFONT hfont, prev_hfont;
7010 WORD glyphs[5];
7011 INT widths[5];
7012 LOGFONTA lf;
7013 ABC abc[5];
7014 int len, i;
7015 DWORD nb;
7016 BOOL ret;
7017 HDC hdc;
7019 memset(&lf, 0, sizeof(lf));
7020 strcpy(lf.lfFaceName, "Tahoma");
7021 lf.lfHeight = -20;
7023 hdc = GetDC(0);
7025 hfont = CreateFontIndirectA(&lf);
7026 prev_hfont = SelectObject(hdc, hfont);
7028 len = strlen(teststr);
7029 nb = GetGlyphIndicesA(hdc, teststr, len, glyphs, 0);
7030 ok(nb == len, "\n");
7032 memset(abc, 0xcc, sizeof(abc));
7033 ret = GetCharABCWidthsI(hdc, 0, len, glyphs, abc);
7034 ok(ret, "GetCharABCWidthsI failed\n");
7036 memset(widths, 0xcc, sizeof(widths));
7037 ret = GetCharWidthI(hdc, 0, len, glyphs, widths);
7038 ok(ret, "GetCharWidthI failed\n");
7040 for (i = 0; i < len; i++)
7041 ok(widths[i] == abc[i].abcA + abc[i].abcB + abc[i].abcC, "%u, glyph %u, got width %d\n",
7042 i, glyphs[i], widths[i]);
7044 DeleteObject(SelectObject(hdc, prev_hfont));
7045 ReleaseDC(0, hdc);
7048 static INT CALLBACK long_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lparam)
7050 BOOL *found_font = (BOOL *)lparam;
7051 *found_font = TRUE;
7052 return 1;
7055 static void test_long_names(void)
7057 char ttf_name[MAX_PATH];
7058 LOGFONTA font = {0};
7059 HFONT handle_font;
7060 BOOL found_font;
7061 int ret;
7062 HDC dc;
7064 if (!write_ttf_file("wine_longname.ttf", ttf_name))
7066 skip("Failed to create ttf file for testing\n");
7067 return;
7070 dc = GetDC(NULL);
7072 ret = AddFontResourceExA(ttf_name, FR_PRIVATE, 0);
7073 ok(ret, "AddFontResourceEx() failed\n");
7075 strcpy(font.lfFaceName, "wine_3_this_is_a_very_long_name");
7076 found_font = FALSE;
7077 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
7078 ok(found_font == TRUE, "EnumFontFamiliesExA didn't find font.\n");
7080 strcpy(font.lfFaceName, "wine_2_this_is_a_very_long_name");
7081 found_font = FALSE;
7082 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
7083 ok(found_font == TRUE, "EnumFontFamiliesExA didn't find font.\n");
7085 strcpy(font.lfFaceName, "wine_1_this_is_a_very_long_name");
7086 found_font = FALSE;
7087 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
7088 ok(found_font == FALSE, "EnumFontFamiliesExA must not find font.\n");
7090 handle_font = CreateFontIndirectA(&font);
7091 ok(handle_font != NULL, "CreateFontIndirectA failed\n");
7092 DeleteObject(handle_font);
7094 ret = RemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
7095 ok(ret, "RemoveFontResourceEx() failed\n");
7097 DeleteFileA(ttf_name);
7098 ReleaseDC(NULL, dc);
7101 static void test_ttf_names(void)
7103 struct enum_fullname_data efnd;
7104 char ttf_name[MAX_PATH], ttf_name_bold[MAX_PATH];
7105 LOGFONTA font = {0};
7106 HFONT handle_font;
7107 int ret;
7108 HDC dc;
7110 if (!write_ttf_file("wine_ttfnames.ttf", ttf_name))
7112 skip("Failed to create ttf file for testing\n");
7113 return;
7116 if (!write_ttf_file("wine_ttfnames_bold.ttf", ttf_name_bold))
7118 skip("Failed to create ttf file for testing\n");
7119 DeleteFileA(ttf_name);
7120 return;
7123 ret = AddFontResourceExA(ttf_name, FR_PRIVATE, 0);
7124 ok(ret, "AddFontResourceEx() failed\n");
7126 ret = AddFontResourceExA(ttf_name_bold, FR_PRIVATE, 0);
7127 ok(ret, "AddFontResourceEx() failed\n");
7129 dc = GetDC(NULL);
7131 strcpy(font.lfFaceName, "Wine_TTF_Names_Long_Family1_Con");
7132 memset(&efnd, 0, sizeof(efnd));
7133 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7134 ok(efnd.total == 0, "EnumFontFamiliesExA must not find font.\n");
7136 /* Windows doesn't match with Typographic/Preferred Family tags */
7137 strcpy(font.lfFaceName, "Wine TTF Names Long Family1");
7138 memset(&efnd, 0, sizeof(efnd));
7139 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7140 ok(efnd.total == 0, "EnumFontFamiliesExA must not find font.\n");
7142 strcpy(font.lfFaceName, "Wine TTF Names Long Family1 Ext");
7143 memset(&efnd, 0, sizeof(efnd));
7144 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7145 ok(efnd.total == 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd.total);
7147 strcpy(font.lfFaceName, "Wine TTF Names Long Family1 Con");
7148 memset(&efnd, 0, sizeof(efnd));
7149 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7150 ok(efnd.total == 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd.total);
7152 handle_font = CreateFontIndirectA(&font);
7153 ok(handle_font != NULL, "CreateFontIndirectA failed\n");
7154 DeleteObject(handle_font);
7156 ret = RemoveFontResourceExA(ttf_name_bold, FR_PRIVATE, 0);
7157 ok(ret, "RemoveFontResourceEx() failed\n");
7159 DeleteFileA(ttf_name_bold);
7161 ret = RemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
7162 ok(ret, "RemoveFontResourceEx() failed\n");
7164 DeleteFileA(ttf_name);
7165 ReleaseDC(NULL, dc);
7168 static void test_lang_names(void)
7170 static const WCHAR name_cond_ja_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja)";
7171 static const WCHAR name_cond_ja_reg_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg";
7172 static const WCHAR name_cond_ja_reg_ja_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg (ja)";
7173 static const WCHAR name_wws_ja_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d WWS (ja)";
7175 struct enum_fullname_data efnd;
7176 struct enum_fullname_data_w efnd_w;
7177 char ttf_name[MAX_PATH], ttf_name2[MAX_PATH], ttf_name3[MAX_PATH];
7178 LOGFONTA font = {0};
7179 LOGFONTW font_w = {0};
7180 int ret, i;
7181 HDC dc;
7182 const WCHAR *primary_family, *primary_fullname;
7184 if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH && PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE)
7186 skip( "Primary language is neither English nor Japanese, skipping test\n" );
7187 return;
7190 if (!write_ttf_file( "wine_langnames.ttf", ttf_name ))
7192 skip( "Failed to create ttf file for testing\n" );
7193 return;
7196 if (!write_ttf_file( "wine_langnames2.ttf", ttf_name2 ))
7198 skip( "Failed to create ttf file for testing\n" );
7199 DeleteFileA( ttf_name );
7200 return;
7203 if (!write_ttf_file( "wine_langnames3.ttf", ttf_name3 ))
7205 skip( "Failed to create ttf file for testing\n" );
7206 DeleteFileA( ttf_name2 );
7207 DeleteFileA( ttf_name );
7208 return;
7211 ret = AddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
7212 ok( ret, "AddFontResourceEx() failed\n" );
7214 dc = GetDC( NULL );
7216 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7218 primary_family = L"Wine Lang Cond (en)";
7219 primary_fullname = L"Wine Lang Cond Reg (en)";
7221 else
7223 primary_family = name_cond_ja_w;
7224 primary_fullname = name_cond_ja_reg_w;
7227 for (i = 0; i < 3; ++i)
7229 /* check that lookup by preferred or WWS family / full names or postscript FontName doesn't work */
7231 strcpy( font.lfFaceName, "Wine Lang (en)" );
7232 memset( &efnd, 0, sizeof(efnd) );
7233 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7234 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7236 strcpy( font.lfFaceName, "Wine Lang Condensed Bold (ko)" );
7237 memset( &efnd, 0, sizeof(efnd) );
7238 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7239 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7241 wcscpy( font_w.lfFaceName, name_wws_ja_w );
7242 memset( &efnd_w, 0, sizeof(efnd_w) );
7243 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7244 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7246 strcpy( font.lfFaceName, "Reg WWS (zh-tw)" );
7247 memset( &efnd, 0, sizeof(efnd) );
7248 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7249 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7251 strcpy( font.lfFaceName, "Wine Lang (en) Reg WWS (en)" );
7252 memset( &efnd, 0, sizeof(efnd) );
7253 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7254 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7256 strcpy( font.lfFaceName, "WineLangNamesRegular" );
7257 memset( &efnd, 0, sizeof(efnd) );
7258 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7259 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7261 /* then, the primary ttf family name always works */
7263 wcscpy( font_w.lfFaceName, primary_family );
7264 memset( &efnd_w, 0, sizeof(efnd_w) );
7265 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7266 ok( efnd_w.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7268 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7270 wcscpy( font_w.lfFaceName, name_cond_ja_w );
7271 memset( &efnd_w, 0, sizeof(efnd_w) );
7272 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7273 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7276 /* if there is no primary ttf family name, the english ttf name, or postscript FamilyName are used instead */
7278 strcpy( font.lfFaceName, "Wine_Lang_Names" );
7279 memset( &efnd, 0, sizeof(efnd) );
7280 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7281 if (i == 2)
7282 ok( efnd.total == 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7283 else
7284 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7286 /* same goes for ttf full names */
7288 wcscpy( font_w.lfFaceName, primary_fullname );
7289 memset( &efnd_w, 0, sizeof(efnd_w) );
7290 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7291 ok( efnd_w.total == 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7293 if (efnd_w.total >= 1)
7295 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfLogFont.lfFaceName, primary_family ),
7296 "%d: (%d) unexpected lfFaceName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfLogFont.lfFaceName) );
7297 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfFullName, primary_fullname ),
7298 "%d: (%d) unexpected elfFullName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfFullName) );
7299 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfStyle, PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH ? L"Reg (en)" : L"Reg (ja)" ),
7300 "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfStyle) );
7303 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7305 wcscpy( font_w.lfFaceName, name_cond_ja_reg_w );
7306 memset( &efnd_w, 0, sizeof(efnd_w) );
7307 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7308 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7311 wcscpy( font_w.lfFaceName, L"Wine_Lang_Names_Regular" );
7312 memset( &efnd_w, 0, sizeof(efnd_w) );
7313 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7314 ok( efnd_w.total == i, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7316 while (efnd_w.total--)
7318 ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfLogFont.lfFaceName, efnd_w.total == 1 ? L"Wine_Lang_Names" : primary_family ),
7319 "%d: (%d) unexpected lfFaceName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfLogFont.lfFaceName) );
7320 ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfFullName, L"Wine_Lang_Names_Regular" ),
7321 "%d: (%d) unexpected elfFullName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfFullName) );
7322 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7323 ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfStyle, efnd_w.total == 1 ? L"Regular" : L"Reg (en)" ),
7324 "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfStyle) );
7325 else
7326 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfStyle, L"Reg (ja)" ),
7327 "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfStyle) );
7330 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7332 wcscpy( font_w.lfFaceName, name_cond_ja_reg_ja_w );
7333 memset( &efnd_w, 0, sizeof(efnd_w) );
7334 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7335 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7338 /* another language can also be used for lookup, if the primary langid isn't english, then
7339 english seems to have priority, otherwise or if english is already the primary langid,
7340 the family name with the smallest langid is used as secondary lookup language. */
7342 strcpy( font.lfFaceName, "Wine Lang Cond (zh-tw)" );
7343 memset( &efnd, 0, sizeof(efnd) );
7344 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7345 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7346 ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7347 else /* (zh-tw) doesn't match here probably because there's an (en) name too */
7348 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7350 strcpy( font.lfFaceName, "Wine Lang Cond (en)" );
7351 memset( &efnd, 0, sizeof(efnd) );
7352 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7353 /* either because it's the primary language, or because it's a secondary */
7354 ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7356 wcscpy( font_w.lfFaceName, L"Wine Police d'\xe9" "criture (fr)" );
7357 memset( &efnd_w, 0, sizeof(efnd_w) );
7358 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7359 /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */
7360 if (i == 2) ok( efnd_w.total == 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7361 else ok( efnd_w.total == 0, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7363 /* case matching should not depend on the current locale */
7364 if (i == 2)
7366 wcscpy( font_w.lfFaceName, L"Wine POLICE D'\xc9" "CRITURE (fr)" );
7367 memset( &efnd_w, 0, sizeof(efnd_w) );
7368 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7369 ok( efnd_w.total == 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7372 strcpy( font.lfFaceName, "Wine Lang Cond (ko)" );
7373 memset( &efnd, 0, sizeof(efnd) );
7374 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7375 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7377 /* that doesn't apply to full names */
7379 strcpy( font.lfFaceName, "Wine Lang Cond Reg (zh-tw)" );
7380 memset( &efnd, 0, sizeof(efnd) );
7381 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7382 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7384 strcpy( font.lfFaceName, "Wine Lang Cond Reg (fr)" );
7385 memset( &efnd, 0, sizeof(efnd) );
7386 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7387 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7389 if (i == 0)
7391 ret = AddFontResourceExA( ttf_name2, FR_PRIVATE, 0 );
7392 ok( ret, "AddFontResourceEx() failed\n" );
7394 else if (i == 1)
7396 ret = AddFontResourceExA( ttf_name3, FR_PRIVATE, 0 );
7397 ok( ret, "AddFontResourceEx() failed\n" );
7401 ret = RemoveFontResourceExA( ttf_name3, FR_PRIVATE, 0 );
7402 ok( ret, "RemoveFontResourceEx() failed\n" );
7404 DeleteFileA( ttf_name3 );
7406 ret = RemoveFontResourceExA( ttf_name2, FR_PRIVATE, 0 );
7407 ok( ret, "RemoveFontResourceEx() failed\n" );
7409 DeleteFileA( ttf_name2 );
7411 ret = RemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
7412 ok( ret, "RemoveFontResourceEx() failed\n" );
7414 DeleteFileA( ttf_name );
7415 ReleaseDC( NULL, dc );
7418 typedef struct
7420 USHORT majorVersion;
7421 USHORT minorVersion;
7422 SHORT ascender;
7423 SHORT descender;
7424 SHORT lineGap;
7425 USHORT advanceWidthMax;
7426 SHORT minLeftSideBearing;
7427 SHORT minRightSideBearing;
7428 SHORT xMaxExtent;
7429 SHORT caretSlopeRise;
7430 SHORT caretSlopeRun;
7431 SHORT caretOffset;
7432 SHORT reserved[4];
7433 SHORT metricDataFormat;
7434 SHORT numberOfHMetrics;
7435 } TT_Hori_Header;
7437 static void test_GetCharWidthInfo(void)
7439 HDC hdc;
7440 HFONT hfont, hfont_prev;
7441 LOGFONTA lf;
7442 BOOL r;
7443 DWORD ret, i;
7444 OUTLINETEXTMETRICA otm;
7445 TT_Hori_Header hhea;
7446 struct char_width_info
7448 INT lsb, rsb, unk;
7449 } info, info2;
7450 SHORT minLeftSideBearing, minRightSideBearing;
7451 POINT pt[2];
7452 const char* face_list[] = { "Symbol", "Ume Gothic", "MS Gothic" };
7454 if (!pGetCharWidthInfo)
7456 win_skip("GetCharWidthInfo is unavailable\n");
7457 return;
7460 hdc = GetDC(NULL);
7462 /* test default (System) font */
7463 memset(&info, 0xaa, sizeof(info));
7464 r = pGetCharWidthInfo(hdc, &info);
7465 if (r) /* win10 1803 succeeds */
7467 ok(info.lsb == 0, "expected 0, got %d\n", info.lsb);
7468 ok(info.rsb == 0, "expected 0, got %d\n", info.rsb);
7469 ok(info.unk == 0, "expected 0, got %d\n", info.unk);
7472 memset(&lf, 0, sizeof(lf));
7473 lf.lfWeight = FW_NORMAL;
7474 lf.lfCharSet = ANSI_CHARSET;
7475 strcpy(lf.lfFaceName, "Tahoma");
7476 hfont = CreateFontIndirectA(&lf);
7477 hfont_prev = SelectObject(hdc, hfont);
7478 ok(hfont_prev != NULL, "SelectObject failed\n");
7480 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
7481 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
7482 DeleteObject(SelectObject(hdc, hfont_prev));
7484 /* test Tahoma at the em square size */
7485 lf.lfHeight = -(int)otm.otmEMSquare;
7486 hfont = CreateFontIndirectA(&lf);
7487 hfont_prev = SelectObject(hdc, hfont);
7488 ok(hfont_prev != NULL, "SelectObject failed\n");
7490 ret = GetFontData(hdc, MS_MAKE_TAG('h','h','e','a'), 0, &hhea, sizeof(hhea));
7491 ok(ret == sizeof(hhea), "got %u\n", ret);
7492 minLeftSideBearing = GET_BE_WORD(hhea.minLeftSideBearing);
7493 minRightSideBearing = GET_BE_WORD(hhea.minRightSideBearing);
7495 memset(&info, 0xaa, sizeof(info));
7496 r = pGetCharWidthInfo(hdc, &info);
7497 ok(r, "GetCharWidthInfo failed\n");
7498 ok(info.lsb == minLeftSideBearing, "expected %d, got %d\n", minLeftSideBearing, info.lsb);
7499 ok(info.rsb == minRightSideBearing, "expected %d, got %d\n", minRightSideBearing, info.rsb);
7501 DeleteObject(SelectObject(hdc, hfont_prev));
7503 /* these values are scaled, try with smaller size */
7504 lf.lfHeight /= 3;
7505 hfont = CreateFontIndirectA(&lf);
7506 hfont_prev = SelectObject(hdc, hfont);
7507 ok(hfont_prev != NULL, "SelectObject failed\n");
7509 memset(&info2, 0xaa, sizeof(info2));
7510 r = pGetCharWidthInfo(hdc, &info2);
7511 ok(r, "pGetCharWidthInfo failed\n");
7512 ok(info2.lsb == info.lsb/3, "expected %d, got %d\n", info.lsb/3, info2.lsb);
7513 ok(info2.rsb == info.rsb/3, "expected %d, got %d\n", info.rsb/3, info2.rsb);
7515 DeleteObject(SelectObject(hdc, hfont_prev));
7516 ReleaseDC(NULL, hdc);
7518 /* test with another mapping mode */
7519 hdc = GetDC(NULL);
7520 SetMapMode(hdc, MM_ISOTROPIC);
7521 SetWindowExtEx(hdc, 2, 2, NULL);
7522 SetViewportExtEx(hdc, 1, 1, NULL);
7524 memset(pt, 0, sizeof(pt));
7525 pt[0].y = otm.otmEMSquare;
7526 DPtoLP(hdc, pt, 1);
7528 memset(&lf, 0, sizeof(lf));
7529 lf.lfWeight = FW_NORMAL;
7530 lf.lfCharSet = ANSI_CHARSET;
7531 lf.lfHeight = -abs(pt[0].y);
7532 strcpy(lf.lfFaceName, "Tahoma");
7533 hfont = CreateFontIndirectA(&lf);
7534 hfont_prev = SelectObject(hdc, hfont);
7535 ok(hfont_prev != NULL, "SelectObject failed\n");
7537 memset(&info2, 0xaa, sizeof(info2));
7538 r = pGetCharWidthInfo(hdc, &info2);
7539 ok(r, "GetCharWidthInfo failed\n");
7540 pt[0].x = info.lsb; pt[0].y = 0;
7541 pt[1].x = info.rsb; pt[1].y = 0;
7542 DPtoLP(hdc, pt, 2);
7543 ok(pt[0].x == info2.lsb, "expected %d, got %d\n", pt[0].x, info2.lsb);
7544 ok(pt[1].x == info2.rsb, "expected %d, got %d\n", pt[1].x, info2.rsb);
7546 DeleteObject(SelectObject(hdc, hfont_prev));
7547 ReleaseDC(NULL, hdc);
7549 /* test with synthetic fonts */
7550 hdc = GetDC(NULL);
7551 for (i = 0; i < ARRAY_SIZE(face_list); i++)
7553 const char* face = face_list[i];
7554 if (!is_truetype_font_installed(face))
7556 skip("%s is not installed\n", face);
7557 continue;
7559 memset(&lf, 0, sizeof(lf));
7560 lf.lfWeight = FW_NORMAL;
7561 lf.lfItalic = FALSE;
7562 lf.lfCharSet = DEFAULT_CHARSET;
7563 lf.lfHeight = -256;
7564 strcpy(lf.lfFaceName, face);
7565 hfont = CreateFontIndirectA(&lf);
7566 hfont_prev = SelectObject(hdc, hfont);
7568 memset(&info, 0xaa, sizeof(info));
7569 r = pGetCharWidthInfo(hdc, &info);
7570 ok(r, "%s: GetCharWidthInfo failed\n", face);
7572 /* test with synthetic bold */
7573 lf.lfWeight = FW_BOLD;
7574 lf.lfItalic = FALSE;
7575 hfont = CreateFontIndirectA(&lf);
7576 DeleteObject(SelectObject(hdc, hfont));
7578 memset(&info2, 0xaa, sizeof(info2));
7579 r = pGetCharWidthInfo(hdc, &info2);
7580 ok(r, "%s: GetCharWidthInfo failed\n", face);
7581 ok(info.lsb == info2.lsb, "%s: expected %d, got %d\n", face, info.lsb, info2.lsb);
7582 ok(info.rsb == info2.rsb, "%s: expected %d, got %d\n", face, info.rsb, info2.rsb);
7584 /* test with synthetic italic */
7585 lf.lfWeight = FW_NORMAL;
7586 lf.lfItalic = TRUE;
7587 hfont = CreateFontIndirectA(&lf);
7588 DeleteObject(SelectObject(hdc, hfont));
7590 memset(&info2, 0xaa, sizeof(info2));
7591 r = pGetCharWidthInfo(hdc, &info2);
7592 ok(r, "%s: GetCharWidthInfo failed\n", face);
7593 todo_wine ok(info.lsb > info2.lsb, "%s: expected less than %d, got %d\n", face, info.lsb, info2.lsb);
7594 todo_wine ok(info.rsb > info2.rsb, "%s: expected less than %d, got %d\n", face, info.rsb, info2.rsb);
7595 DeleteObject(SelectObject(hdc, hfont_prev));
7598 ReleaseDC(NULL, hdc);
7601 static int CALLBACK get_char_width_proc(const LOGFONTA *lf,
7602 const TEXTMETRICA *tm, DWORD type, LPARAM ctx)
7604 HFONT font = CreateFontIndirectA(lf);
7605 HDC dc = GetDC(NULL);
7606 const char c = 'm';
7607 ABCFLOAT abcf;
7608 int i, i32;
7609 BOOL ret;
7610 float f;
7611 ABC abc;
7613 SelectObject(dc, font);
7615 ret = GetCharWidthFloatA(dc, c, c, &f);
7616 ok(ret, "%s: GetCharWidthFloat() failed\n", lf->lfFaceName);
7617 ret = GetCharWidth32A(dc, c, c, &i32);
7618 ok(ret, "%s: GetCharWidth32A() failed\n", lf->lfFaceName);
7619 ret = GetCharWidthA(dc, c, c, &i);
7620 ok(ret, "%s: GetCharWidthA() failed\n", lf->lfFaceName);
7621 ok(i == i32, "%s: mismatched widths %d/%d\n", lf->lfFaceName, i, i32);
7622 ok((float)i / 16.0f == f, "%s: mismatched widths %d/%.8e\n", lf->lfFaceName, i, f);
7624 ret = GetCharABCWidthsFloatA(dc, c, c, &abcf);
7625 ok(ret, "%s: GetCharABCWidths() failed\n", lf->lfFaceName);
7626 if (GetCharABCWidthsA(dc, c, c, &abc))
7627 ok((float)abc.abcB == abcf.abcfB, "%s: mismatched widths %d/%.8e\n",
7628 lf->lfFaceName, abc.abcB, abcf.abcfB);
7630 ReleaseDC(NULL, dc);
7631 DeleteObject(font);
7632 return 1;
7635 static void test_char_width(void)
7637 HDC dc = GetDC(NULL);
7638 LOGFONTA lf = {0};
7640 lf.lfCharSet = DEFAULT_CHARSET;
7641 EnumFontFamiliesExA(dc, &lf, get_char_width_proc, 0, 0);
7643 ReleaseDC(NULL, dc);
7646 static void test_GetCharacterPlacement_kerning(void)
7648 LOGFONTA lf;
7649 HFONT hfont, hfont_old;
7650 KERNINGPAIR *kp;
7651 HDC hdc;
7652 DWORD count, ret, i, size, width, width_kern, idx;
7653 WCHAR str[30];
7654 GCP_RESULTSW result;
7655 int kern[30], pos[30], pos_kern[30], dx[30], dx_kern[30], kern_amount;
7657 if (!is_font_installed("Arial"))
7659 skip("Arial is not installed, skipping the test\n");
7660 return;
7663 hdc = GetDC(0);
7665 memset(&lf, 0, sizeof(lf));
7666 strcpy(lf.lfFaceName, "Arial");
7667 lf.lfHeight = 120;
7668 hfont = CreateFontIndirectA(&lf);
7669 ok(hfont != NULL, "CreateFontIndirect failed\n");
7671 hfont_old = SelectObject(hdc, hfont);
7673 count = GetKerningPairsW(hdc, 0, NULL);
7674 kp = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*kp));
7676 ret = GetKerningPairsW(hdc, count, kp);
7677 ok(ret == count, "got %u, expected %u\n", ret, count);
7679 size = kern_amount = idx = 0;
7680 for (i = 0; i < count; i++)
7682 if (kp[i].wFirst >= 'A' && kp[i].wFirst <= 'z' &&
7683 kp[i].wSecond >= 'A' && kp[i].wSecond <= 'z')
7685 str[size++] = kp[i].wFirst;
7686 str[size++] = kp[i].wSecond;
7687 str[size++] = 0;
7688 kern[idx] = kp[i].iKernAmount;
7689 idx++;
7690 kern_amount += kp[i].iKernAmount;
7691 if (size >= ARRAY_SIZE(str)) break;
7695 HeapFree(GetProcessHeap(), 0, kp);
7697 count = size;
7699 memset(&result, 0, sizeof(result));
7700 result.lStructSize = sizeof(result);
7701 result.lpCaretPos = pos;
7702 result.lpDx = dx;
7703 result.nGlyphs = count;
7704 ret = GetCharacterPlacementW(hdc, str, count, 0, &result, 0);
7705 ok(ret, "GetCharacterPlacement failed\n");
7706 ok(result.nGlyphs == count, "got %u\n", result.nGlyphs);
7707 width = LOWORD(ret);
7709 memset(&result, 0, sizeof(result));
7710 result.lStructSize = sizeof(result);
7711 result.lpCaretPos = pos_kern;
7712 result.lpDx = dx_kern;
7713 result.nGlyphs = count;
7714 ret = GetCharacterPlacementW(hdc, str, count, 0, &result, GCP_USEKERNING);
7715 ok(ret, "GetCharacterPlacement failed\n");
7716 ok(result.nGlyphs == count, "got %u\n", result.nGlyphs);
7717 width_kern = LOWORD(ret);
7719 if (width == width_kern)
7721 win_skip("GCP_USEKERNING is broken on this platform\n");
7722 goto done;
7725 ok(width + kern_amount == width_kern, "%d + %d != %d\n", width, kern_amount, width_kern);
7727 kern_amount = idx = 0;
7728 for (i = 0; i < count; i += 3, idx++)
7730 ok(pos[i] + kern_amount == pos_kern[i], "%d: %d + %d != %d\n", i, pos[i], kern_amount, pos_kern[i]);
7731 kern_amount += kern[idx];
7732 ok(pos[i+1] + kern_amount == pos_kern[i+1], "%d: %d + %d != %d\n", i, pos[i+1], kern_amount, pos_kern[i+1]);
7733 ok(pos[i+2] + kern_amount == pos_kern[i+2], "%d: %d + %d != %d\n", i, pos[i+2], kern_amount, pos_kern[i+2]);
7735 ok(dx[i] + kern[idx] == dx_kern[i], "%d: %d + %d != %d\n", i, dx[i], kern[idx], dx_kern[i]);
7736 ok(dx[i+1] == dx_kern[i+1], "%d: %d != %d\n", i, dx[i+1], dx_kern[i+1]);
7737 ok(dx[i+2] == dx_kern[i+2], "%d: %d != %d\n", i, dx[i+2], dx_kern[i+2]);
7740 done:
7741 SelectObject(hdc, hfont_old);
7742 DeleteObject(hfont);
7743 ReleaseDC(0, hdc);
7746 static void test_select_object(void)
7748 HFONT hfont, old_font;
7749 LOGFONTA lf;
7751 memset(&lf, 0, sizeof lf);
7753 lf.lfCharSet = ANSI_CHARSET;
7754 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
7755 lf.lfWeight = FW_DONTCARE;
7756 lf.lfHeight = 16;
7757 lf.lfWidth = 16;
7758 lf.lfQuality = DEFAULT_QUALITY;
7760 lstrcpyA(lf.lfFaceName, "Arial");
7761 hfont = create_font("Arial", &lf);
7763 SetLastError(0xdeadbeef);
7764 old_font = SelectObject(NULL, hfont);
7765 ok(!old_font, "SelectObject returned %p\n", old_font);
7766 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError() = %u\n",
7767 GetLastError());
7769 DeleteObject(hfont);
7772 START_TEST(font)
7774 static const char *test_names[] =
7776 "AddFontMemResource",
7778 char path_name[MAX_PATH];
7779 STARTUPINFOA startup;
7780 char **argv;
7781 int argc, i;
7783 init();
7785 argc = winetest_get_mainargs(&argv);
7786 if (argc >= 3)
7788 if (!strcmp(argv[2], "AddFontMemResource"))
7789 test_AddFontMemResource();
7790 return;
7793 test_stock_fonts();
7794 test_logfont();
7795 test_bitmap_font();
7796 test_outline_font();
7797 test_bitmap_font_metrics();
7798 test_GdiGetCharDimensions();
7799 test_GetCharABCWidths();
7800 test_text_extents();
7801 test_GetGlyphIndices();
7802 test_GetKerningPairs();
7803 test_GetOutlineTextMetrics();
7804 test_SetTextJustification();
7805 test_font_charset();
7806 test_GdiGetCodePage();
7807 test_GetFontUnicodeRanges();
7808 test_nonexistent_font();
7809 test_orientation();
7810 test_height_selection();
7811 test_EnumFonts();
7812 test_EnumFonts_subst();
7814 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
7815 * I'd like to avoid them in this test.
7817 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
7818 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
7819 if (is_truetype_font_installed("Arial Black") &&
7820 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
7822 test_EnumFontFamilies("", ANSI_CHARSET);
7823 test_EnumFontFamilies("", SYMBOL_CHARSET);
7824 test_EnumFontFamilies("", DEFAULT_CHARSET);
7826 else
7827 skip("Arial Black or Symbol/Wingdings is not installed\n");
7828 test_EnumFontFamiliesEx_default_charset();
7829 test_GetTextMetrics();
7830 test_RealizationInfo();
7831 test_GetTextFace();
7832 test_GetGlyphOutline();
7833 test_GetTextMetrics2("Tahoma", -11);
7834 test_GetTextMetrics2("Tahoma", -55);
7835 test_GetTextMetrics2("Tahoma", -110);
7836 test_GetTextMetrics2("Arial", -11);
7837 test_GetTextMetrics2("Arial", -55);
7838 test_GetTextMetrics2("Arial", -110);
7839 test_GetCharacterPlacement();
7840 test_GetCharacterPlacement_kerning();
7841 test_GetCharWidthInfo();
7842 test_CreateFontIndirect();
7843 test_CreateFontIndirectEx();
7844 test_oemcharset();
7845 test_fullname();
7846 test_fullname2();
7847 test_east_asian_font_selection();
7848 test_max_height();
7849 test_vertical_order();
7850 test_GetCharWidth32();
7851 test_fake_bold_font();
7852 test_bitmap_font_glyph_index();
7853 test_GetCharWidthI();
7854 test_long_names();
7855 test_ttf_names();
7856 test_lang_names();
7857 test_char_width();
7858 test_select_object();
7860 /* These tests should be last test until RemoveFontResource
7861 * is properly implemented.
7863 test_vertical_font();
7864 test_CreateScalableFontResource();
7866 winetest_get_mainargs( &argv );
7867 for (i = 0; i < ARRAY_SIZE(test_names); ++i)
7869 PROCESS_INFORMATION info;
7871 memset(&startup, 0, sizeof(startup));
7872 startup.cb = sizeof(startup);
7873 sprintf(path_name, "%s font %s", argv[0], test_names[i]);
7874 ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info),
7875 "CreateProcess failed.\n");
7876 wait_child_process(info.hProcess);
7877 CloseHandle(info.hProcess);
7878 CloseHandle(info.hThread);