gdi32/tests: Add MS Shell Dlg tests.
[wine/wine-gecko.git] / dlls / gdi32 / tests / font.c
blob0e7508818dc48dd1f4da47f11f54551d316a7d8a
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b, exact) (abs((a) - (b)) <= ((exact) ? 0 : 1))
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
46 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
47 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
48 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
49 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
50 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
51 LPINT nfit, LPINT dxs, LPSIZE size );
52 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
53 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
54 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
55 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
56 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
57 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
59 static HMODULE hgdi32 = 0;
60 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
61 static WORD system_lang_id;
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
66 #else
67 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
69 #endif
71 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
72 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
73 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
74 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
75 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
76 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
78 static void init(void)
80 hgdi32 = GetModuleHandleA("gdi32.dll");
82 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
83 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
84 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
85 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
86 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
87 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
88 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
89 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
90 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
91 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
92 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
93 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
94 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
95 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
96 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
97 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
98 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
99 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
101 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
104 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
106 if (type != TRUETYPE_FONTTYPE) return 1;
108 return 0;
111 static BOOL is_truetype_font_installed(const char *name)
113 HDC hdc = GetDC(0);
114 BOOL ret = FALSE;
116 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
117 ret = TRUE;
119 ReleaseDC(0, hdc);
120 return ret;
123 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
125 return 0;
128 static BOOL is_font_installed(const char *name)
130 HDC hdc = GetDC(0);
131 BOOL ret = FALSE;
133 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
134 ret = TRUE;
136 ReleaseDC(0, hdc);
137 return ret;
140 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
142 HRSRC rsrc;
143 void *rsrc_data;
145 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
146 if (!rsrc) return NULL;
148 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
149 if (!rsrc_data) return NULL;
151 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
152 if (!*rsrc_size) return NULL;
154 return rsrc_data;
157 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
159 char tmp_path[MAX_PATH];
160 HANDLE hfile;
161 BOOL ret;
163 GetTempPathA(MAX_PATH, tmp_path);
164 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
166 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
167 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
169 ret = WriteFile(hfile, data, *size, size, NULL);
171 CloseHandle(hfile);
172 return ret;
175 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
177 void *rsrc_data;
178 DWORD rsrc_size;
180 rsrc_data = get_res_data( fontname, &rsrc_size );
181 if (!rsrc_data) return FALSE;
183 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
186 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
188 LOGFONTA getobj_lf;
189 int ret, minlen = 0;
191 if (!hfont)
192 return;
194 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
195 /* NT4 tries to be clever and only returns the minimum length */
196 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
197 minlen++;
198 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
199 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
200 ok(lf->lfHeight == getobj_lf.lfHeight ||
201 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
202 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
203 ok(lf->lfWidth == getobj_lf.lfWidth ||
204 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
205 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
206 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
207 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
208 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
209 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
210 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
211 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
212 ok(lf->lfWeight == getobj_lf.lfWeight ||
213 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
214 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
215 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
216 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
217 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
218 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
219 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
220 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
221 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
222 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
223 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
224 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
225 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
228 static HFONT create_font(const char* test, const LOGFONTA* lf)
230 HFONT hfont = CreateFontIndirectA(lf);
231 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
232 if (hfont)
233 check_font(test, lf, hfont);
234 return hfont;
237 static void test_logfont(void)
239 LOGFONTA lf;
240 HFONT hfont;
242 memset(&lf, 0, sizeof lf);
244 lf.lfCharSet = ANSI_CHARSET;
245 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
246 lf.lfWeight = FW_DONTCARE;
247 lf.lfHeight = 16;
248 lf.lfWidth = 16;
249 lf.lfQuality = DEFAULT_QUALITY;
251 lstrcpyA(lf.lfFaceName, "Arial");
252 hfont = create_font("Arial", &lf);
253 DeleteObject(hfont);
255 memset(&lf, 'A', sizeof(lf));
256 hfont = CreateFontIndirectA(&lf);
257 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
259 lf.lfFaceName[LF_FACESIZE - 1] = 0;
260 check_font("AAA...", &lf, hfont);
261 DeleteObject(hfont);
264 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
266 if (type & RASTER_FONTTYPE)
268 LOGFONTA *lf = (LOGFONTA *)lParam;
269 *lf = *elf;
270 return 0; /* stop enumeration */
273 return 1; /* continue enumeration */
276 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
278 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
279 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
280 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
281 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
282 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
283 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
284 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
285 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
286 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
287 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
288 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
289 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
290 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
291 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
292 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
293 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
294 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
295 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
296 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
297 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
300 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
301 LONG lfWidth, const char *test_str,
302 INT test_str_len, const TEXTMETRICA *tm_orig,
303 const SIZE *size_orig, INT width_of_A_orig,
304 INT scale_x, INT scale_y)
306 LOGFONTA lf;
307 OUTLINETEXTMETRICA otm;
308 TEXTMETRICA tm;
309 SIZE size;
310 INT width_of_A, cx, cy;
311 UINT ret;
313 if (!hfont)
314 return;
316 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
318 GetObjectA(hfont, sizeof(lf), &lf);
320 if (GetOutlineTextMetricsA(hdc, 0, NULL))
322 otm.otmSize = sizeof(otm) / 2;
323 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
324 ok(ret == sizeof(otm)/2 /* XP */ ||
325 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
327 memset(&otm, 0x1, sizeof(otm));
328 otm.otmSize = sizeof(otm);
329 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
330 ok(ret == sizeof(otm) /* XP */ ||
331 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
333 memset(&tm, 0x2, sizeof(tm));
334 ret = GetTextMetricsA(hdc, &tm);
335 ok(ret, "GetTextMetricsA failed\n");
336 /* the structure size is aligned */
337 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
339 ok(0, "tm != otm\n");
340 compare_tm(&tm, &otm.otmTextMetrics);
343 tm = otm.otmTextMetrics;
344 if (0) /* these metrics are scaled too, but with rounding errors */
346 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
347 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
349 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
350 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
351 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
352 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
353 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
354 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
356 else
358 ret = GetTextMetricsA(hdc, &tm);
359 ok(ret, "GetTextMetricsA failed\n");
362 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
363 cy = tm.tmHeight / tm_orig->tmHeight;
364 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
365 lfHeight, scale_x, scale_y, cx, cy);
366 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
367 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
368 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
369 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
370 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
372 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
373 if (lf.lfHeight)
375 if (lf.lfWidth)
376 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
378 else
379 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
381 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
383 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
384 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
386 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
388 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
391 /* Test how GDI scales bitmap font metrics */
392 static void test_bitmap_font(void)
394 static const char test_str[11] = "Test String";
395 HDC hdc;
396 LOGFONTA bitmap_lf;
397 HFONT hfont, old_hfont;
398 TEXTMETRICA tm_orig;
399 SIZE size_orig;
400 INT ret, i, width_orig, height_orig, scale, lfWidth;
402 hdc = CreateCompatibleDC(0);
404 /* "System" has only 1 pixel size defined, otherwise the test breaks */
405 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
406 if (ret)
408 ReleaseDC(0, hdc);
409 trace("no bitmap fonts were found, skipping the test\n");
410 return;
413 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
415 height_orig = bitmap_lf.lfHeight;
416 lfWidth = bitmap_lf.lfWidth;
418 hfont = create_font("bitmap", &bitmap_lf);
419 old_hfont = SelectObject(hdc, hfont);
420 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
421 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
422 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
423 SelectObject(hdc, old_hfont);
424 DeleteObject(hfont);
426 bitmap_lf.lfHeight = 0;
427 bitmap_lf.lfWidth = 4;
428 hfont = create_font("bitmap", &bitmap_lf);
429 old_hfont = SelectObject(hdc, hfont);
430 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
431 SelectObject(hdc, old_hfont);
432 DeleteObject(hfont);
434 bitmap_lf.lfHeight = height_orig;
435 bitmap_lf.lfWidth = lfWidth;
437 /* test fractional scaling */
438 for (i = 1; i <= height_orig * 6; i++)
440 INT nearest_height;
442 bitmap_lf.lfHeight = i;
443 hfont = create_font("fractional", &bitmap_lf);
444 scale = (i + height_orig - 1) / height_orig;
445 nearest_height = scale * height_orig;
446 /* Only jump to the next height if the difference <= 25% original height */
447 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
448 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
449 so we'll not test this particular height. */
450 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
451 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
452 old_hfont = SelectObject(hdc, hfont);
453 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
454 SelectObject(hdc, old_hfont);
455 DeleteObject(hfont);
458 /* test integer scaling 3x2 */
459 bitmap_lf.lfHeight = height_orig * 2;
460 bitmap_lf.lfWidth *= 3;
461 hfont = create_font("3x2", &bitmap_lf);
462 old_hfont = SelectObject(hdc, hfont);
463 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
464 SelectObject(hdc, old_hfont);
465 DeleteObject(hfont);
467 /* test integer scaling 3x3 */
468 bitmap_lf.lfHeight = height_orig * 3;
469 bitmap_lf.lfWidth = 0;
470 hfont = create_font("3x3", &bitmap_lf);
471 old_hfont = SelectObject(hdc, hfont);
472 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
473 SelectObject(hdc, old_hfont);
474 DeleteObject(hfont);
476 DeleteDC(hdc);
479 /* Test how GDI scales outline font metrics */
480 static void test_outline_font(void)
482 static const char test_str[11] = "Test String";
483 HDC hdc, hdc_2;
484 LOGFONTA lf;
485 HFONT hfont, old_hfont, old_hfont_2;
486 OUTLINETEXTMETRICA otm;
487 SIZE size_orig;
488 INT width_orig, height_orig, lfWidth;
489 XFORM xform;
490 GLYPHMETRICS gm;
491 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
492 POINT pt;
493 INT ret;
495 if (!is_truetype_font_installed("Arial"))
497 skip("Arial is not installed\n");
498 return;
501 hdc = CreateCompatibleDC(0);
503 memset(&lf, 0, sizeof(lf));
504 strcpy(lf.lfFaceName, "Arial");
505 lf.lfHeight = 72;
506 hfont = create_font("outline", &lf);
507 old_hfont = SelectObject(hdc, hfont);
508 otm.otmSize = sizeof(otm);
509 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
510 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
511 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
513 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
514 SelectObject(hdc, old_hfont);
515 DeleteObject(hfont);
517 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
518 lf.lfHeight = otm.otmEMSquare;
519 lf.lfHeight = -lf.lfHeight;
520 hfont = create_font("outline", &lf);
521 old_hfont = SelectObject(hdc, hfont);
522 otm.otmSize = sizeof(otm);
523 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
524 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
525 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
526 SelectObject(hdc, old_hfont);
527 DeleteObject(hfont);
529 height_orig = otm.otmTextMetrics.tmHeight;
530 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
532 /* test integer scaling 3x2 */
533 lf.lfHeight = height_orig * 2;
534 lf.lfWidth = lfWidth * 3;
535 hfont = create_font("3x2", &lf);
536 old_hfont = SelectObject(hdc, hfont);
537 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
538 SelectObject(hdc, old_hfont);
539 DeleteObject(hfont);
541 /* test integer scaling 3x3 */
542 lf.lfHeight = height_orig * 3;
543 lf.lfWidth = lfWidth * 3;
544 hfont = create_font("3x3", &lf);
545 old_hfont = SelectObject(hdc, hfont);
546 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
547 SelectObject(hdc, old_hfont);
548 DeleteObject(hfont);
550 /* test integer scaling 1x1 */
551 lf.lfHeight = height_orig * 1;
552 lf.lfWidth = lfWidth * 1;
553 hfont = create_font("1x1", &lf);
554 old_hfont = SelectObject(hdc, hfont);
555 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 SelectObject(hdc, old_hfont);
557 DeleteObject(hfont);
559 /* test integer scaling 1x1 */
560 lf.lfHeight = height_orig;
561 lf.lfWidth = 0;
562 hfont = create_font("1x1", &lf);
563 old_hfont = SelectObject(hdc, hfont);
564 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
566 /* with an identity matrix */
567 memset(&gm, 0, sizeof(gm));
568 SetLastError(0xdeadbeef);
569 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
570 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
571 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
572 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
573 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
574 /* with a custom matrix */
575 memset(&gm, 0, sizeof(gm));
576 SetLastError(0xdeadbeef);
577 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
578 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
580 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
581 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
585 * another DC.
587 hdc_2 = CreateCompatibleDC(0);
588 old_hfont_2 = SelectObject(hdc_2, hfont);
589 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
591 SetMapMode(hdc, MM_ANISOTROPIC);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc, 100, 100, NULL);
601 SetViewportExtEx(hdc, 50, 100, NULL);
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc, 100, 200, NULL);
611 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc, MM_TEXT);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 SelectObject(hdc_2, old_hfont_2);
622 DeleteDC(hdc_2);
624 if (!SetGraphicsMode(hdc, GM_ADVANCED))
626 SelectObject(hdc, old_hfont);
627 DeleteObject(hfont);
628 DeleteDC(hdc);
629 skip("GM_ADVANCED is not supported on this platform\n");
630 return;
633 xform.eM11 = 20.0f;
634 xform.eM12 = 0.0f;
635 xform.eM21 = 0.0f;
636 xform.eM22 = 20.0f;
637 xform.eDx = 0.0f;
638 xform.eDy = 0.0f;
640 SetLastError(0xdeadbeef);
641 ret = SetWorldTransform(hdc, &xform);
642 ok(ret, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
646 /* with an identity matrix */
647 memset(&gm, 0, sizeof(gm));
648 SetLastError(0xdeadbeef);
649 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
650 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
651 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
652 pt.x = width_orig; pt.y = 0;
653 LPtoDP(hdc, &pt, 1);
654 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
655 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
656 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
657 /* with a custom matrix */
658 memset(&gm, 0, sizeof(gm));
659 SetLastError(0xdeadbeef);
660 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
661 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
662 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
663 pt.x = width_orig; pt.y = 0;
664 LPtoDP(hdc, &pt, 1);
665 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
666 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
667 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
669 SetLastError(0xdeadbeef);
670 ret = SetMapMode(hdc, MM_LOMETRIC);
671 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
673 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
675 /* with an identity matrix */
676 memset(&gm, 0, sizeof(gm));
677 SetLastError(0xdeadbeef);
678 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
679 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
680 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
681 pt.x = width_orig; pt.y = 0;
682 LPtoDP(hdc, &pt, 1);
683 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
684 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
685 /* with a custom matrix */
686 memset(&gm, 0, sizeof(gm));
687 SetLastError(0xdeadbeef);
688 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
689 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
690 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
691 pt.x = width_orig; pt.y = 0;
692 LPtoDP(hdc, &pt, 1);
693 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
694 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
696 SetLastError(0xdeadbeef);
697 ret = SetMapMode(hdc, MM_TEXT);
698 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
700 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
702 /* with an identity matrix */
703 memset(&gm, 0, sizeof(gm));
704 SetLastError(0xdeadbeef);
705 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
706 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
708 pt.x = width_orig; pt.y = 0;
709 LPtoDP(hdc, &pt, 1);
710 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
711 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
712 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
713 /* with a custom matrix */
714 memset(&gm, 0, sizeof(gm));
715 SetLastError(0xdeadbeef);
716 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
717 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
718 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
719 pt.x = width_orig; pt.y = 0;
720 LPtoDP(hdc, &pt, 1);
721 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
722 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
723 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
725 SelectObject(hdc, old_hfont);
726 DeleteObject(hfont);
727 DeleteDC(hdc);
730 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
732 LOGFONTA *lf = (LOGFONTA *)lParam;
734 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
736 *lf = *elf;
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL is_CJK(void)
744 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const struct font_data
752 const char face_name[LF_FACESIZE];
753 int weight, height, ascent, descent, int_leading, ext_leading;
754 int ave_char_width, max_char_width, dpi;
755 BYTE first_char, last_char, def_char, break_char;
756 DWORD ansi_bitfield;
757 WORD skip_lang_id;
758 int scaled_height;
759 } fd[] =
761 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
762 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
763 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
764 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
765 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
766 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
767 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
768 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
769 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 16 },
770 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
772 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
773 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
775 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
777 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
778 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
781 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
783 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
784 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
785 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
786 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
787 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
788 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
789 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
790 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
791 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
792 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
793 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
794 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
795 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
796 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
797 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
798 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
800 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
801 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
802 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
803 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
804 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
805 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
806 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
807 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
808 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
809 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
813 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
814 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
815 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
816 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
817 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
818 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
819 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
820 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
822 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
823 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
824 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
826 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
827 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
828 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
831 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
833 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
834 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
835 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
836 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
837 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
838 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
839 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
840 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
841 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
843 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
844 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
845 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
847 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
848 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
849 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
851 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
852 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
853 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
855 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
856 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
858 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
859 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
860 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
861 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
862 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
863 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
864 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
865 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
866 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
867 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
868 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
869 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
870 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
871 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
872 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
873 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
874 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
875 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
876 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
877 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
878 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
880 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
881 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
882 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
883 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
884 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
885 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
886 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
887 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
888 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
889 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
890 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
891 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
893 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
894 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
895 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
897 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
899 /* FIXME: add "Terminal" */
901 static const int font_log_pixels[] = { 96, 120 };
902 HDC hdc;
903 LOGFONTA lf;
904 HFONT hfont, old_hfont;
905 TEXTMETRICA tm;
906 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
907 char face_name[LF_FACESIZE];
908 CHARSETINFO csi;
910 trace("system language id %04x\n", system_lang_id);
912 expected_cs = GetACP();
913 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
915 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
916 return;
918 expected_cs = csi.ciCharset;
919 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
921 hdc = CreateCompatibleDC(0);
922 assert(hdc);
924 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
925 GetDeviceCaps(hdc, LOGPIXELSY));
927 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
928 diff = 32768;
929 font_res = 0;
930 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
932 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
933 if (new_diff < diff)
935 diff = new_diff;
936 font_res = font_log_pixels[i];
939 trace("best font resolution is %d\n", font_res);
941 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
943 int bit, height;
945 memset(&lf, 0, sizeof(lf));
947 height = fd[i].height & ~FH_SCALE;
948 lf.lfHeight = height;
949 strcpy(lf.lfFaceName, fd[i].face_name);
951 for(bit = 0; bit < 32; bit++)
953 GLYPHMETRICS gm;
954 DWORD fs[2];
955 BOOL bRet;
957 fs[0] = 1L << bit;
958 fs[1] = 0;
959 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
960 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
962 lf.lfCharSet = csi.ciCharset;
963 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
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 if (ret) /* FIXME: Remove once Wine is fixed */
972 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
973 else
974 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
977 if (ret && !(fd[i].height & FH_SCALE))
978 continue;
980 hfont = create_font(lf.lfFaceName, &lf);
981 old_hfont = SelectObject(hdc, hfont);
983 SetLastError(0xdeadbeef);
984 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
985 ok(ret, "GetTextFace error %u\n", GetLastError());
987 if (strcmp(face_name, fd[i].face_name) != 0)
989 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
990 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
991 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
992 SelectObject(hdc, old_hfont);
993 DeleteObject(hfont);
994 continue;
997 memset(&gm, 0, sizeof(gm));
998 SetLastError(0xdeadbeef);
999 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1000 todo_wine {
1001 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1002 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1005 bRet = GetTextMetricsA(hdc, &tm);
1006 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1008 SetLastError(0xdeadbeef);
1009 ret = GetTextCharset(hdc);
1010 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1011 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1012 else
1013 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1015 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1016 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1018 if(fd[i].dpi == tm.tmDigitizedAspectX)
1020 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1021 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
1023 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1024 if (fd[i].height & FH_SCALE)
1025 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);
1026 else
1027 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);
1028 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1029 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1030 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);
1031 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);
1032 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);
1033 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1034 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1035 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1036 make default char test fail */
1037 if (tm.tmCharSet == lf.lfCharSet)
1038 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1039 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1040 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);
1042 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1043 that make the max width bigger */
1044 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1045 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);
1047 else
1048 skip("Skipping font metrics test for system langid 0x%x\n",
1049 system_lang_id);
1051 SelectObject(hdc, old_hfont);
1052 DeleteObject(hfont);
1056 DeleteDC(hdc);
1059 static void test_GdiGetCharDimensions(void)
1061 HDC hdc;
1062 TEXTMETRICW tm;
1063 LONG ret;
1064 SIZE size;
1065 LONG avgwidth, height;
1066 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1068 if (!pGdiGetCharDimensions)
1070 win_skip("GdiGetCharDimensions not available on this platform\n");
1071 return;
1074 hdc = CreateCompatibleDC(NULL);
1076 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1077 avgwidth = ((size.cx / 26) + 1) / 2;
1079 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1080 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1081 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1083 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1084 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1086 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1087 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1089 height = 0;
1090 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1091 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1092 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1094 DeleteDC(hdc);
1097 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1098 const TEXTMETRICA *lpntme,
1099 DWORD FontType, LPARAM lParam)
1101 if (FontType & TRUETYPE_FONTTYPE)
1103 HFONT hfont;
1105 hfont = CreateFontIndirectA(lpelfe);
1106 if (hfont)
1108 *(HFONT *)lParam = hfont;
1109 return 0;
1113 return 1;
1116 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1118 ABC abc[1];
1119 ABCFLOAT abcf[1];
1120 BOOL ret = FALSE;
1122 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1123 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1124 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1125 if (todo) todo_wine ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1126 else ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1127 if (todo) todo_wine ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1128 else ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1130 ret = pGetCharABCWidthsW(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 if (todo) todo_wine ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1134 else ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1135 if (todo) todo_wine ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1136 else ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's should be unchanged\n", description);
1138 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1139 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1140 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1141 if (todo) todo_wine ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1142 else ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's should be unchanged\n", description);
1143 if (todo) todo_wine ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1144 else ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1147 static void test_GetCharABCWidths(void)
1149 static const WCHAR str[] = {'i',0};
1150 BOOL ret;
1151 HDC hdc;
1152 LOGFONTA lf;
1153 HFONT hfont;
1154 ABC abc[1];
1155 ABC abcw[1];
1156 ABCFLOAT abcf[1];
1157 WORD glyphs[1];
1158 DWORD nb;
1159 HWND hwnd;
1160 static const struct
1162 UINT first;
1163 UINT last;
1164 } range[] =
1166 {0xff, 0xff},
1167 {0x100, 0x100},
1168 {0xff, 0x100},
1169 {0x1ff, 0xff00},
1170 {0xffff, 0xffff},
1171 {0x10000, 0x10000},
1172 {0xffff, 0x10000},
1173 {0xffffff, 0xffffff},
1174 {0x1000000, 0x1000000},
1175 {0xffffff, 0x1000000},
1176 {0xffffffff, 0xffffffff},
1177 {0x00, 0xff}
1179 static const struct
1181 UINT cs;
1182 UINT a;
1183 UINT w;
1184 BOOL r[sizeof range / sizeof range[0]];
1185 } c[] =
1187 {ANSI_CHARSET, 0x30, 0x30,
1188 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1189 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1190 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1191 {HANGEUL_CHARSET, 0x8141, 0xac02,
1192 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1193 {GB2312_CHARSET, 0x8141, 0x4e04,
1194 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1195 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1196 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1198 UINT i;
1200 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1202 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1203 return;
1206 memset(&lf, 0, sizeof(lf));
1207 strcpy(lf.lfFaceName, "System");
1208 lf.lfHeight = 20;
1210 hfont = CreateFontIndirectA(&lf);
1211 hdc = GetDC(0);
1212 hfont = SelectObject(hdc, hfont);
1214 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1215 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1217 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1218 ok(!ret, "GetCharABCWidthsI should have failed\n");
1220 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1221 ok(!ret, "GetCharABCWidthsI should have failed\n");
1223 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1224 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1226 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1227 ok(!ret, "GetCharABCWidthsW should have failed\n");
1229 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1230 ok(!ret, "GetCharABCWidthsW should have failed\n");
1232 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1233 ok(!ret, "GetCharABCWidthsW should have failed\n");
1235 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1236 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1238 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1239 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1241 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1242 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1244 hfont = SelectObject(hdc, hfont);
1245 DeleteObject(hfont);
1247 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1249 ABC a[2], w[2];
1250 ABC full[256];
1251 UINT code = 0x41, j;
1253 lf.lfFaceName[0] = '\0';
1254 lf.lfCharSet = c[i].cs;
1255 lf.lfPitchAndFamily = 0;
1256 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1258 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1259 continue;
1262 memset(a, 0, sizeof a);
1263 memset(w, 0, sizeof w);
1264 hfont = SelectObject(hdc, hfont);
1265 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1266 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1267 memcmp(a, w, sizeof a) == 0,
1268 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1270 memset(a, 0xbb, sizeof a);
1271 ret = pGetCharABCWidthsA(hdc, code, code, a);
1272 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1273 memset(full, 0xcc, sizeof full);
1274 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1275 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1276 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1277 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1279 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1281 memset(full, 0xdd, sizeof full);
1282 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1283 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1284 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1285 if (ret)
1287 UINT last = range[j].last - range[j].first;
1288 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1289 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1290 "GetCharABCWidthsA %x should match. codepage = %u\n",
1291 range[j].last, c[i].cs);
1295 hfont = SelectObject(hdc, hfont);
1296 DeleteObject(hfont);
1299 memset(&lf, 0, sizeof(lf));
1300 strcpy(lf.lfFaceName, "Tahoma");
1301 lf.lfHeight = 200;
1302 hfont = CreateFontIndirectA(&lf);
1304 /* test empty glyph's metrics */
1305 hfont = SelectObject(hdc, hfont);
1306 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1307 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1308 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1309 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1310 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1311 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1313 /* 1) prepare unrotated font metrics */
1314 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1315 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1316 DeleteObject(SelectObject(hdc, hfont));
1318 /* 2) get rotated font metrics */
1319 lf.lfEscapement = lf.lfOrientation = 900;
1320 hfont = CreateFontIndirectA(&lf);
1321 hfont = SelectObject(hdc, hfont);
1322 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1323 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1325 /* 3) compare ABC results */
1326 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1327 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1328 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1329 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1330 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1331 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1333 DeleteObject(SelectObject(hdc, hfont));
1334 ReleaseDC(NULL, hdc);
1336 trace("ABC sign test for a variety of transforms:\n");
1337 memset(&lf, 0, sizeof(lf));
1338 strcpy(lf.lfFaceName, "Tahoma");
1339 lf.lfHeight = 20;
1340 hfont = CreateFontIndirectA(&lf);
1341 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1342 0, 0, 0, NULL);
1343 hdc = GetDC(hwnd);
1344 SetMapMode(hdc, MM_ANISOTROPIC);
1345 SelectObject(hdc, hfont);
1347 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1348 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1350 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1351 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1352 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1353 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1354 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1355 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1357 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1358 SetWindowExtEx(hdc, -1, -1, NULL);
1359 SetGraphicsMode(hdc, GM_COMPATIBLE);
1360 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1361 SetGraphicsMode(hdc, GM_ADVANCED);
1362 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1363 SetWindowExtEx(hdc, 1, 1, NULL);
1364 SetGraphicsMode(hdc, GM_COMPATIBLE);
1365 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1366 SetGraphicsMode(hdc, GM_ADVANCED);
1367 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1369 ReleaseDC(hwnd, hdc);
1370 DestroyWindow(hwnd);
1372 trace("RTL layout\n");
1373 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1374 0, 0, 0, NULL);
1375 hdc = GetDC(hwnd);
1376 SetMapMode(hdc, MM_ANISOTROPIC);
1377 SelectObject(hdc, hfont);
1379 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1380 SetWindowExtEx(hdc, -1, -1, NULL);
1381 SetGraphicsMode(hdc, GM_COMPATIBLE);
1382 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1383 SetGraphicsMode(hdc, GM_ADVANCED);
1384 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1385 SetWindowExtEx(hdc, 1, 1, NULL);
1386 SetGraphicsMode(hdc, GM_COMPATIBLE);
1387 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1388 SetGraphicsMode(hdc, GM_ADVANCED);
1389 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1391 ReleaseDC(hwnd, hdc);
1392 DestroyWindow(hwnd);
1393 DeleteObject(hfont);
1396 static void test_text_extents(void)
1398 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1399 LPINT extents;
1400 INT i, len, fit1, fit2, extents2[3];
1401 LOGFONTA lf;
1402 TEXTMETRICA tm;
1403 HDC hdc;
1404 HFONT hfont;
1405 SIZE sz;
1406 SIZE sz1, sz2;
1407 BOOL ret;
1409 memset(&lf, 0, sizeof(lf));
1410 strcpy(lf.lfFaceName, "Arial");
1411 lf.lfHeight = 20;
1413 hfont = CreateFontIndirectA(&lf);
1414 hdc = GetDC(0);
1415 hfont = SelectObject(hdc, hfont);
1416 GetTextMetricsA(hdc, &tm);
1417 GetTextExtentPointA(hdc, "o", 1, &sz);
1418 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1420 SetLastError(0xdeadbeef);
1421 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1422 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1424 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1425 hfont = SelectObject(hdc, hfont);
1426 DeleteObject(hfont);
1427 ReleaseDC(0, hdc);
1428 return;
1431 len = lstrlenW(wt);
1432 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1433 extents[0] = 1; /* So that the increasing sequence test will fail
1434 if the extents array is untouched. */
1435 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1436 GetTextExtentPointW(hdc, wt, len, &sz2);
1437 ok(sz1.cy == sz2.cy,
1438 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1439 /* Because of the '\n' in the string GetTextExtentExPoint and
1440 GetTextExtentPoint return different widths under Win2k, but
1441 under WinXP they return the same width. So we don't test that
1442 here. */
1444 for (i = 1; i < len; ++i)
1445 ok(extents[i-1] <= extents[i],
1446 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1448 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1449 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1450 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1451 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1452 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1453 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1455 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1456 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1457 ok(extents[0] == extents[2] && extents[1] == extents[3],
1458 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1459 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1460 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1461 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1463 /* extents functions fail with -ve counts (the interesting case being -1) */
1464 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1465 ok(ret == FALSE, "got %d\n", ret);
1466 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1467 ok(ret == FALSE, "got %d\n", ret);
1468 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1469 ok(ret == FALSE, "got %d\n", ret);
1471 /* max_extent = 0 succeeds and returns zero */
1472 fit1 = fit2 = -215;
1473 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1474 ok(ret == TRUE ||
1475 broken(ret == FALSE), /* NT4, 2k */
1476 "got %d\n", ret);
1477 ok(fit1 == 0 ||
1478 broken(fit1 == -215), /* NT4, 2k */
1479 "fit = %d\n", fit1);
1480 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1481 ok(ret == TRUE, "got %d\n", ret);
1482 ok(fit2 == 0, "fit = %d\n", fit2);
1484 /* max_extent = -1 is interpreted as a very large width that will
1485 * definitely fit our three characters */
1486 fit1 = fit2 = -215;
1487 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1488 ok(ret == TRUE, "got %d\n", ret);
1489 ok(fit1 == 3, "fit = %d\n", fit1);
1490 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1491 ok(ret == TRUE, "got %d\n", ret);
1492 ok(fit2 == 3, "fit = %d\n", fit2);
1494 /* max_extent = -2 is interpreted similarly, but the Ansi version
1495 * rejects it while the Unicode one accepts it */
1496 fit1 = fit2 = -215;
1497 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1498 ok(ret == FALSE, "got %d\n", ret);
1499 ok(fit1 == -215, "fit = %d\n", fit1);
1500 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1501 ok(ret == TRUE, "got %d\n", ret);
1502 ok(fit2 == 3, "fit = %d\n", fit2);
1504 hfont = SelectObject(hdc, hfont);
1505 DeleteObject(hfont);
1507 /* non-MM_TEXT mapping mode */
1508 lf.lfHeight = 2000;
1509 hfont = CreateFontIndirectA(&lf);
1510 hfont = SelectObject(hdc, hfont);
1512 SetMapMode( hdc, MM_HIMETRIC );
1513 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1514 ok(ret, "got %d\n", ret);
1515 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1517 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1518 ok(ret, "got %d\n", ret);
1519 ok(fit1 == 2, "got %d\n", fit1);
1520 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1521 for(i = 0; i < 2; i++)
1522 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1524 hfont = SelectObject(hdc, hfont);
1525 DeleteObject(hfont);
1526 HeapFree(GetProcessHeap(), 0, extents);
1527 ReleaseDC(NULL, hdc);
1530 static void test_GetGlyphIndices(void)
1532 HDC hdc;
1533 HFONT hfont;
1534 DWORD charcount;
1535 LOGFONTA lf;
1536 DWORD flags = 0;
1537 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1538 WORD glyphs[(sizeof(testtext)/2)-1];
1539 TEXTMETRICA textm;
1540 HFONT hOldFont;
1542 if (!pGetGlyphIndicesW) {
1543 win_skip("GetGlyphIndicesW not available on platform\n");
1544 return;
1547 hdc = GetDC(0);
1549 memset(&lf, 0, sizeof(lf));
1550 strcpy(lf.lfFaceName, "System");
1551 lf.lfHeight = 16;
1552 lf.lfCharSet = ANSI_CHARSET;
1554 hfont = CreateFontIndirectA(&lf);
1555 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1556 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1557 if (textm.tmCharSet == ANSI_CHARSET)
1559 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1560 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1561 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1562 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1563 flags = 0;
1564 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1565 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1566 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1567 textm.tmDefaultChar, glyphs[4]);
1569 else
1570 /* FIXME: Write tests for non-ANSI charsets. */
1571 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1573 if(!is_font_installed("Tahoma"))
1575 skip("Tahoma is not installed so skipping this test\n");
1576 return;
1578 memset(&lf, 0, sizeof(lf));
1579 strcpy(lf.lfFaceName, "Tahoma");
1580 lf.lfHeight = 20;
1582 hfont = CreateFontIndirectA(&lf);
1583 hOldFont = SelectObject(hdc, hfont);
1584 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1585 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1586 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1587 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1588 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1589 flags = 0;
1590 testtext[0] = textm.tmDefaultChar;
1591 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1592 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1593 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1594 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1595 DeleteObject(SelectObject(hdc, hOldFont));
1598 static void test_GetKerningPairs(void)
1600 static const struct kerning_data
1602 const char face_name[LF_FACESIZE];
1603 LONG height;
1604 /* some interesting fields from OUTLINETEXTMETRIC */
1605 LONG tmHeight, tmAscent, tmDescent;
1606 UINT otmEMSquare;
1607 INT otmAscent;
1608 INT otmDescent;
1609 UINT otmLineGap;
1610 UINT otmsCapEmHeight;
1611 UINT otmsXHeight;
1612 INT otmMacAscent;
1613 INT otmMacDescent;
1614 UINT otmMacLineGap;
1615 UINT otmusMinimumPPEM;
1616 /* small subset of kerning pairs to test */
1617 DWORD total_kern_pairs;
1618 const KERNINGPAIR kern_pair[26];
1619 } kd[] =
1621 {"Arial", 12, 12, 9, 3,
1622 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1625 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1626 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1627 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1628 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1629 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1630 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1631 {933,970,+1},{933,972,-1}
1634 {"Arial", -34, 39, 32, 7,
1635 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1638 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1639 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1640 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1641 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1642 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1643 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1644 {933,970,+2},{933,972,-3}
1647 { "Arial", 120, 120, 97, 23,
1648 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1651 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1652 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1653 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1654 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1655 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1656 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1657 {933,970,+6},{933,972,-10}
1660 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1661 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1662 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1665 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1666 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1667 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1668 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1669 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1670 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1671 {933,970,+54},{933,972,-83}
1674 #endif
1676 LOGFONTA lf;
1677 HFONT hfont, hfont_old;
1678 KERNINGPAIR *kern_pair;
1679 HDC hdc;
1680 DWORD total_kern_pairs, ret, i, n, matches;
1682 hdc = GetDC(0);
1684 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1685 * which may render this test unusable, so we're trying to avoid that.
1687 SetLastError(0xdeadbeef);
1688 GetKerningPairsW(hdc, 0, NULL);
1689 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1691 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1692 ReleaseDC(0, hdc);
1693 return;
1696 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1698 OUTLINETEXTMETRICW otm;
1699 UINT uiRet;
1701 if (!is_font_installed(kd[i].face_name))
1703 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1704 continue;
1707 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1709 memset(&lf, 0, sizeof(lf));
1710 strcpy(lf.lfFaceName, kd[i].face_name);
1711 lf.lfHeight = kd[i].height;
1712 hfont = CreateFontIndirectA(&lf);
1713 assert(hfont != 0);
1715 hfont_old = SelectObject(hdc, hfont);
1717 SetLastError(0xdeadbeef);
1718 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1719 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1720 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1722 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1723 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1724 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1725 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1726 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1727 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1729 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1730 kd[i].otmEMSquare, otm.otmEMSquare);
1731 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1732 kd[i].otmAscent, otm.otmAscent);
1733 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1734 kd[i].otmDescent, otm.otmDescent);
1735 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1736 kd[i].otmLineGap, otm.otmLineGap);
1737 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1738 kd[i].otmMacDescent, otm.otmMacDescent);
1739 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1740 kd[i].otmMacAscent, otm.otmMacAscent);
1741 todo_wine {
1742 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1743 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1744 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1745 kd[i].otmsXHeight, otm.otmsXHeight);
1746 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1747 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1748 kd[i].otmMacLineGap, otm.otmMacLineGap);
1749 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1750 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1753 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1754 trace("total_kern_pairs %u\n", total_kern_pairs);
1755 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1757 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1758 * passes on XP.
1760 SetLastError(0xdeadbeef);
1761 ret = GetKerningPairsW(hdc, 0, kern_pair);
1762 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1763 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1764 ok(ret == 0, "got %u, expected 0\n", ret);
1766 ret = GetKerningPairsW(hdc, 100, NULL);
1767 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1769 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1770 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1772 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1773 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1775 matches = 0;
1777 for (n = 0; n < ret; n++)
1779 DWORD j;
1780 /* Disabled to limit console spam */
1781 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1782 trace("{'%c','%c',%d},\n",
1783 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1784 for (j = 0; j < kd[i].total_kern_pairs; j++)
1786 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1787 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1789 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1790 "pair %d:%d got %d, expected %d\n",
1791 kern_pair[n].wFirst, kern_pair[n].wSecond,
1792 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1793 matches++;
1798 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1799 matches, kd[i].total_kern_pairs);
1801 HeapFree(GetProcessHeap(), 0, kern_pair);
1803 SelectObject(hdc, hfont_old);
1804 DeleteObject(hfont);
1807 ReleaseDC(0, hdc);
1810 struct font_data
1812 const char face_name[LF_FACESIZE];
1813 int requested_height;
1814 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1815 BOOL exact;
1818 static void test_height( HDC hdc, const struct font_data *fd )
1820 LOGFONTA lf;
1821 HFONT hfont, old_hfont;
1822 TEXTMETRICA tm;
1823 INT ret, i;
1825 for (i = 0; fd[i].face_name[0]; i++)
1827 if (!is_truetype_font_installed(fd[i].face_name))
1829 skip("%s is not installed\n", fd[i].face_name);
1830 continue;
1833 memset(&lf, 0, sizeof(lf));
1834 lf.lfHeight = fd[i].requested_height;
1835 lf.lfWeight = fd[i].weight;
1836 strcpy(lf.lfFaceName, fd[i].face_name);
1838 hfont = CreateFontIndirectA(&lf);
1839 assert(hfont);
1841 old_hfont = SelectObject(hdc, hfont);
1842 ret = GetTextMetricsA(hdc, &tm);
1843 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1844 if(fd[i].dpi == tm.tmDigitizedAspectX)
1846 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1847 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);
1848 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);
1849 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);
1850 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);
1851 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);
1852 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);
1855 SelectObject(hdc, old_hfont);
1856 DeleteObject(hfont);
1860 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1862 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1863 DWORD *table = (DWORD *)ttf + 3;
1865 for (i = 0; i < num_tables; i++)
1867 if (table[0] == tag)
1868 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1869 table += 4;
1871 return NULL;
1874 static void test_height_selection_vdmx( HDC hdc )
1876 static const struct font_data charset_0[] = /* doesn't use VDMX */
1878 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1879 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1880 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1881 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1882 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1883 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1884 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1885 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1886 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1887 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1888 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1889 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1890 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1891 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1892 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1893 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1894 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1895 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1896 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1897 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1898 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1899 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1900 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1901 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1902 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1903 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1904 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1905 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1906 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1907 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1908 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1909 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1910 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1911 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1912 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1913 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1914 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1915 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1916 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1917 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1918 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1919 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1920 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1921 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1922 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1923 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1924 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1925 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1926 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1927 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1928 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1929 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1930 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1933 static const struct font_data charset_1[] = /* Uses VDMX */
1935 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1936 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1937 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1938 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1939 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1940 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1941 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1942 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1943 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1944 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1945 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1946 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1947 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1948 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1949 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1950 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1951 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1952 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1953 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1954 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1955 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1956 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1957 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1958 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
1959 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
1960 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
1961 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1962 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1963 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1964 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1965 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1966 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1967 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1968 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1969 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1970 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1971 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1972 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1973 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1974 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1975 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1976 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
1977 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
1978 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
1979 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
1980 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
1981 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
1982 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
1983 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
1984 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
1985 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
1986 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
1987 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1990 static const struct vdmx_data
1992 WORD version;
1993 BYTE bCharSet;
1994 const struct font_data *fd;
1995 } data[] =
1997 { 0, 0, charset_0 },
1998 { 0, 1, charset_1 },
1999 { 1, 0, charset_0 },
2000 { 1, 1, charset_1 }
2002 int i;
2003 DWORD size, num;
2004 WORD *vdmx_header;
2005 BYTE *ratio_rec;
2006 char ttf_name[MAX_PATH];
2007 void *res, *copy;
2009 if (!pAddFontResourceExA)
2011 win_skip("AddFontResourceExA unavailable\n");
2012 return;
2015 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2017 res = get_res_data( "wine_vdmx.ttf", &size );
2019 copy = HeapAlloc( GetProcessHeap(), 0, size );
2020 memcpy( copy, res, size );
2021 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2022 vdmx_header[0] = GET_BE_WORD( data[i].version );
2023 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2024 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2025 ratio_rec = (BYTE *)&vdmx_header[3];
2026 ratio_rec[0] = data[i].bCharSet;
2028 write_tmp_file( copy, &size, ttf_name );
2029 HeapFree( GetProcessHeap(), 0, copy );
2031 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2032 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2033 if (!num) win_skip("Unable to add ttf font resource\n");
2034 else
2036 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2037 test_height( hdc, data[i].fd );
2038 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2040 DeleteFileA( ttf_name );
2044 static void test_height_selection(void)
2046 static const struct font_data tahoma[] =
2048 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2049 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2050 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2051 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2052 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2053 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2054 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2055 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2056 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2057 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2058 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2060 HDC hdc = CreateCompatibleDC(0);
2061 assert(hdc);
2063 test_height( hdc, tahoma );
2064 test_height_selection_vdmx( hdc );
2066 DeleteDC(hdc);
2069 static void test_GetOutlineTextMetrics(void)
2071 OUTLINETEXTMETRICA *otm;
2072 LOGFONTA lf;
2073 HFONT hfont, hfont_old;
2074 HDC hdc;
2075 DWORD ret, otm_size;
2076 LPSTR unset_ptr;
2078 if (!is_font_installed("Arial"))
2080 skip("Arial is not installed\n");
2081 return;
2084 hdc = GetDC(0);
2086 memset(&lf, 0, sizeof(lf));
2087 strcpy(lf.lfFaceName, "Arial");
2088 lf.lfHeight = -13;
2089 lf.lfWeight = FW_NORMAL;
2090 lf.lfPitchAndFamily = DEFAULT_PITCH;
2091 lf.lfQuality = PROOF_QUALITY;
2092 hfont = CreateFontIndirectA(&lf);
2093 assert(hfont != 0);
2095 hfont_old = SelectObject(hdc, hfont);
2096 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2097 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2099 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2101 memset(otm, 0xAA, otm_size);
2102 SetLastError(0xdeadbeef);
2103 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2104 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2105 ok(ret == 1 /* Win9x */ ||
2106 ret == otm->otmSize /* XP*/,
2107 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2108 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2110 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2111 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2112 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2113 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2116 memset(otm, 0xAA, otm_size);
2117 SetLastError(0xdeadbeef);
2118 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2119 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2120 ok(ret == 1 /* Win9x */ ||
2121 ret == otm->otmSize /* XP*/,
2122 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2123 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2125 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2126 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2127 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2128 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2131 /* ask about truncated data */
2132 memset(otm, 0xAA, otm_size);
2133 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2134 SetLastError(0xdeadbeef);
2135 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2136 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2137 ok(ret == 1 /* Win9x */ ||
2138 ret == otm->otmSize /* XP*/,
2139 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2140 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2142 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2143 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2144 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2146 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2148 HeapFree(GetProcessHeap(), 0, otm);
2150 SelectObject(hdc, hfont_old);
2151 DeleteObject(hfont);
2153 ReleaseDC(0, hdc);
2156 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2158 INT y,
2159 breakCount,
2160 areaWidth = clientArea->right - clientArea->left,
2161 nErrors = 0, e;
2162 const char *pFirstChar, *pLastChar;
2163 SIZE size;
2164 TEXTMETRICA tm;
2165 struct err
2167 const char *start;
2168 int len;
2169 int GetTextExtentExPointWWidth;
2170 } error[20];
2172 GetTextMetricsA(hdc, &tm);
2173 y = clientArea->top;
2174 do {
2175 breakCount = 0;
2176 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2177 pFirstChar = str;
2179 do {
2180 pLastChar = str;
2182 /* if not at the end of the string, ... */
2183 if (*str == '\0') break;
2184 /* ... add the next word to the current extent */
2185 while (*str != '\0' && *str++ != tm.tmBreakChar);
2186 breakCount++;
2187 SetTextJustification(hdc, 0, 0);
2188 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2189 } while ((int) size.cx < areaWidth);
2191 /* ignore trailing break chars */
2192 breakCount--;
2193 while (*(pLastChar - 1) == tm.tmBreakChar)
2195 pLastChar--;
2196 breakCount--;
2199 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2201 SetTextJustification(hdc, 0, 0);
2202 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2204 /* do not justify the last extent */
2205 if (*str != '\0' && breakCount > 0)
2207 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2208 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2209 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2211 error[nErrors].start = pFirstChar;
2212 error[nErrors].len = pLastChar - pFirstChar;
2213 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2214 nErrors++;
2218 trace( "%u %.*s\n", size.cx, (int)(pLastChar - pFirstChar), pFirstChar);
2220 y += size.cy;
2221 str = pLastChar;
2222 } while (*str && y < clientArea->bottom);
2224 for (e = 0; e < nErrors; e++)
2226 /* The width returned by GetTextExtentPoint32() is exactly the same
2227 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2228 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2229 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2230 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2234 static void test_SetTextJustification(void)
2236 HDC hdc;
2237 RECT clientArea;
2238 LOGFONTA lf;
2239 HFONT hfont;
2240 HWND hwnd;
2241 SIZE size, expect;
2242 int i;
2243 WORD indices[2];
2244 static const char testText[] =
2245 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2246 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2247 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2248 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2249 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2250 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2251 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2253 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2254 GetClientRect( hwnd, &clientArea );
2255 hdc = GetDC( hwnd );
2257 if (!is_font_installed("Times New Roman"))
2259 skip("Times New Roman is not installed\n");
2260 return;
2263 memset(&lf, 0, sizeof lf);
2264 lf.lfCharSet = ANSI_CHARSET;
2265 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2266 lf.lfWeight = FW_DONTCARE;
2267 lf.lfHeight = 20;
2268 lf.lfQuality = DEFAULT_QUALITY;
2269 lstrcpyA(lf.lfFaceName, "Times New Roman");
2270 hfont = create_font("Times New Roman", &lf);
2271 SelectObject(hdc, hfont);
2273 testJustification(hdc, testText, &clientArea);
2275 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2276 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2278 SetTextJustification(hdc, 0, 0);
2279 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2280 GetTextExtentPoint32A(hdc, " ", 3, &size);
2281 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2282 SetTextJustification(hdc, 4, 1);
2283 GetTextExtentPoint32A(hdc, " ", 1, &size);
2284 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2285 SetTextJustification(hdc, 9, 2);
2286 GetTextExtentPoint32A(hdc, " ", 2, &size);
2287 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2288 SetTextJustification(hdc, 7, 3);
2289 GetTextExtentPoint32A(hdc, " ", 3, &size);
2290 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2291 SetTextJustification(hdc, 7, 3);
2292 SetTextCharacterExtra(hdc, 2 );
2293 GetTextExtentPoint32A(hdc, " ", 3, &size);
2294 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2295 SetTextJustification(hdc, 0, 0);
2296 SetTextCharacterExtra(hdc, 0);
2297 size.cx = size.cy = 1234;
2298 GetTextExtentPoint32A(hdc, " ", 0, &size);
2299 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2300 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2301 SetTextJustification(hdc, 5, 1);
2302 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2303 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2304 SetTextJustification(hdc, 0, 0);
2306 SetMapMode( hdc, MM_ANISOTROPIC );
2307 SetWindowExtEx( hdc, 2, 2, NULL );
2308 GetClientRect( hwnd, &clientArea );
2309 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2310 testJustification(hdc, testText, &clientArea);
2312 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2313 for (i = 0; i < 10; i++)
2315 SetTextCharacterExtra(hdc, i);
2316 GetTextExtentPoint32A(hdc, "A", 1, &size);
2317 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2319 SetTextCharacterExtra(hdc, 0);
2320 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2321 for (i = 0; i < 10; i++)
2323 SetTextCharacterExtra(hdc, i);
2324 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2325 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2327 SetTextCharacterExtra(hdc, 0);
2329 SetViewportExtEx( hdc, 3, 3, NULL );
2330 GetClientRect( hwnd, &clientArea );
2331 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2332 testJustification(hdc, testText, &clientArea);
2334 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2335 for (i = 0; i < 10; i++)
2337 SetTextCharacterExtra(hdc, i);
2338 GetTextExtentPoint32A(hdc, "A", 1, &size);
2339 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2342 done:
2343 DeleteObject(hfont);
2344 ReleaseDC(hwnd, hdc);
2345 DestroyWindow(hwnd);
2348 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2350 HDC hdc;
2351 LOGFONTA lf;
2352 HFONT hfont, hfont_old;
2353 CHARSETINFO csi;
2354 FONTSIGNATURE fs;
2355 INT cs;
2356 DWORD i, ret;
2357 char name[64];
2359 assert(count <= 128);
2361 memset(&lf, 0, sizeof(lf));
2363 lf.lfCharSet = charset;
2364 lf.lfHeight = 10;
2365 lstrcpyA(lf.lfFaceName, "Arial");
2366 SetLastError(0xdeadbeef);
2367 hfont = CreateFontIndirectA(&lf);
2368 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2370 hdc = GetDC(0);
2371 hfont_old = SelectObject(hdc, hfont);
2373 cs = GetTextCharsetInfo(hdc, &fs, 0);
2374 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2376 SetLastError(0xdeadbeef);
2377 ret = GetTextFaceA(hdc, sizeof(name), name);
2378 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2380 if (charset == SYMBOL_CHARSET)
2382 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2383 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
2385 else
2387 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2388 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2391 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2393 trace("Can't find codepage for charset %d\n", cs);
2394 ReleaseDC(0, hdc);
2395 return FALSE;
2397 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2399 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2401 skip("Font code page %d, looking for code page %d\n",
2402 pGdiGetCodePage(hdc), code_page);
2403 ReleaseDC(0, hdc);
2404 return FALSE;
2407 if (unicode)
2409 char ansi_buf[128];
2410 WCHAR unicode_buf[128];
2412 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2414 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2416 SetLastError(0xdeadbeef);
2417 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2418 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2419 count, ret, GetLastError());
2421 else
2423 char ansi_buf[128];
2425 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2427 SetLastError(0xdeadbeef);
2428 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2429 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2430 count, ret, GetLastError());
2433 SelectObject(hdc, hfont_old);
2434 DeleteObject(hfont);
2436 ReleaseDC(0, hdc);
2438 return TRUE;
2441 static void test_font_charset(void)
2443 static struct charset_data
2445 INT charset;
2446 UINT code_page;
2447 WORD font_idxA[128], font_idxW[128];
2448 } cd[] =
2450 { ANSI_CHARSET, 1252 },
2451 { RUSSIAN_CHARSET, 1251 },
2452 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2454 int i;
2456 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2458 win_skip("Skipping the font charset test on a Win9x platform\n");
2459 return;
2462 if (!is_font_installed("Arial"))
2464 skip("Arial is not installed\n");
2465 return;
2468 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2470 if (cd[i].charset == SYMBOL_CHARSET)
2472 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2474 skip("Symbol or Wingdings is not installed\n");
2475 break;
2478 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2479 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2480 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2483 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2484 if (i > 2)
2486 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2487 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2489 else
2490 skip("Symbol or Wingdings is not installed\n");
2493 static void test_GdiGetCodePage(void)
2495 static const struct _matching_data
2497 UINT current_codepage;
2498 LPCSTR lfFaceName;
2499 UCHAR lfCharSet;
2500 UINT expected_codepage;
2501 } matching_data[] = {
2502 {1251, "Arial", ANSI_CHARSET, 1252},
2503 {1251, "Tahoma", ANSI_CHARSET, 1252},
2505 {1252, "Arial", ANSI_CHARSET, 1252},
2506 {1252, "Tahoma", ANSI_CHARSET, 1252},
2508 {1253, "Arial", ANSI_CHARSET, 1252},
2509 {1253, "Tahoma", ANSI_CHARSET, 1252},
2511 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2512 { 932, "Tahoma", ANSI_CHARSET, 1252},
2513 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2515 { 936, "Arial", ANSI_CHARSET, 936},
2516 { 936, "Tahoma", ANSI_CHARSET, 936},
2517 { 936, "Simsun", ANSI_CHARSET, 936},
2519 { 949, "Arial", ANSI_CHARSET, 949},
2520 { 949, "Tahoma", ANSI_CHARSET, 949},
2521 { 949, "Gulim", ANSI_CHARSET, 949},
2523 { 950, "Arial", ANSI_CHARSET, 950},
2524 { 950, "Tahoma", ANSI_CHARSET, 950},
2525 { 950, "PMingLiU", ANSI_CHARSET, 950},
2527 HDC hdc;
2528 LOGFONTA lf;
2529 HFONT hfont;
2530 UINT charset, acp;
2531 DWORD codepage;
2532 int i;
2534 if (!pGdiGetCodePage)
2536 skip("GdiGetCodePage not available on this platform\n");
2537 return;
2540 acp = GetACP();
2542 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2544 /* only test data matched current locale codepage */
2545 if (matching_data[i].current_codepage != acp)
2546 continue;
2548 if (!is_font_installed(matching_data[i].lfFaceName))
2550 skip("%s is not installed\n", matching_data[i].lfFaceName);
2551 continue;
2554 hdc = GetDC(0);
2556 memset(&lf, 0, sizeof(lf));
2557 lf.lfHeight = -16;
2558 lf.lfCharSet = matching_data[i].lfCharSet;
2559 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2560 hfont = CreateFontIndirectA(&lf);
2561 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2563 hfont = SelectObject(hdc, hfont);
2564 charset = GetTextCharset(hdc);
2565 codepage = pGdiGetCodePage(hdc);
2566 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2567 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2568 ok(codepage == matching_data[i].expected_codepage,
2569 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2571 hfont = SelectObject(hdc, hfont);
2572 DeleteObject(hfont);
2573 ReleaseDC(NULL, hdc);
2577 static void test_GetFontUnicodeRanges(void)
2579 LOGFONTA lf;
2580 HDC hdc;
2581 HFONT hfont, hfont_old;
2582 DWORD size;
2583 GLYPHSET *gs;
2584 DWORD i;
2586 if (!pGetFontUnicodeRanges)
2588 win_skip("GetFontUnicodeRanges not available before W2K\n");
2589 return;
2592 memset(&lf, 0, sizeof(lf));
2593 lstrcpyA(lf.lfFaceName, "Arial");
2594 hfont = create_font("Arial", &lf);
2596 hdc = GetDC(0);
2597 hfont_old = SelectObject(hdc, hfont);
2599 size = pGetFontUnicodeRanges(NULL, NULL);
2600 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2602 size = pGetFontUnicodeRanges(hdc, NULL);
2603 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2605 gs = HeapAlloc(GetProcessHeap(), 0, size);
2607 size = pGetFontUnicodeRanges(hdc, gs);
2608 ok(size, "GetFontUnicodeRanges failed\n");
2610 if (0) /* Disabled to limit console spam */
2611 for (i = 0; i < gs->cRanges; i++)
2612 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2613 trace("found %u ranges\n", gs->cRanges);
2615 HeapFree(GetProcessHeap(), 0, gs);
2617 SelectObject(hdc, hfont_old);
2618 DeleteObject(hfont);
2619 ReleaseDC(NULL, hdc);
2622 #define MAX_ENUM_FONTS 4096
2624 struct enum_font_data
2626 int total;
2627 LOGFONTA lf[MAX_ENUM_FONTS];
2630 struct enum_fullname_data
2632 int total;
2633 ENUMLOGFONTA elf[MAX_ENUM_FONTS];
2636 struct enum_font_dataW
2638 int total;
2639 LOGFONTW lf[MAX_ENUM_FONTS];
2642 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2644 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2645 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2647 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2648 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2650 if (type != TRUETYPE_FONTTYPE) return 1;
2652 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2654 if (0) /* Disabled to limit console spam */
2655 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2656 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2657 if (efd->total < MAX_ENUM_FONTS)
2658 efd->lf[efd->total++] = *lf;
2659 else
2660 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2662 return 1;
2665 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2667 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2668 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2670 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2671 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2673 if (type != TRUETYPE_FONTTYPE) return 1;
2675 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2677 if (0) /* Disabled to limit console spam */
2678 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2679 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2680 if (efd->total < MAX_ENUM_FONTS)
2681 efd->lf[efd->total++] = *lf;
2682 else
2683 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2685 return 1;
2688 static void get_charset_stats(struct enum_font_data *efd,
2689 int *ansi_charset, int *symbol_charset,
2690 int *russian_charset)
2692 int i;
2694 *ansi_charset = 0;
2695 *symbol_charset = 0;
2696 *russian_charset = 0;
2698 for (i = 0; i < efd->total; i++)
2700 switch (efd->lf[i].lfCharSet)
2702 case ANSI_CHARSET:
2703 (*ansi_charset)++;
2704 break;
2705 case SYMBOL_CHARSET:
2706 (*symbol_charset)++;
2707 break;
2708 case RUSSIAN_CHARSET:
2709 (*russian_charset)++;
2710 break;
2715 static void get_charset_statsW(struct enum_font_dataW *efd,
2716 int *ansi_charset, int *symbol_charset,
2717 int *russian_charset)
2719 int i;
2721 *ansi_charset = 0;
2722 *symbol_charset = 0;
2723 *russian_charset = 0;
2725 for (i = 0; i < efd->total; i++)
2727 switch (efd->lf[i].lfCharSet)
2729 case ANSI_CHARSET:
2730 (*ansi_charset)++;
2731 break;
2732 case SYMBOL_CHARSET:
2733 (*symbol_charset)++;
2734 break;
2735 case RUSSIAN_CHARSET:
2736 (*russian_charset)++;
2737 break;
2742 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2744 struct enum_font_data efd;
2745 struct enum_font_dataW efdw;
2746 LOGFONTA lf;
2747 HDC hdc;
2748 int i, ret, ansi_charset, symbol_charset, russian_charset;
2750 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2752 if (*font_name && !is_truetype_font_installed(font_name))
2754 skip("%s is not installed\n", font_name);
2755 return;
2758 hdc = GetDC(0);
2760 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2761 * while EnumFontFamiliesEx doesn't.
2763 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2766 * Use EnumFontFamiliesW since win98 crashes when the
2767 * second parameter is NULL using EnumFontFamilies
2769 efdw.total = 0;
2770 SetLastError(0xdeadbeef);
2771 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2772 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2773 if(ret)
2775 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2776 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2777 ansi_charset, symbol_charset, russian_charset);
2778 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2779 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2780 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2781 ok(russian_charset > 0 ||
2782 broken(russian_charset == 0), /* NT4 */
2783 "NULL family should enumerate RUSSIAN_CHARSET\n");
2786 efdw.total = 0;
2787 SetLastError(0xdeadbeef);
2788 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2789 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2790 if(ret)
2792 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2793 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2794 ansi_charset, symbol_charset, russian_charset);
2795 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2796 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2797 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2798 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2802 efd.total = 0;
2803 SetLastError(0xdeadbeef);
2804 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2805 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2806 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2807 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2808 ansi_charset, symbol_charset, russian_charset,
2809 *font_name ? font_name : "<empty>");
2810 if (*font_name)
2811 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2812 else
2813 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2814 for (i = 0; i < efd.total; i++)
2816 /* FIXME: remove completely once Wine is fixed */
2817 if (efd.lf[i].lfCharSet != font_charset)
2819 todo_wine
2820 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2822 else
2823 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2824 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2825 font_name, efd.lf[i].lfFaceName);
2828 memset(&lf, 0, sizeof(lf));
2829 lf.lfCharSet = ANSI_CHARSET;
2830 strcpy(lf.lfFaceName, font_name);
2831 efd.total = 0;
2832 SetLastError(0xdeadbeef);
2833 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2834 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2835 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2836 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2837 ansi_charset, symbol_charset, russian_charset,
2838 *font_name ? font_name : "<empty>");
2839 if (font_charset == SYMBOL_CHARSET)
2841 if (*font_name)
2842 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2843 else
2844 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2846 else
2848 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2849 for (i = 0; i < efd.total; i++)
2851 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2852 if (*font_name)
2853 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2854 font_name, efd.lf[i].lfFaceName);
2858 /* DEFAULT_CHARSET should enumerate all available charsets */
2859 memset(&lf, 0, sizeof(lf));
2860 lf.lfCharSet = DEFAULT_CHARSET;
2861 strcpy(lf.lfFaceName, font_name);
2862 efd.total = 0;
2863 SetLastError(0xdeadbeef);
2864 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2865 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2866 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2867 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2868 ansi_charset, symbol_charset, russian_charset,
2869 *font_name ? font_name : "<empty>");
2870 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2871 for (i = 0; i < efd.total; i++)
2873 if (*font_name)
2874 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2875 font_name, efd.lf[i].lfFaceName);
2877 if (*font_name)
2879 switch (font_charset)
2881 case ANSI_CHARSET:
2882 ok(ansi_charset > 0,
2883 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2884 ok(!symbol_charset,
2885 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2886 ok(russian_charset > 0,
2887 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2888 break;
2889 case SYMBOL_CHARSET:
2890 ok(!ansi_charset,
2891 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2892 ok(symbol_charset,
2893 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2894 ok(!russian_charset,
2895 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2896 break;
2897 case DEFAULT_CHARSET:
2898 ok(ansi_charset > 0,
2899 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2900 ok(symbol_charset > 0,
2901 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2902 ok(russian_charset > 0,
2903 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2904 break;
2907 else
2909 ok(ansi_charset > 0,
2910 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2911 ok(symbol_charset > 0,
2912 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2913 ok(russian_charset > 0,
2914 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2917 memset(&lf, 0, sizeof(lf));
2918 lf.lfCharSet = SYMBOL_CHARSET;
2919 strcpy(lf.lfFaceName, font_name);
2920 efd.total = 0;
2921 SetLastError(0xdeadbeef);
2922 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2923 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2924 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2925 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2926 ansi_charset, symbol_charset, russian_charset,
2927 *font_name ? font_name : "<empty>");
2928 if (*font_name && font_charset == ANSI_CHARSET)
2929 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2930 else
2932 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2933 for (i = 0; i < efd.total; i++)
2935 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2936 if (*font_name)
2937 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2938 font_name, efd.lf[i].lfFaceName);
2941 ok(!ansi_charset,
2942 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2943 ok(symbol_charset > 0,
2944 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2945 ok(!russian_charset,
2946 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2949 ReleaseDC(0, hdc);
2952 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2954 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
2955 LOGFONTA *target = (LOGFONTA *)lParam;
2956 const DWORD valid_bits = 0x003f01ff;
2957 CHARSETINFO csi;
2958 DWORD fs;
2960 if (type != TRUETYPE_FONTTYPE) return TRUE;
2962 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
2963 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
2964 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
2965 *target = *lf;
2966 return FALSE;
2970 return TRUE;
2973 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
2975 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2977 if (type != TRUETYPE_FONTTYPE) return 1;
2979 if (efd->total < MAX_ENUM_FONTS)
2980 efd->lf[efd->total++] = *lf;
2981 else
2982 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2984 return 1;
2987 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
2989 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2991 if (type != TRUETYPE_FONTTYPE) return 1;
2993 if (efnd->total < MAX_ENUM_FONTS)
2994 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
2995 else
2996 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2998 return 1;
3001 static void test_EnumFontFamiliesEx_default_charset(void)
3003 struct enum_font_data efd;
3004 LOGFONTA target, enum_font;
3005 UINT acp;
3006 HDC hdc;
3007 CHARSETINFO csi;
3009 acp = GetACP();
3010 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3011 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3012 return;
3015 hdc = GetDC(0);
3016 memset(&enum_font, 0, sizeof(enum_font));
3017 enum_font.lfCharSet = csi.ciCharset;
3018 target.lfFaceName[0] = '\0';
3019 target.lfCharSet = csi.ciCharset;
3020 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3021 if (target.lfFaceName[0] == '\0') {
3022 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3023 return;
3025 if (acp == 874 || acp == 1255 || acp == 1256) {
3026 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3027 target.lfCharSet = ANSI_CHARSET;
3030 efd.total = 0;
3031 memset(&enum_font, 0, sizeof(enum_font));
3032 strcpy(enum_font.lfFaceName, target.lfFaceName);
3033 enum_font.lfCharSet = DEFAULT_CHARSET;
3034 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3035 ReleaseDC(0, hdc);
3037 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3038 if (efd.total < 2) {
3039 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3040 return;
3043 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3044 "(%s) got charset %d expected %d\n",
3045 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3047 return;
3050 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3052 HFONT hfont, hfont_prev;
3053 DWORD ret;
3054 GLYPHMETRICS gm1, gm2;
3055 LOGFONTA lf2 = *lf;
3056 WORD idx;
3058 if(!pGetGlyphIndicesA)
3059 return;
3061 /* negative widths are handled just as positive ones */
3062 lf2.lfWidth = -lf->lfWidth;
3064 SetLastError(0xdeadbeef);
3065 hfont = CreateFontIndirectA(lf);
3066 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3067 check_font("original", lf, hfont);
3069 hfont_prev = SelectObject(hdc, hfont);
3071 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3072 if (ret == GDI_ERROR || idx == 0xffff)
3074 SelectObject(hdc, hfont_prev);
3075 DeleteObject(hfont);
3076 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3077 return;
3080 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3081 memset(&gm1, 0xab, sizeof(gm1));
3082 SetLastError(0xdeadbeef);
3083 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3084 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3086 SelectObject(hdc, hfont_prev);
3087 DeleteObject(hfont);
3089 SetLastError(0xdeadbeef);
3090 hfont = CreateFontIndirectA(&lf2);
3091 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3092 check_font("negative width", &lf2, hfont);
3094 hfont_prev = SelectObject(hdc, hfont);
3096 memset(&gm2, 0xbb, sizeof(gm2));
3097 SetLastError(0xdeadbeef);
3098 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3099 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3101 SelectObject(hdc, hfont_prev);
3102 DeleteObject(hfont);
3104 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3105 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3106 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3107 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3108 gm1.gmCellIncX == gm2.gmCellIncX &&
3109 gm1.gmCellIncY == gm2.gmCellIncY,
3110 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3111 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3112 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3113 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3114 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3117 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3118 #include "pshpack2.h"
3119 typedef struct
3121 USHORT version;
3122 SHORT xAvgCharWidth;
3123 USHORT usWeightClass;
3124 USHORT usWidthClass;
3125 SHORT fsType;
3126 SHORT ySubscriptXSize;
3127 SHORT ySubscriptYSize;
3128 SHORT ySubscriptXOffset;
3129 SHORT ySubscriptYOffset;
3130 SHORT ySuperscriptXSize;
3131 SHORT ySuperscriptYSize;
3132 SHORT ySuperscriptXOffset;
3133 SHORT ySuperscriptYOffset;
3134 SHORT yStrikeoutSize;
3135 SHORT yStrikeoutPosition;
3136 SHORT sFamilyClass;
3137 PANOSE panose;
3138 ULONG ulUnicodeRange1;
3139 ULONG ulUnicodeRange2;
3140 ULONG ulUnicodeRange3;
3141 ULONG ulUnicodeRange4;
3142 CHAR achVendID[4];
3143 USHORT fsSelection;
3144 USHORT usFirstCharIndex;
3145 USHORT usLastCharIndex;
3146 /* According to the Apple spec, original version didn't have the below fields,
3147 * version numbers were taken from the OpenType spec.
3149 /* version 0 (TrueType 1.5) */
3150 USHORT sTypoAscender;
3151 USHORT sTypoDescender;
3152 USHORT sTypoLineGap;
3153 USHORT usWinAscent;
3154 USHORT usWinDescent;
3155 /* version 1 (TrueType 1.66) */
3156 ULONG ulCodePageRange1;
3157 ULONG ulCodePageRange2;
3158 /* version 2 (OpenType 1.2) */
3159 SHORT sxHeight;
3160 SHORT sCapHeight;
3161 USHORT usDefaultChar;
3162 USHORT usBreakChar;
3163 USHORT usMaxContext;
3164 } TT_OS2_V2;
3165 #include "poppack.h"
3167 typedef struct
3169 USHORT version;
3170 USHORT num_tables;
3171 } cmap_header;
3173 typedef struct
3175 USHORT plat_id;
3176 USHORT enc_id;
3177 ULONG offset;
3178 } cmap_encoding_record;
3180 typedef struct
3182 USHORT format;
3183 USHORT length;
3184 USHORT language;
3186 BYTE glyph_ids[256];
3187 } cmap_format_0;
3189 typedef struct
3191 USHORT format;
3192 USHORT length;
3193 USHORT language;
3195 USHORT seg_countx2;
3196 USHORT search_range;
3197 USHORT entry_selector;
3198 USHORT range_shift;
3200 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3201 /* Then follows:
3202 USHORT pad;
3203 USHORT start_count[seg_countx2 / 2];
3204 USHORT id_delta[seg_countx2 / 2];
3205 USHORT id_range_offset[seg_countx2 / 2];
3206 USHORT glyph_ids[];
3208 } cmap_format_4;
3210 typedef struct
3212 USHORT end_count;
3213 USHORT start_count;
3214 USHORT id_delta;
3215 USHORT id_range_offset;
3216 } cmap_format_4_seg;
3218 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
3220 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3221 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3222 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3223 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3224 os2->panose.bWeight, os2->panose.bProportion);
3227 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3229 int i;
3230 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3232 *first = 256;
3234 for(i = 0; i < 256; i++)
3236 if(cmap->glyph_ids[i] == 0) continue;
3237 *last = i;
3238 if(*first == 256) *first = i;
3240 if(*first == 256) return FALSE;
3241 return TRUE;
3244 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3246 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3247 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3248 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3249 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3250 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3253 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3255 int i;
3256 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3257 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3258 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
3260 *first = 0x10000;
3262 for(i = 0; i < seg_count; i++)
3264 DWORD code, index;
3265 cmap_format_4_seg seg;
3267 get_seg4(cmap, i, &seg);
3268 for(code = seg.start_count; code <= seg.end_count; code++)
3270 if(seg.id_range_offset == 0)
3271 index = (seg.id_delta + code) & 0xffff;
3272 else
3274 index = seg.id_range_offset / 2
3275 + code - seg.start_count
3276 + i - seg_count;
3278 /* some fonts have broken last segment */
3279 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
3280 index = GET_BE_WORD(glyph_ids[index]);
3281 else
3283 trace("segment %04x/%04x index %04x points to nowhere\n",
3284 seg.start_count, seg.end_count, index);
3285 index = 0;
3287 if(index) index += seg.id_delta;
3289 if(*first == 0x10000)
3290 *last = *first = code;
3291 else if(index)
3292 *last = code;
3296 if(*first == 0x10000) return FALSE;
3297 return TRUE;
3300 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3302 USHORT i;
3303 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3305 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3307 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3308 return (BYTE *)header + GET_BE_DWORD(record->offset);
3309 record++;
3311 return NULL;
3314 typedef enum
3316 cmap_none,
3317 cmap_ms_unicode,
3318 cmap_ms_symbol
3319 } cmap_type;
3321 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3323 LONG size, ret;
3324 cmap_header *header;
3325 void *cmap;
3326 BOOL r = FALSE;
3327 WORD format;
3329 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3330 ok(size != GDI_ERROR, "no cmap table found\n");
3331 if(size == GDI_ERROR) return FALSE;
3333 header = HeapAlloc(GetProcessHeap(), 0, size);
3334 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3335 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3336 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3338 cmap = get_cmap(header, 3, 1);
3339 if(cmap)
3340 *cmap_type = cmap_ms_unicode;
3341 else
3343 cmap = get_cmap(header, 3, 0);
3344 if(cmap) *cmap_type = cmap_ms_symbol;
3346 if(!cmap)
3348 *cmap_type = cmap_none;
3349 goto end;
3352 format = GET_BE_WORD(*(WORD *)cmap);
3353 switch(format)
3355 case 0:
3356 r = get_first_last_from_cmap0(cmap, first, last);
3357 break;
3358 case 4:
3359 r = get_first_last_from_cmap4(cmap, first, last, size);
3360 break;
3361 default:
3362 trace("unhandled cmap format %d\n", format);
3363 break;
3366 end:
3367 HeapFree(GetProcessHeap(), 0, header);
3368 return r;
3371 #define TT_PLATFORM_MICROSOFT 3
3372 #define TT_MS_ID_SYMBOL_CS 0
3373 #define TT_MS_ID_UNICODE_CS 1
3374 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3375 #define TT_NAME_ID_FONT_FAMILY 1
3376 #define TT_NAME_ID_FONT_SUBFAMILY 2
3377 #define TT_NAME_ID_UNIQUE_ID 3
3378 #define TT_NAME_ID_FULL_NAME 4
3380 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3382 struct sfnt_name_header
3384 USHORT format;
3385 USHORT number_of_record;
3386 USHORT storage_offset;
3387 } *header;
3388 struct sfnt_name
3390 USHORT platform_id;
3391 USHORT encoding_id;
3392 USHORT language_id;
3393 USHORT name_id;
3394 USHORT length;
3395 USHORT offset;
3396 } *entry;
3397 BOOL r = FALSE;
3398 LONG size, offset, length;
3399 LONG c, ret;
3400 WCHAR *name;
3401 BYTE *data;
3402 USHORT i;
3404 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3405 ok(size != GDI_ERROR, "no name table found\n");
3406 if(size == GDI_ERROR) return FALSE;
3408 data = HeapAlloc(GetProcessHeap(), 0, size);
3409 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3410 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3412 header = (void *)data;
3413 header->format = GET_BE_WORD(header->format);
3414 header->number_of_record = GET_BE_WORD(header->number_of_record);
3415 header->storage_offset = GET_BE_WORD(header->storage_offset);
3416 if (header->format != 0)
3418 trace("got format %u\n", header->format);
3419 goto out;
3421 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3423 trace("number records out of range: %d\n", header->number_of_record);
3424 goto out;
3426 if (header->storage_offset >= size)
3428 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3429 goto out;
3432 entry = (void *)&header[1];
3433 for (i = 0; i < header->number_of_record; i++)
3435 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
3436 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
3437 GET_BE_WORD(entry[i].language_id) != language_id ||
3438 GET_BE_WORD(entry[i].name_id) != name_id)
3440 continue;
3443 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
3444 length = GET_BE_WORD(entry[i].length);
3445 if (offset + length > size)
3447 trace("entry %d is out of range\n", i);
3448 break;
3450 if (length >= out_size)
3452 trace("buffer too small for entry %d\n", i);
3453 break;
3456 name = (WCHAR *)(data + offset);
3457 for (c = 0; c < length / 2; c++)
3458 out_buf[c] = GET_BE_WORD(name[c]);
3459 out_buf[c] = 0;
3461 r = TRUE;
3462 break;
3465 out:
3466 HeapFree(GetProcessHeap(), 0, data);
3467 return r;
3470 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3472 HDC hdc;
3473 HFONT hfont, hfont_old;
3474 TEXTMETRICA tmA;
3475 TT_OS2_V2 tt_os2;
3476 LONG size, ret;
3477 const char *font_name = lf->lfFaceName;
3478 DWORD cmap_first = 0, cmap_last = 0;
3479 UINT ascent, descent, cell_height;
3480 cmap_type cmap_type;
3481 BOOL sys_lang_non_english;
3483 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3484 hdc = GetDC(0);
3486 SetLastError(0xdeadbeef);
3487 hfont = CreateFontIndirectA(lf);
3488 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3490 hfont_old = SelectObject(hdc, hfont);
3492 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3493 if (size == GDI_ERROR)
3495 trace("OS/2 chunk was not found\n");
3496 goto end_of_test;
3498 if (size > sizeof(tt_os2))
3500 trace("got too large OS/2 chunk of size %u\n", size);
3501 size = sizeof(tt_os2);
3504 memset(&tt_os2, 0, sizeof(tt_os2));
3505 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3506 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3508 SetLastError(0xdeadbeef);
3509 ret = GetTextMetricsA(hdc, &tmA);
3510 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3512 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3514 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3516 else
3518 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3519 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3520 UINT os2_first_char, os2_last_char, default_char, break_char;
3521 USHORT version;
3522 TEXTMETRICW tmW;
3524 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3525 descent = GET_BE_WORD(tt_os2.usWinDescent);
3526 cell_height = ascent + descent;
3527 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3528 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3530 version = GET_BE_WORD(tt_os2.version);
3532 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3533 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3534 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3535 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3537 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3538 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3539 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3541 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3543 expect_first_W = 0;
3544 switch(GetACP())
3546 case 1255: /* Hebrew */
3547 expect_last_W = 0xf896;
3548 break;
3549 case 1257: /* Baltic */
3550 expect_last_W = 0xf8fd;
3551 break;
3552 default:
3553 expect_last_W = 0xf0ff;
3555 expect_break_W = 0x20;
3556 expect_default_W = expect_break_W - 1;
3557 expect_first_A = 0x1e;
3558 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3560 else
3562 expect_first_W = cmap_first;
3563 expect_last_W = min(cmap_last, os2_last_char);
3564 if(os2_first_char <= 1)
3565 expect_break_W = os2_first_char + 2;
3566 else if(os2_first_char > 0xff)
3567 expect_break_W = 0x20;
3568 else
3569 expect_break_W = os2_first_char;
3570 expect_default_W = expect_break_W - 1;
3571 expect_first_A = expect_default_W - 1;
3572 expect_last_A = min(expect_last_W, 0xff);
3574 expect_break_A = expect_break_W;
3575 expect_default_A = expect_default_W;
3577 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3578 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3579 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3580 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3581 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3582 else
3583 ok(tmA.tmFirstChar == expect_first_A ||
3584 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3585 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3586 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3587 ok(tmA.tmLastChar == expect_last_A ||
3588 tmA.tmLastChar == 0xff /* win9x */,
3589 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3590 else
3591 skip("tmLastChar is DBCS lead byte\n");
3592 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3593 font_name, tmA.tmBreakChar, expect_break_A);
3594 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3595 "A: tmDefaultChar for %s got %02x expected %02x\n",
3596 font_name, tmA.tmDefaultChar, expect_default_A);
3599 SetLastError(0xdeadbeef);
3600 ret = GetTextMetricsW(hdc, &tmW);
3601 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3602 "GetTextMetricsW error %u\n", GetLastError());
3603 if (ret)
3605 /* Wine uses the os2 first char */
3606 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3607 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3608 font_name, tmW.tmFirstChar, expect_first_W);
3609 else
3610 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3611 font_name, tmW.tmFirstChar, expect_first_W);
3613 /* Wine uses the os2 last char */
3614 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3615 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3616 font_name, tmW.tmLastChar, expect_last_W);
3617 else
3618 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3619 font_name, tmW.tmLastChar, expect_last_W);
3620 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3621 font_name, tmW.tmBreakChar, expect_break_W);
3622 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3623 "W: tmDefaultChar for %s got %02x expected %02x\n",
3624 font_name, tmW.tmDefaultChar, expect_default_W);
3626 /* Test the aspect ratio while we have tmW */
3627 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3628 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3629 tmW.tmDigitizedAspectX, ret);
3630 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3631 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3632 tmW.tmDigitizedAspectX, ret);
3636 /* test FF_ values */
3637 switch(tt_os2.panose.bFamilyType)
3639 case PAN_ANY:
3640 case PAN_NO_FIT:
3641 case PAN_FAMILY_TEXT_DISPLAY:
3642 case PAN_FAMILY_PICTORIAL:
3643 default:
3644 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3645 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3647 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3648 break;
3650 switch(tt_os2.panose.bSerifStyle)
3652 case PAN_ANY:
3653 case PAN_NO_FIT:
3654 default:
3655 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3656 break;
3658 case PAN_SERIF_COVE:
3659 case PAN_SERIF_OBTUSE_COVE:
3660 case PAN_SERIF_SQUARE_COVE:
3661 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3662 case PAN_SERIF_SQUARE:
3663 case PAN_SERIF_THIN:
3664 case PAN_SERIF_BONE:
3665 case PAN_SERIF_EXAGGERATED:
3666 case PAN_SERIF_TRIANGLE:
3667 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3668 break;
3670 case PAN_SERIF_NORMAL_SANS:
3671 case PAN_SERIF_OBTUSE_SANS:
3672 case PAN_SERIF_PERP_SANS:
3673 case PAN_SERIF_FLARED:
3674 case PAN_SERIF_ROUNDED:
3675 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3676 break;
3678 break;
3680 case PAN_FAMILY_SCRIPT:
3681 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3682 break;
3684 case PAN_FAMILY_DECORATIVE:
3685 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3686 break;
3689 test_negative_width(hdc, lf);
3691 end_of_test:
3692 SelectObject(hdc, hfont_old);
3693 DeleteObject(hfont);
3695 ReleaseDC(0, hdc);
3698 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3700 INT *enumed = (INT *)lParam;
3702 if (type == TRUETYPE_FONTTYPE)
3704 (*enumed)++;
3705 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
3707 return 1;
3710 static void test_GetTextMetrics(void)
3712 LOGFONTA lf;
3713 HDC hdc;
3714 INT enumed;
3716 /* Report only once */
3717 if(!pGetGlyphIndicesA)
3718 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3720 hdc = GetDC(0);
3722 memset(&lf, 0, sizeof(lf));
3723 lf.lfCharSet = DEFAULT_CHARSET;
3724 enumed = 0;
3725 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3726 trace("Tested metrics of %d truetype fonts\n", enumed);
3728 ReleaseDC(0, hdc);
3731 static void test_nonexistent_font(void)
3733 static const struct
3735 const char *name;
3736 int charset;
3737 } font_subst[] =
3739 { "Times New Roman Baltic", 186 },
3740 { "Times New Roman CE", 238 },
3741 { "Times New Roman CYR", 204 },
3742 { "Times New Roman Greek", 161 },
3743 { "Times New Roman TUR", 162 }
3745 LOGFONTA lf;
3746 HDC hdc;
3747 HFONT hfont;
3748 CHARSETINFO csi;
3749 INT cs, expected_cs, i;
3750 char buf[LF_FACESIZE];
3752 if (!is_truetype_font_installed("Arial") ||
3753 !is_truetype_font_installed("Times New Roman"))
3755 skip("Arial or Times New Roman not installed\n");
3756 return;
3759 expected_cs = GetACP();
3760 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3762 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3763 return;
3765 expected_cs = csi.ciCharset;
3766 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3768 hdc = GetDC(0);
3770 memset(&lf, 0, sizeof(lf));
3771 lf.lfHeight = 100;
3772 lf.lfWeight = FW_REGULAR;
3773 lf.lfCharSet = ANSI_CHARSET;
3774 lf.lfPitchAndFamily = FF_SWISS;
3775 strcpy(lf.lfFaceName, "Nonexistent font");
3776 hfont = CreateFontIndirectA(&lf);
3777 hfont = SelectObject(hdc, hfont);
3778 GetTextFaceA(hdc, sizeof(buf), buf);
3779 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3780 cs = GetTextCharset(hdc);
3781 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3782 DeleteObject(SelectObject(hdc, hfont));
3784 memset(&lf, 0, sizeof(lf));
3785 lf.lfHeight = -13;
3786 lf.lfWeight = FW_DONTCARE;
3787 strcpy(lf.lfFaceName, "Nonexistent font");
3788 hfont = CreateFontIndirectA(&lf);
3789 hfont = SelectObject(hdc, hfont);
3790 GetTextFaceA(hdc, sizeof(buf), buf);
3791 todo_wine /* Wine uses Arial for all substitutions */
3792 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3793 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3794 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3795 "Got %s\n", buf);
3796 cs = GetTextCharset(hdc);
3797 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3798 DeleteObject(SelectObject(hdc, hfont));
3800 memset(&lf, 0, sizeof(lf));
3801 lf.lfHeight = -13;
3802 lf.lfWeight = FW_REGULAR;
3803 strcpy(lf.lfFaceName, "Nonexistent font");
3804 hfont = CreateFontIndirectA(&lf);
3805 hfont = SelectObject(hdc, hfont);
3806 GetTextFaceA(hdc, sizeof(buf), buf);
3807 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3808 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3809 cs = GetTextCharset(hdc);
3810 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3811 DeleteObject(SelectObject(hdc, hfont));
3813 memset(&lf, 0, sizeof(lf));
3814 lf.lfHeight = -13;
3815 lf.lfWeight = FW_DONTCARE;
3816 strcpy(lf.lfFaceName, "Times New Roman");
3817 hfont = CreateFontIndirectA(&lf);
3818 hfont = SelectObject(hdc, hfont);
3819 GetTextFaceA(hdc, sizeof(buf), buf);
3820 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3821 cs = GetTextCharset(hdc);
3822 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3823 DeleteObject(SelectObject(hdc, hfont));
3825 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3827 memset(&lf, 0, sizeof(lf));
3828 lf.lfHeight = -13;
3829 lf.lfWeight = FW_REGULAR;
3830 strcpy(lf.lfFaceName, font_subst[i].name);
3831 hfont = CreateFontIndirectA(&lf);
3832 hfont = SelectObject(hdc, hfont);
3833 cs = GetTextCharset(hdc);
3834 if (font_subst[i].charset == expected_cs)
3836 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3837 GetTextFaceA(hdc, sizeof(buf), buf);
3838 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3840 else
3842 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3843 GetTextFaceA(hdc, sizeof(buf), buf);
3844 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3845 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3847 DeleteObject(SelectObject(hdc, hfont));
3849 memset(&lf, 0, sizeof(lf));
3850 lf.lfHeight = -13;
3851 lf.lfWeight = FW_DONTCARE;
3852 strcpy(lf.lfFaceName, font_subst[i].name);
3853 hfont = CreateFontIndirectA(&lf);
3854 hfont = SelectObject(hdc, hfont);
3855 GetTextFaceA(hdc, sizeof(buf), buf);
3856 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3857 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3858 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3859 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3860 "got %s for font %s\n", buf, font_subst[i].name);
3861 cs = GetTextCharset(hdc);
3862 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3863 DeleteObject(SelectObject(hdc, hfont));
3866 ReleaseDC(0, hdc);
3869 static void test_GdiRealizationInfo(void)
3871 HDC hdc;
3872 DWORD info[4];
3873 BOOL r;
3874 HFONT hfont, hfont_old;
3875 LOGFONTA lf;
3877 if(!pGdiRealizationInfo)
3879 win_skip("GdiRealizationInfo not available\n");
3880 return;
3883 hdc = GetDC(0);
3885 memset(info, 0xcc, sizeof(info));
3886 r = pGdiRealizationInfo(hdc, info);
3887 ok(r != 0, "ret 0\n");
3888 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3889 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3891 if (!is_truetype_font_installed("Arial"))
3893 skip("skipping GdiRealizationInfo with truetype font\n");
3894 goto end;
3897 memset(&lf, 0, sizeof(lf));
3898 strcpy(lf.lfFaceName, "Arial");
3899 lf.lfHeight = 20;
3900 lf.lfWeight = FW_NORMAL;
3901 hfont = CreateFontIndirectA(&lf);
3902 hfont_old = SelectObject(hdc, hfont);
3904 memset(info, 0xcc, sizeof(info));
3905 r = pGdiRealizationInfo(hdc, info);
3906 ok(r != 0, "ret 0\n");
3907 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3908 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3910 DeleteObject(SelectObject(hdc, hfont_old));
3912 end:
3913 ReleaseDC(0, hdc);
3916 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3917 the nul in the count of characters copied when the face name buffer is not
3918 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3919 always includes it. */
3920 static void test_GetTextFace(void)
3922 static const char faceA[] = "Tahoma";
3923 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3924 LOGFONTA fA = {0};
3925 LOGFONTW fW = {0};
3926 char bufA[LF_FACESIZE];
3927 WCHAR bufW[LF_FACESIZE];
3928 HFONT f, g;
3929 HDC dc;
3930 int n;
3932 if(!is_font_installed("Tahoma"))
3934 skip("Tahoma is not installed so skipping this test\n");
3935 return;
3938 /* 'A' case. */
3939 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3940 f = CreateFontIndirectA(&fA);
3941 ok(f != NULL, "CreateFontIndirectA failed\n");
3943 dc = GetDC(NULL);
3944 g = SelectObject(dc, f);
3945 n = GetTextFaceA(dc, sizeof bufA, bufA);
3946 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3947 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3949 /* Play with the count arg. */
3950 bufA[0] = 'x';
3951 n = GetTextFaceA(dc, 0, bufA);
3952 ok(n == 0, "GetTextFaceA returned %d\n", n);
3953 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3955 bufA[0] = 'x';
3956 n = GetTextFaceA(dc, 1, bufA);
3957 ok(n == 0, "GetTextFaceA returned %d\n", n);
3958 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3960 bufA[0] = 'x'; bufA[1] = 'y';
3961 n = GetTextFaceA(dc, 2, bufA);
3962 ok(n == 1, "GetTextFaceA returned %d\n", n);
3963 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3965 n = GetTextFaceA(dc, 0, NULL);
3966 ok(n == sizeof faceA ||
3967 broken(n == 0), /* win98, winMe */
3968 "GetTextFaceA returned %d\n", n);
3970 DeleteObject(SelectObject(dc, g));
3971 ReleaseDC(NULL, dc);
3973 /* 'W' case. */
3974 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3975 SetLastError(0xdeadbeef);
3976 f = CreateFontIndirectW(&fW);
3977 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3979 win_skip("CreateFontIndirectW is not implemented\n");
3980 return;
3982 ok(f != NULL, "CreateFontIndirectW failed\n");
3984 dc = GetDC(NULL);
3985 g = SelectObject(dc, f);
3986 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3987 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3988 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3990 /* Play with the count arg. */
3991 bufW[0] = 'x';
3992 n = GetTextFaceW(dc, 0, bufW);
3993 ok(n == 0, "GetTextFaceW returned %d\n", n);
3994 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3996 bufW[0] = 'x';
3997 n = GetTextFaceW(dc, 1, bufW);
3998 ok(n == 1, "GetTextFaceW returned %d\n", n);
3999 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4001 bufW[0] = 'x'; bufW[1] = 'y';
4002 n = GetTextFaceW(dc, 2, bufW);
4003 ok(n == 2, "GetTextFaceW returned %d\n", n);
4004 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4006 n = GetTextFaceW(dc, 0, NULL);
4007 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4009 DeleteObject(SelectObject(dc, g));
4010 ReleaseDC(NULL, dc);
4013 static void test_orientation(void)
4015 static const char test_str[11] = "Test String";
4016 HDC hdc;
4017 LOGFONTA lf;
4018 HFONT hfont, old_hfont;
4019 SIZE size;
4021 if (!is_truetype_font_installed("Arial"))
4023 skip("Arial is not installed\n");
4024 return;
4027 hdc = CreateCompatibleDC(0);
4028 memset(&lf, 0, sizeof(lf));
4029 lstrcpyA(lf.lfFaceName, "Arial");
4030 lf.lfHeight = 72;
4031 lf.lfOrientation = lf.lfEscapement = 900;
4032 hfont = create_font("orientation", &lf);
4033 old_hfont = SelectObject(hdc, hfont);
4034 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4035 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4036 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4037 SelectObject(hdc, old_hfont);
4038 DeleteObject(hfont);
4039 DeleteDC(hdc);
4042 static void test_oemcharset(void)
4044 HDC hdc;
4045 LOGFONTA lf, clf;
4046 HFONT hfont, old_hfont;
4047 int charset;
4049 hdc = CreateCompatibleDC(0);
4050 ZeroMemory(&lf, sizeof(lf));
4051 lf.lfHeight = 12;
4052 lf.lfCharSet = OEM_CHARSET;
4053 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4054 lstrcpyA(lf.lfFaceName, "Terminal");
4055 hfont = CreateFontIndirectA(&lf);
4056 old_hfont = SelectObject(hdc, hfont);
4057 charset = GetTextCharset(hdc);
4058 todo_wine
4059 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4060 hfont = SelectObject(hdc, old_hfont);
4061 GetObjectA(hfont, sizeof(clf), &clf);
4062 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4063 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4064 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4065 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4066 DeleteObject(hfont);
4067 DeleteDC(hdc);
4070 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4071 const TEXTMETRICA *lpntme,
4072 DWORD FontType, LPARAM lParam)
4074 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4075 CHARSETINFO csi;
4076 LOGFONTA lf = *lpelfe;
4077 HFONT hfont;
4078 DWORD found_subset;
4080 /* skip bitmap, proportional or vertical font */
4081 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4082 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4083 lf.lfFaceName[0] == '@')
4084 return 1;
4086 /* skip linked font */
4087 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4088 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4089 return 1;
4091 /* skip linked font, like SimSun-ExtB */
4092 switch (lpelfe->lfCharSet) {
4093 case SHIFTJIS_CHARSET:
4094 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4095 break;
4096 case GB2312_CHARSET:
4097 case CHINESEBIG5_CHARSET:
4098 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4099 break;
4100 case HANGEUL_CHARSET:
4101 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4102 break;
4103 default:
4104 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4105 break;
4107 if (!found_subset)
4108 return 1;
4110 /* test with an odd height */
4111 lf.lfHeight = -19;
4112 lf.lfWidth = 0;
4113 hfont = CreateFontIndirectA(&lf);
4114 if (hfont)
4116 *(HFONT *)lParam = hfont;
4117 return 0;
4119 return 1;
4122 static void test_GetGlyphOutline(void)
4124 HDC hdc;
4125 GLYPHMETRICS gm, gm2;
4126 LOGFONTA lf;
4127 HFONT hfont, old_hfont;
4128 INT ret, ret2;
4129 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4130 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4131 static const struct
4133 UINT cs;
4134 UINT a;
4135 UINT w;
4136 } c[] =
4138 {ANSI_CHARSET, 0x30, 0x30},
4139 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4140 {HANGEUL_CHARSET, 0x8141, 0xac02},
4141 {GB2312_CHARSET, 0x8141, 0x4e04},
4142 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4144 UINT i;
4146 if (!is_truetype_font_installed("Tahoma"))
4148 skip("Tahoma is not installed\n");
4149 return;
4152 hdc = CreateCompatibleDC(0);
4153 memset(&lf, 0, sizeof(lf));
4154 lf.lfHeight = 72;
4155 lstrcpyA(lf.lfFaceName, "Tahoma");
4156 SetLastError(0xdeadbeef);
4157 hfont = CreateFontIndirectA(&lf);
4158 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4159 old_hfont = SelectObject(hdc, hfont);
4161 memset(&gm, 0, sizeof(gm));
4162 SetLastError(0xdeadbeef);
4163 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4164 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4166 memset(&gm, 0, sizeof(gm));
4167 SetLastError(0xdeadbeef);
4168 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4169 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4170 ok(GetLastError() == 0xdeadbeef ||
4171 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4172 "expected 0xdeadbeef, got %u\n", GetLastError());
4174 memset(&gm, 0, sizeof(gm));
4175 SetLastError(0xdeadbeef);
4176 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4177 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4178 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4180 memset(&gm, 0, sizeof(gm));
4181 SetLastError(0xdeadbeef);
4182 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4183 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4185 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4186 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4189 /* test for needed buffer size request on space char */
4190 memset(&gm, 0, sizeof(gm));
4191 SetLastError(0xdeadbeef);
4192 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4193 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4194 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4196 /* requesting buffer size for space char + error */
4197 memset(&gm, 0, sizeof(gm));
4198 SetLastError(0xdeadbeef);
4199 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4200 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4202 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4203 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4206 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4208 DWORD dummy;
4210 memset(&gm, 0xab, sizeof(gm));
4211 SetLastError(0xdeadbeef);
4212 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4213 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4215 if (fmt[i] == GGO_METRICS)
4216 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4217 else
4218 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4219 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4220 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4223 memset(&gm, 0xab, sizeof(gm));
4224 SetLastError(0xdeadbeef);
4225 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4226 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4228 if (fmt[i] == GGO_METRICS)
4229 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4230 else
4231 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4232 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4233 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4236 memset(&gm, 0xab, sizeof(gm));
4237 SetLastError(0xdeadbeef);
4238 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4239 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4241 if (fmt[i] == GGO_METRICS)
4242 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4243 else
4244 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4245 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4246 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4249 memset(&gm, 0xab, sizeof(gm));
4250 SetLastError(0xdeadbeef);
4251 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4252 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4254 if (fmt[i] == GGO_METRICS) {
4255 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4256 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4257 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4259 else
4261 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4262 memset(&gm2, 0xab, sizeof(gm2));
4263 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4264 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4269 SelectObject(hdc, old_hfont);
4270 DeleteObject(hfont);
4272 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4274 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4275 TEXTMETRICA tm;
4277 lf.lfFaceName[0] = '\0';
4278 lf.lfCharSet = c[i].cs;
4279 lf.lfPitchAndFamily = 0;
4280 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4282 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4283 continue;
4286 old_hfont = SelectObject(hdc, hfont);
4288 /* expected to ignore superfluous bytes (sigle-byte character) */
4289 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4290 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4291 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4293 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4294 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4295 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4297 /* expected to ignore superfluous bytes (double-byte character) */
4298 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4299 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4300 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4301 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4303 /* expected to match wide-char version results */
4304 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4305 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4307 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4309 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4310 continue;
4312 DeleteObject(SelectObject(hdc, hfont));
4313 if (c[i].a <= 0xff)
4315 DeleteObject(SelectObject(hdc, old_hfont));
4316 continue;
4319 ret = GetObjectA(hfont, sizeof lf, &lf);
4320 ok(ret > 0, "GetObject error %u\n", GetLastError());
4322 ret = GetTextMetricsA(hdc, &tm);
4323 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4324 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4325 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4326 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4327 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4328 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4329 "expected %d, got %d (%s:%d)\n",
4330 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4332 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4333 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4334 ok(gm2.gmCellIncY == -lf.lfHeight,
4335 "expected %d, got %d (%s:%d)\n",
4336 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4338 lf.lfItalic = TRUE;
4339 hfont = CreateFontIndirectA(&lf);
4340 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4341 DeleteObject(SelectObject(hdc, hfont));
4342 ret = GetTextMetricsA(hdc, &tm);
4343 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4344 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4345 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4346 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4347 "expected %d, got %d (%s:%d)\n",
4348 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4350 lf.lfItalic = FALSE;
4351 lf.lfEscapement = lf.lfOrientation = 2700;
4352 hfont = CreateFontIndirectA(&lf);
4353 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4354 DeleteObject(SelectObject(hdc, hfont));
4355 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4356 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4357 ok(gm2.gmCellIncY == -lf.lfHeight,
4358 "expected %d, got %d (%s:%d)\n",
4359 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4361 hfont = SelectObject(hdc, old_hfont);
4362 DeleteObject(hfont);
4365 DeleteDC(hdc);
4368 /* bug #9995: there is a limit to the character width that can be specified */
4369 static void test_GetTextMetrics2(const char *fontname, int font_height)
4371 HFONT of, hf;
4372 HDC hdc;
4373 TEXTMETRICA tm;
4374 BOOL ret;
4375 int ave_width, height, width, ratio, scale;
4377 if (!is_truetype_font_installed( fontname)) {
4378 skip("%s is not installed\n", fontname);
4379 return;
4381 hdc = CreateCompatibleDC(0);
4382 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4383 /* select width = 0 */
4384 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4385 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4386 DEFAULT_QUALITY, VARIABLE_PITCH,
4387 fontname);
4388 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4389 of = SelectObject( hdc, hf);
4390 ret = GetTextMetricsA( hdc, &tm);
4391 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4392 height = tm.tmHeight;
4393 ave_width = tm.tmAveCharWidth;
4394 SelectObject( hdc, of);
4395 DeleteObject( hf);
4397 trace("height %d, ave width %d\n", height, ave_width);
4399 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4401 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4402 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4403 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4404 ok(hf != 0, "CreateFont failed\n");
4405 of = SelectObject(hdc, hf);
4406 ret = GetTextMetricsA(hdc, &tm);
4407 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4408 SelectObject(hdc, of);
4409 DeleteObject(hf);
4411 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4412 break;
4415 DeleteDC(hdc);
4417 ratio = width / height;
4418 scale = width / ave_width;
4420 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4421 width, height, ratio, width, ave_width, scale);
4423 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4426 static void test_CreateFontIndirect(void)
4428 LOGFONTA lf, getobj_lf;
4429 int ret, i;
4430 HFONT hfont;
4431 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4433 memset(&lf, 0, sizeof(lf));
4434 lf.lfCharSet = ANSI_CHARSET;
4435 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4436 lf.lfHeight = 16;
4437 lf.lfWidth = 16;
4438 lf.lfQuality = DEFAULT_QUALITY;
4439 lf.lfItalic = FALSE;
4440 lf.lfWeight = FW_DONTCARE;
4442 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4444 lstrcpyA(lf.lfFaceName, TestName[i]);
4445 hfont = CreateFontIndirectA(&lf);
4446 ok(hfont != 0, "CreateFontIndirectA failed\n");
4447 SetLastError(0xdeadbeef);
4448 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4449 ok(ret, "GetObject failed: %d\n", GetLastError());
4450 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4451 ok(lf.lfWeight == getobj_lf.lfWeight ||
4452 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4453 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4454 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4455 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4456 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4457 DeleteObject(hfont);
4461 static void test_CreateFontIndirectEx(void)
4463 ENUMLOGFONTEXDVA lfex;
4464 HFONT hfont;
4466 if (!pCreateFontIndirectExA)
4468 win_skip("CreateFontIndirectExA is not available\n");
4469 return;
4472 if (!is_truetype_font_installed("Arial"))
4474 skip("Arial is not installed\n");
4475 return;
4478 SetLastError(0xdeadbeef);
4479 hfont = pCreateFontIndirectExA(NULL);
4480 ok(hfont == NULL, "got %p\n", hfont);
4481 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4483 memset(&lfex, 0, sizeof(lfex));
4484 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
4485 hfont = pCreateFontIndirectExA(&lfex);
4486 ok(hfont != 0, "CreateFontIndirectEx failed\n");
4487 if (hfont)
4488 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
4489 DeleteObject(hfont);
4492 static void free_font(void *font)
4494 UnmapViewOfFile(font);
4497 static void *load_font(const char *font_name, DWORD *font_size)
4499 char file_name[MAX_PATH];
4500 HANDLE file, mapping;
4501 void *font;
4503 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
4504 strcat(file_name, "\\fonts\\");
4505 strcat(file_name, font_name);
4507 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4508 if (file == INVALID_HANDLE_VALUE) return NULL;
4510 *font_size = GetFileSize(file, NULL);
4512 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4513 if (!mapping)
4515 CloseHandle(file);
4516 return NULL;
4519 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4521 CloseHandle(file);
4522 CloseHandle(mapping);
4523 return font;
4526 static void test_AddFontMemResource(void)
4528 void *font;
4529 DWORD font_size, num_fonts;
4530 HANDLE ret;
4531 BOOL bRet;
4533 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4535 win_skip("AddFontMemResourceEx is not available on this platform\n");
4536 return;
4539 font = load_font("sserife.fon", &font_size);
4540 if (!font)
4542 skip("Unable to locate and load font sserife.fon\n");
4543 return;
4546 SetLastError(0xdeadbeef);
4547 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4548 ok(!ret, "AddFontMemResourceEx should fail\n");
4549 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4550 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4551 GetLastError());
4553 SetLastError(0xdeadbeef);
4554 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4555 ok(!ret, "AddFontMemResourceEx should fail\n");
4556 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4557 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4558 GetLastError());
4560 SetLastError(0xdeadbeef);
4561 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4562 ok(!ret, "AddFontMemResourceEx should fail\n");
4563 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4564 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4565 GetLastError());
4567 SetLastError(0xdeadbeef);
4568 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4569 ok(!ret, "AddFontMemResourceEx should fail\n");
4570 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4571 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4572 GetLastError());
4574 SetLastError(0xdeadbeef);
4575 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4576 ok(!ret, "AddFontMemResourceEx should fail\n");
4577 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4578 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4579 GetLastError());
4581 SetLastError(0xdeadbeef);
4582 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4583 ok(!ret, "AddFontMemResourceEx should fail\n");
4584 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4585 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4586 GetLastError());
4588 num_fonts = 0xdeadbeef;
4589 SetLastError(0xdeadbeef);
4590 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4591 ok(!ret, "AddFontMemResourceEx should fail\n");
4592 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4593 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4594 GetLastError());
4595 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4597 if (0) /* hangs under windows 2000 */
4599 num_fonts = 0xdeadbeef;
4600 SetLastError(0xdeadbeef);
4601 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4602 ok(!ret, "AddFontMemResourceEx should fail\n");
4603 ok(GetLastError() == 0xdeadbeef,
4604 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4605 GetLastError());
4606 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4609 num_fonts = 0xdeadbeef;
4610 SetLastError(0xdeadbeef);
4611 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4612 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4613 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4614 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4616 free_font(font);
4618 SetLastError(0xdeadbeef);
4619 bRet = pRemoveFontMemResourceEx(ret);
4620 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4622 /* test invalid pointer to number of loaded fonts */
4623 font = load_font("sserife.fon", &font_size);
4624 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4626 SetLastError(0xdeadbeef);
4627 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4628 ok(!ret, "AddFontMemResourceEx should fail\n");
4629 ok(GetLastError() == 0xdeadbeef,
4630 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4631 GetLastError());
4633 SetLastError(0xdeadbeef);
4634 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4635 ok(!ret, "AddFontMemResourceEx should fail\n");
4636 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4637 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4638 GetLastError());
4640 free_font(font);
4643 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4645 LOGFONTA *lf;
4647 if (type != TRUETYPE_FONTTYPE) return 1;
4649 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4651 lf = (LOGFONTA *)lparam;
4652 *lf = *elf;
4653 return 0;
4656 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4658 int ret;
4659 LOGFONTA *lf;
4661 if (type != TRUETYPE_FONTTYPE) return 1;
4663 lf = (LOGFONTA *)lparam;
4664 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
4665 if(ret == 0)
4667 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4668 *lf = *elf;
4669 return 0;
4671 return 1;
4674 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4676 return lparam;
4679 static void test_EnumFonts(void)
4681 int ret;
4682 LOGFONTA lf;
4683 HDC hdc;
4684 struct enum_fullname_data efnd;
4686 if (!is_truetype_font_installed("Arial"))
4688 skip("Arial is not installed\n");
4689 return;
4692 /* Windows uses localized font face names, so Arial Bold won't be found */
4693 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4695 skip("User locale is not English, skipping the test\n");
4696 return;
4699 hdc = CreateCompatibleDC(0);
4701 /* check that the enumproc's retval is returned */
4702 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4703 ok(ret == 0xcafe, "got %08x\n", ret);
4705 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4706 ok(!ret, "font Arial is not enumerated\n");
4707 ret = strcmp(lf.lfFaceName, "Arial");
4708 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4709 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4711 strcpy(lf.lfFaceName, "Arial");
4712 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4713 ok(!ret, "font Arial is not enumerated\n");
4714 ret = strcmp(lf.lfFaceName, "Arial");
4715 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4716 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4718 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4719 ok(!ret, "font Arial Bold is not enumerated\n");
4720 ret = strcmp(lf.lfFaceName, "Arial");
4721 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4722 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4724 strcpy(lf.lfFaceName, "Arial Bold");
4725 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4726 ok(ret, "font Arial Bold should not be enumerated\n");
4728 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4729 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4730 ret = strcmp(lf.lfFaceName, "Arial");
4731 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4732 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4734 strcpy(lf.lfFaceName, "Arial Bold Italic");
4735 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4736 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4738 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4739 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4741 strcpy(lf.lfFaceName, "Arial Italic Bold");
4742 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4743 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4745 /* MS Shell Dlg and MS Shell Dlg 2 must exist */
4746 memset(&lf, 0, sizeof(lf));
4747 lf.lfCharSet = DEFAULT_CHARSET;
4749 memset(&efnd, 0, sizeof(efnd));
4750 strcpy(lf.lfFaceName, "MS Shell Dlg");
4751 ret = EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4752 ok(ret, "font MS Shell Dlg is not enumerated\n");
4753 ret = strcmp((char*)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
4754 todo_wine ok(!ret, "expected MS Shell Dlg got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
4755 ret = strcmp((char*)efnd.elf[0].elfFullName, "MS Shell Dlg");
4756 ok(ret, "did not expect MS Shell Dlg\n");
4758 memset(&efnd, 0, sizeof(efnd));
4759 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
4760 ret = EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4761 ok(ret, "font MS Shell Dlg 2 is not enumerated\n");
4762 ret = strcmp((char*)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
4763 todo_wine ok(!ret, "expected MS Shell Dlg 2 got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
4764 ret = strcmp((char*)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
4765 ok(ret, "did not expect MS Shell Dlg 2\n");
4767 DeleteDC(hdc);
4770 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4772 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
4773 const char *fullname = (const char *)lParam;
4775 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4777 return 1;
4780 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4782 HDC hdc = GetDC(0);
4783 BOOL ret = FALSE;
4785 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4786 ret = TRUE;
4788 ReleaseDC(0, hdc);
4789 return ret;
4792 static void test_fullname(void)
4794 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4795 WCHAR bufW[LF_FULLFACESIZE];
4796 char bufA[LF_FULLFACESIZE];
4797 HFONT hfont, of;
4798 LOGFONTA lf;
4799 HDC hdc;
4800 int i;
4801 DWORD ret;
4803 hdc = CreateCompatibleDC(0);
4804 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4806 memset(&lf, 0, sizeof(lf));
4807 lf.lfCharSet = ANSI_CHARSET;
4808 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4809 lf.lfHeight = 16;
4810 lf.lfWidth = 16;
4811 lf.lfQuality = DEFAULT_QUALITY;
4812 lf.lfItalic = FALSE;
4813 lf.lfWeight = FW_DONTCARE;
4815 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4817 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4819 skip("%s is not installed\n", TestName[i]);
4820 continue;
4823 lstrcpyA(lf.lfFaceName, TestName[i]);
4824 hfont = CreateFontIndirectA(&lf);
4825 ok(hfont != 0, "CreateFontIndirectA failed\n");
4827 of = SelectObject(hdc, hfont);
4828 bufW[0] = 0;
4829 bufA[0] = 0;
4830 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4831 ok(ret, "face full name could not be read\n");
4832 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4833 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4834 SelectObject(hdc, of);
4835 DeleteObject(hfont);
4837 DeleteDC(hdc);
4840 static WCHAR *prepend_at(WCHAR *family)
4842 if (!family)
4843 return NULL;
4845 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4846 family[0] = '@';
4847 return family;
4850 static void test_fullname2_helper(const char *Family)
4852 char *FamilyName, *FaceName, *StyleName, *otmStr;
4853 struct enum_fullname_data efnd;
4854 WCHAR *bufW;
4855 char *bufA;
4856 HFONT hfont, of;
4857 LOGFONTA lf;
4858 HDC hdc;
4859 int i;
4860 DWORD otm_size, ret, buf_size;
4861 OUTLINETEXTMETRICA *otm;
4862 BOOL want_vertical, get_vertical;
4863 want_vertical = ( Family[0] == '@' );
4865 hdc = CreateCompatibleDC(0);
4866 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4868 memset(&lf, 0, sizeof(lf));
4869 lf.lfCharSet = DEFAULT_CHARSET;
4870 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4871 lf.lfHeight = 16;
4872 lf.lfWidth = 16;
4873 lf.lfQuality = DEFAULT_QUALITY;
4874 lf.lfItalic = FALSE;
4875 lf.lfWeight = FW_DONTCARE;
4876 strcpy(lf.lfFaceName, Family);
4877 efnd.total = 0;
4878 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4879 if (efnd.total == 0)
4880 skip("%s is not installed\n", lf.lfFaceName);
4882 for (i = 0; i < efnd.total; i++)
4884 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4885 FaceName = (char *)efnd.elf[i].elfFullName;
4886 StyleName = (char *)efnd.elf[i].elfStyle;
4888 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4890 get_vertical = ( FamilyName[0] == '@' );
4891 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4893 lstrcpyA(lf.lfFaceName, FaceName);
4894 hfont = CreateFontIndirectA(&lf);
4895 ok(hfont != 0, "CreateFontIndirectA failed\n");
4897 of = SelectObject(hdc, hfont);
4898 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4899 ok(buf_size != GDI_ERROR, "no name table found\n");
4900 if (buf_size == GDI_ERROR) continue;
4902 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4903 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4905 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4906 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4907 memset(otm, 0, otm_size);
4908 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
4909 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4910 if (ret == 0) continue;
4912 bufW[0] = 0;
4913 bufA[0] = 0;
4914 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4915 if (!ret)
4917 trace("no localized FONT_FAMILY found.\n");
4918 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4920 ok(ret, "FAMILY (family name) could not be read\n");
4921 if (want_vertical) bufW = prepend_at(bufW);
4922 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4923 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4924 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4925 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4927 bufW[0] = 0;
4928 bufA[0] = 0;
4929 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4930 if (!ret)
4932 trace("no localized FULL_NAME found.\n");
4933 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4935 ok(ret, "FULL_NAME (face name) could not be read\n");
4936 if (want_vertical) bufW = prepend_at(bufW);
4937 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4938 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4939 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4940 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4942 bufW[0] = 0;
4943 bufA[0] = 0;
4944 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4945 if (!ret)
4947 trace("no localized FONT_SUBFAMILY found.\n");
4948 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4950 ok(ret, "SUBFAMILY (style name) could not be read\n");
4951 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4952 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4953 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4954 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4956 bufW[0] = 0;
4957 bufA[0] = 0;
4958 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4959 if (!ret)
4961 trace("no localized UNIQUE_ID found.\n");
4962 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4964 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4965 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4966 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4967 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4969 SelectObject(hdc, of);
4970 DeleteObject(hfont);
4972 HeapFree(GetProcessHeap(), 0, otm);
4973 HeapFree(GetProcessHeap(), 0, bufW);
4974 HeapFree(GetProcessHeap(), 0, bufA);
4976 DeleteDC(hdc);
4979 static void test_fullname2(void)
4981 test_fullname2_helper("Arial");
4982 test_fullname2_helper("DejaVu Sans");
4983 test_fullname2_helper("Lucida Sans");
4984 test_fullname2_helper("Tahoma");
4985 test_fullname2_helper("Webdings");
4986 test_fullname2_helper("Wingdings");
4987 test_fullname2_helper("SimSun");
4988 test_fullname2_helper("NSimSun");
4989 test_fullname2_helper("MingLiu");
4990 test_fullname2_helper("PMingLiu");
4991 test_fullname2_helper("WenQuanYi Micro Hei");
4992 test_fullname2_helper("MS UI Gothic");
4993 test_fullname2_helper("Ume UI Gothic");
4994 test_fullname2_helper("MS Gothic");
4995 test_fullname2_helper("Ume Gothic");
4996 test_fullname2_helper("MS PGothic");
4997 test_fullname2_helper("Ume P Gothic");
4998 test_fullname2_helper("Gulim");
4999 test_fullname2_helper("Batang");
5000 test_fullname2_helper("UnBatang");
5001 test_fullname2_helper("UnDotum");
5002 test_fullname2_helper("@SimSun");
5003 test_fullname2_helper("@NSimSun");
5004 test_fullname2_helper("@MingLiu");
5005 test_fullname2_helper("@PMingLiu");
5006 test_fullname2_helper("@WenQuanYi Micro Hei");
5007 test_fullname2_helper("@MS UI Gothic");
5008 test_fullname2_helper("@Ume UI Gothic");
5009 test_fullname2_helper("@MS Gothic");
5010 test_fullname2_helper("@Ume Gothic");
5011 test_fullname2_helper("@MS PGothic");
5012 test_fullname2_helper("@Ume P Gothic");
5013 test_fullname2_helper("@Gulim");
5014 test_fullname2_helper("@Batang");
5015 test_fullname2_helper("@UnBatang");
5016 test_fullname2_helper("@UnDotum");
5020 static void test_GetGlyphOutline_empty_contour(void)
5022 HDC hdc;
5023 LOGFONTA lf;
5024 HFONT hfont, hfont_prev;
5025 TTPOLYGONHEADER *header;
5026 GLYPHMETRICS gm;
5027 char buf[1024];
5028 DWORD ret;
5030 memset(&lf, 0, sizeof(lf));
5031 lf.lfHeight = 72;
5032 lstrcpyA(lf.lfFaceName, "wine_test");
5034 hfont = CreateFontIndirectA(&lf);
5035 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5037 hdc = GetDC(NULL);
5039 hfont_prev = SelectObject(hdc, hfont);
5040 ok(hfont_prev != NULL, "SelectObject failed\n");
5042 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5043 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5045 header = (TTPOLYGONHEADER*)buf;
5046 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5047 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5048 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5049 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5050 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5051 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5052 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5053 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5055 SelectObject(hdc, hfont_prev);
5056 DeleteObject(hfont);
5057 ReleaseDC(NULL, hdc);
5060 static void test_GetGlyphOutline_metric_clipping(void)
5062 HDC hdc;
5063 LOGFONTA lf;
5064 HFONT hfont, hfont_prev;
5065 GLYPHMETRICS gm;
5066 TEXTMETRICA tm;
5067 DWORD ret;
5069 memset(&lf, 0, sizeof(lf));
5070 lf.lfHeight = 72;
5071 lstrcpyA(lf.lfFaceName, "wine_test");
5073 SetLastError(0xdeadbeef);
5074 hfont = CreateFontIndirectA(&lf);
5075 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5077 hdc = GetDC(NULL);
5079 hfont_prev = SelectObject(hdc, hfont);
5080 ok(hfont_prev != NULL, "SelectObject failed\n");
5082 SetLastError(0xdeadbeef);
5083 ret = GetTextMetricsA(hdc, &tm);
5084 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5086 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5087 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5088 "Glyph top(%d) exceeds ascent(%d)\n",
5089 gm.gmptGlyphOrigin.y, tm.tmAscent);
5090 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5091 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5092 "Glyph bottom(%d) exceeds descent(%d)\n",
5093 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5095 SelectObject(hdc, hfont_prev);
5096 DeleteObject(hfont);
5097 ReleaseDC(NULL, hdc);
5100 static void test_CreateScalableFontResource(void)
5102 char ttf_name[MAX_PATH];
5103 char tmp_path[MAX_PATH];
5104 char fot_name[MAX_PATH];
5105 char *file_part;
5106 DWORD ret;
5107 int i;
5109 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5111 win_skip("AddFontResourceExA is not available on this platform\n");
5112 return;
5115 if (!write_ttf_file("wine_test.ttf", ttf_name))
5117 skip("Failed to create ttf file for testing\n");
5118 return;
5121 trace("created %s\n", ttf_name);
5123 ret = is_truetype_font_installed("wine_test");
5124 ok(!ret, "font wine_test should not be enumerated\n");
5126 ret = GetTempPathA(MAX_PATH, tmp_path);
5127 ok(ret, "GetTempPath() error %d\n", GetLastError());
5128 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5129 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5131 ret = GetFileAttributesA(fot_name);
5132 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5134 SetLastError(0xdeadbeef);
5135 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5136 ok(!ret, "CreateScalableFontResource() should fail\n");
5137 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5139 SetLastError(0xdeadbeef);
5140 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5141 ok(!ret, "CreateScalableFontResource() should fail\n");
5142 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5144 file_part = strrchr(ttf_name, '\\');
5145 SetLastError(0xdeadbeef);
5146 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5147 ok(!ret, "CreateScalableFontResource() should fail\n");
5148 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5150 SetLastError(0xdeadbeef);
5151 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5152 ok(!ret, "CreateScalableFontResource() should fail\n");
5153 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5155 SetLastError(0xdeadbeef);
5156 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5157 ok(!ret, "CreateScalableFontResource() should fail\n");
5158 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5160 ret = DeleteFileA(fot_name);
5161 ok(ret, "DeleteFile() error %d\n", GetLastError());
5163 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5164 ok(!ret, "RemoveFontResourceEx() should fail\n");
5166 /* test public font resource */
5167 SetLastError(0xdeadbeef);
5168 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5169 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5171 ret = is_truetype_font_installed("wine_test");
5172 ok(!ret, "font wine_test should not be enumerated\n");
5174 SetLastError(0xdeadbeef);
5175 ret = pAddFontResourceExA(fot_name, 0, 0);
5176 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5178 ret = is_truetype_font_installed("wine_test");
5179 ok(ret, "font wine_test should be enumerated\n");
5181 test_GetGlyphOutline_empty_contour();
5182 test_GetGlyphOutline_metric_clipping();
5184 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5185 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5187 SetLastError(0xdeadbeef);
5188 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5189 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5191 ret = is_truetype_font_installed("wine_test");
5192 ok(!ret, "font wine_test should not be enumerated\n");
5194 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5195 ok(!ret, "RemoveFontResourceEx() should fail\n");
5197 /* test refcounting */
5198 for (i = 0; i < 5; i++)
5200 SetLastError(0xdeadbeef);
5201 ret = pAddFontResourceExA(fot_name, 0, 0);
5202 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5204 for (i = 0; i < 5; i++)
5206 SetLastError(0xdeadbeef);
5207 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5208 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5210 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5211 ok(!ret, "RemoveFontResourceEx() should fail\n");
5213 DeleteFileA(fot_name);
5215 /* test hidden font resource */
5216 SetLastError(0xdeadbeef);
5217 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5218 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5220 ret = is_truetype_font_installed("wine_test");
5221 ok(!ret, "font wine_test should not be enumerated\n");
5223 SetLastError(0xdeadbeef);
5224 ret = pAddFontResourceExA(fot_name, 0, 0);
5225 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5227 ret = is_truetype_font_installed("wine_test");
5228 todo_wine
5229 ok(!ret, "font wine_test should not be enumerated\n");
5231 /* XP allows removing a private font added with 0 flags */
5232 SetLastError(0xdeadbeef);
5233 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5234 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5236 ret = is_truetype_font_installed("wine_test");
5237 ok(!ret, "font wine_test should not be enumerated\n");
5239 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5240 ok(!ret, "RemoveFontResourceEx() should fail\n");
5242 DeleteFileA(fot_name);
5243 DeleteFileA(ttf_name);
5246 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5248 LOGFONTA lf;
5249 HFONT hfont, hfont_prev;
5250 HDC hdc;
5251 char facename[100];
5252 DWORD ret;
5253 static const WCHAR str[] = { 0x2025 };
5255 *installed = is_truetype_font_installed(name);
5257 lf.lfHeight = -18;
5258 lf.lfWidth = 0;
5259 lf.lfEscapement = 0;
5260 lf.lfOrientation = 0;
5261 lf.lfWeight = FW_DONTCARE;
5262 lf.lfItalic = 0;
5263 lf.lfUnderline = 0;
5264 lf.lfStrikeOut = 0;
5265 lf.lfCharSet = DEFAULT_CHARSET;
5266 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5267 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5268 lf.lfQuality = DEFAULT_QUALITY;
5269 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5270 strcpy(lf.lfFaceName, name);
5272 hfont = CreateFontIndirectA(&lf);
5273 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5275 hdc = GetDC(NULL);
5277 hfont_prev = SelectObject(hdc, hfont);
5278 ok(hfont_prev != NULL, "SelectObject failed\n");
5280 ret = GetTextFaceA(hdc, sizeof facename, facename);
5281 ok(ret, "GetTextFaceA failed\n");
5282 *selected = !strcmp(facename, name);
5284 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5285 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5286 if (!*selected)
5287 memset(gm, 0, sizeof *gm);
5289 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5290 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5292 SelectObject(hdc, hfont_prev);
5293 DeleteObject(hfont);
5294 ReleaseDC(NULL, hdc);
5297 static void check_vertical_metrics(const char *face)
5299 LOGFONTA lf;
5300 HFONT hfont, hfont_prev;
5301 HDC hdc;
5302 DWORD ret;
5303 GLYPHMETRICS rgm, vgm;
5304 const UINT code = 0x5EAD, height = 1000;
5305 WORD idx;
5306 ABC abc;
5307 OUTLINETEXTMETRICA otm;
5308 USHORT numOfLongVerMetrics;
5310 hdc = GetDC(NULL);
5312 memset(&lf, 0, sizeof(lf));
5313 strcpy(lf.lfFaceName, face);
5314 lf.lfHeight = -height;
5315 lf.lfCharSet = DEFAULT_CHARSET;
5316 lf.lfEscapement = lf.lfOrientation = 900;
5317 hfont = CreateFontIndirectA(&lf);
5318 hfont_prev = SelectObject(hdc, hfont);
5319 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5320 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5321 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5322 ok(ret, "GetCharABCWidthsW failed\n");
5323 DeleteObject(SelectObject(hdc, hfont_prev));
5325 memset(&lf, 0, sizeof(lf));
5326 strcpy(lf.lfFaceName, "@");
5327 strcat(lf.lfFaceName, face);
5328 lf.lfHeight = -height;
5329 lf.lfCharSet = DEFAULT_CHARSET;
5330 hfont = CreateFontIndirectA(&lf);
5331 hfont_prev = SelectObject(hdc, hfont);
5332 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5333 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5335 memset(&otm, 0, sizeof(otm));
5336 otm.otmSize = sizeof(otm);
5337 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5338 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5340 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5341 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5342 int offset;
5343 SHORT topSideBearing;
5345 if (!pGetGlyphIndicesW) {
5346 win_skip("GetGlyphIndices is not available on this platform\n");
5348 else {
5349 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5350 ok(ret != 0, "GetGlyphIndicesW failed\n");
5351 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5352 if (numOfLongVerMetrics > idx)
5353 offset = idx * 2 + 1;
5354 else
5355 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5356 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5357 &topSideBearing, sizeof(SHORT));
5358 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5359 topSideBearing = GET_BE_WORD(topSideBearing);
5360 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5361 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5362 "expected %d, got %d\n",
5363 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5366 else
5368 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5369 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5370 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5373 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
5374 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
5375 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5376 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
5378 DeleteObject(SelectObject(hdc, hfont_prev));
5379 ReleaseDC(NULL, hdc);
5382 static void test_vertical_font(void)
5384 char ttf_name[MAX_PATH];
5385 int num, i;
5386 BOOL ret, installed, selected;
5387 GLYPHMETRICS gm;
5388 WORD hgi, vgi;
5389 const char* face_list[] = {
5390 "@WineTestVertical", /* has vmtx table */
5391 "@Ume Gothic", /* doesn't have vmtx table */
5392 "@MS UI Gothic", /* has vmtx table, available on native */
5395 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
5397 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5398 return;
5401 if (!write_ttf_file("vertical.ttf", ttf_name))
5403 skip("Failed to create ttf file for testing\n");
5404 return;
5407 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
5408 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5410 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
5411 ok(installed, "WineTestVertical is not installed\n");
5412 ok(selected, "WineTestVertical is not selected\n");
5413 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5414 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5415 gm.gmBlackBoxX, gm.gmBlackBoxY);
5417 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
5418 ok(installed, "@WineTestVertical is not installed\n");
5419 ok(selected, "@WineTestVertical is not selected\n");
5420 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5421 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5422 gm.gmBlackBoxX, gm.gmBlackBoxY);
5424 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
5426 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
5427 const char* face = face_list[i];
5428 if (!is_truetype_font_installed(face)) {
5429 skip("%s is not installed\n", face);
5430 continue;
5432 trace("Testing %s...\n", face);
5433 check_vertical_metrics(&face[1]);
5436 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
5437 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5439 DeleteFileA(ttf_name);
5442 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
5443 DWORD type, LPARAM lParam)
5445 if (lf->lfFaceName[0] == '@') {
5446 return 0;
5448 return 1;
5451 static void test_east_asian_font_selection(void)
5453 HDC hdc;
5454 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
5455 GB2312_CHARSET, CHINESEBIG5_CHARSET };
5456 size_t i;
5458 hdc = GetDC(NULL);
5460 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
5462 LOGFONTA lf;
5463 HFONT hfont;
5464 char face_name[LF_FACESIZE];
5465 int ret;
5467 memset(&lf, 0, sizeof lf);
5468 lf.lfFaceName[0] = '\0';
5469 lf.lfCharSet = charset[i];
5471 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
5473 skip("Vertical font for charset %u is not installed\n", charset[i]);
5474 continue;
5477 hfont = CreateFontIndirectA(&lf);
5478 hfont = SelectObject(hdc, hfont);
5479 memset(face_name, 0, sizeof face_name);
5480 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5481 ok(ret && face_name[0] != '@',
5482 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
5483 DeleteObject(SelectObject(hdc, hfont));
5485 memset(&lf, 0, sizeof lf);
5486 strcpy(lf.lfFaceName, "@");
5487 lf.lfCharSet = charset[i];
5488 hfont = CreateFontIndirectA(&lf);
5489 hfont = SelectObject(hdc, hfont);
5490 memset(face_name, 0, sizeof face_name);
5491 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5492 ok(ret && face_name[0] == '@',
5493 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
5494 DeleteObject(SelectObject(hdc, hfont));
5496 ReleaseDC(NULL, hdc);
5499 static int get_font_dpi(const LOGFONTA *lf, int *height)
5501 HDC hdc = CreateCompatibleDC(0);
5502 HFONT hfont;
5503 TEXTMETRICA tm;
5504 int ret;
5506 hfont = CreateFontIndirectA(lf);
5507 ok(hfont != 0, "CreateFontIndirect failed\n");
5509 SelectObject(hdc, hfont);
5510 ret = GetTextMetricsA(hdc, &tm);
5511 ok(ret, "GetTextMetrics failed\n");
5512 ret = tm.tmDigitizedAspectX;
5513 if (height) *height = tm.tmHeight;
5515 DeleteDC(hdc);
5516 DeleteObject(hfont);
5518 return ret;
5521 static void test_stock_fonts(void)
5523 static const int font[] =
5525 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
5526 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5528 static const struct test_data
5530 int charset, weight, height, height_pixels, dpi;
5531 const char face_name[LF_FACESIZE];
5532 } td[][11] =
5534 { /* ANSI_FIXED_FONT */
5535 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
5536 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
5537 { 0 }
5539 { /* ANSI_VAR_FONT */
5540 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
5541 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
5542 { 0 }
5544 { /* SYSTEM_FONT */
5545 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5546 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5547 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5548 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5549 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5550 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5551 { 0 }
5553 { /* DEVICE_DEFAULT_FONT */
5554 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5555 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5556 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5557 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5558 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5559 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5560 { 0 }
5562 { /* DEFAULT_GUI_FONT */
5563 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
5564 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
5565 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
5566 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
5567 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
5568 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
5569 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
5570 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
5571 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5572 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
5573 { 0 }
5576 int i, j;
5578 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
5580 HFONT hfont;
5581 LOGFONTA lf;
5582 int ret, height;
5584 hfont = GetStockObject(font[i]);
5585 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
5587 ret = GetObjectA(hfont, sizeof(lf), &lf);
5588 if (ret != sizeof(lf))
5590 /* NT4 */
5591 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
5592 continue;
5595 for (j = 0; td[i][j].face_name[0] != 0; j++)
5597 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
5599 continue;
5602 ret = get_font_dpi(&lf, &height);
5603 if (ret != td[i][j].dpi)
5605 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5606 i, j, lf.lfFaceName, ret, td[i][j].dpi);
5607 continue;
5610 /* FIXME: Remove once Wine is fixed */
5611 if (td[i][j].dpi != 96 &&
5612 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5613 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
5614 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5615 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
5616 todo_wine
5617 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5618 else
5619 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5621 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
5622 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
5623 if (td[i][j].face_name[0] == '?')
5625 /* Wine doesn't have this font, skip this case for now.
5626 Actually, the face name is localized on Windows and varies
5627 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5628 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
5630 else
5632 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);
5634 break;
5639 static void test_max_height(void)
5641 HDC hdc;
5642 LOGFONTA lf;
5643 HFONT hfont, hfont_old;
5644 TEXTMETRICA tm1, tm;
5645 BOOL r;
5646 LONG invalid_height[] = { -65536, -123456, 123456 };
5647 size_t i;
5649 memset(&tm1, 0, sizeof(tm1));
5650 memset(&lf, 0, sizeof(lf));
5651 strcpy(lf.lfFaceName, "Tahoma");
5652 lf.lfHeight = -1;
5654 hdc = GetDC(NULL);
5656 /* get 1 ppem value */
5657 hfont = CreateFontIndirectA(&lf);
5658 hfont_old = SelectObject(hdc, hfont);
5659 r = GetTextMetricsA(hdc, &tm1);
5660 ok(r, "GetTextMetrics failed\n");
5661 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5662 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5663 DeleteObject(SelectObject(hdc, hfont_old));
5665 /* test the largest value */
5666 lf.lfHeight = -((1 << 16) - 1);
5667 hfont = CreateFontIndirectA(&lf);
5668 hfont_old = SelectObject(hdc, hfont);
5669 memset(&tm, 0, sizeof(tm));
5670 r = GetTextMetricsA(hdc, &tm);
5671 ok(r, "GetTextMetrics failed\n");
5672 ok(tm.tmHeight > tm1.tmHeight,
5673 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5674 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
5675 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5676 DeleteObject(SelectObject(hdc, hfont_old));
5678 /* test an invalid value */
5679 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
5680 lf.lfHeight = invalid_height[i];
5681 hfont = CreateFontIndirectA(&lf);
5682 hfont_old = SelectObject(hdc, hfont);
5683 memset(&tm, 0, sizeof(tm));
5684 r = GetTextMetricsA(hdc, &tm);
5685 ok(r, "GetTextMetrics failed\n");
5686 ok(tm.tmHeight == tm1.tmHeight,
5687 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5688 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
5689 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5690 DeleteObject(SelectObject(hdc, hfont_old));
5693 ReleaseDC(NULL, hdc);
5694 return;
5697 static void test_vertical_order(void)
5699 struct enum_font_data efd;
5700 LOGFONTA lf;
5701 HDC hdc;
5702 int i, j;
5704 hdc = CreateCompatibleDC(0);
5705 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5707 memset(&lf, 0, sizeof(lf));
5708 lf.lfCharSet = DEFAULT_CHARSET;
5709 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5710 lf.lfHeight = 16;
5711 lf.lfWidth = 16;
5712 lf.lfQuality = DEFAULT_QUALITY;
5713 lf.lfItalic = FALSE;
5714 lf.lfWeight = FW_DONTCARE;
5715 efd.total = 0;
5716 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
5717 for (i = 0; i < efd.total; i++)
5719 if (efd.lf[i].lfFaceName[0] != '@') continue;
5720 for (j = 0; j < efd.total; j++)
5722 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
5724 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
5725 break;
5729 DeleteDC( hdc );
5732 static void test_GetCharWidth32(void)
5734 BOOL ret;
5735 HDC hdc;
5736 LOGFONTA lf;
5737 HFONT hfont;
5738 INT bufferA;
5739 INT bufferW;
5740 HWND hwnd;
5742 if (!pGetCharWidth32A || !pGetCharWidth32W)
5744 win_skip("GetCharWidth32A/W not available on this platform\n");
5745 return;
5748 memset(&lf, 0, sizeof(lf));
5749 strcpy(lf.lfFaceName, "System");
5750 lf.lfHeight = 20;
5752 hfont = CreateFontIndirectA(&lf);
5753 hdc = GetDC(0);
5754 hfont = SelectObject(hdc, hfont);
5756 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5757 ok(ret, "GetCharWidth32W should have succeeded\n");
5758 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
5759 ok(ret, "GetCharWidth32A should have succeeded\n");
5760 ok (bufferA == bufferW, "Widths should be the same\n");
5761 ok (bufferA > 0," Width should be greater than zero\n");
5763 hfont = SelectObject(hdc, hfont);
5764 DeleteObject(hfont);
5765 ReleaseDC(NULL, hdc);
5767 memset(&lf, 0, sizeof(lf));
5768 strcpy(lf.lfFaceName, "Tahoma");
5769 lf.lfHeight = 20;
5771 hfont = CreateFontIndirectA(&lf);
5772 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
5773 0, 0, 0, NULL);
5774 hdc = GetDC(hwnd);
5775 SetMapMode( hdc, MM_ANISOTROPIC );
5776 SelectObject(hdc, hfont);
5778 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5779 ok(ret, "GetCharWidth32W should have succeeded\n");
5780 ok (bufferW > 0," Width should be greater than zero\n");
5781 SetWindowExtEx(hdc, -1,-1,NULL);
5782 SetGraphicsMode(hdc, GM_COMPATIBLE);
5783 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5784 ok(ret, "GetCharWidth32W should have succeeded\n");
5785 ok (bufferW > 0," Width should be greater than zero\n");
5786 SetGraphicsMode(hdc, GM_ADVANCED);
5787 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5788 ok(ret, "GetCharWidth32W should have succeeded\n");
5789 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
5790 SetWindowExtEx(hdc, 1,1,NULL);
5791 SetGraphicsMode(hdc, GM_COMPATIBLE);
5792 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5793 ok(ret, "GetCharWidth32W should have succeeded\n");
5794 ok (bufferW > 0," Width should be greater than zero\n");
5795 SetGraphicsMode(hdc, GM_ADVANCED);
5796 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5797 ok(ret, "GetCharWidth32W should have succeeded\n");
5798 ok (bufferW > 0," Width should be greater than zero\n");
5800 ReleaseDC(hwnd, hdc);
5801 DestroyWindow(hwnd);
5803 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
5804 0, 0, 0, NULL);
5805 hdc = GetDC(hwnd);
5806 SetMapMode( hdc, MM_ANISOTROPIC );
5807 SelectObject(hdc, hfont);
5809 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5810 ok(ret, "GetCharWidth32W should have succeeded\n");
5811 ok (bufferW > 0," Width should be greater than zero\n");
5812 SetWindowExtEx(hdc, -1,-1,NULL);
5813 SetGraphicsMode(hdc, GM_COMPATIBLE);
5814 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5815 ok(ret, "GetCharWidth32W should have succeeded\n");
5816 ok (bufferW > 0," Width should be greater than zero\n");
5817 SetGraphicsMode(hdc, GM_ADVANCED);
5818 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5819 ok(ret, "GetCharWidth32W should have succeeded\n");
5820 ok (bufferW > 0," Width should be greater than zero\n");
5821 SetWindowExtEx(hdc, 1,1,NULL);
5822 SetGraphicsMode(hdc, GM_COMPATIBLE);
5823 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5824 ok(ret, "GetCharWidth32W should have succeeded\n");
5825 ok (bufferW > 0," Width should be greater than zero\n");
5826 SetGraphicsMode(hdc, GM_ADVANCED);
5827 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5828 ok(ret, "GetCharWidth32W should have succeeded\n");
5829 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
5831 ReleaseDC(hwnd, hdc);
5832 DestroyWindow(hwnd);
5833 DeleteObject(hfont);
5836 static void test_fake_bold_font(void)
5838 HDC hdc;
5839 HFONT hfont, hfont_old;
5840 LOGFONTA lf;
5841 BOOL ret;
5842 TEXTMETRICA tm[2];
5843 ABC abc[2];
5844 INT w[2];
5846 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
5847 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
5848 return;
5851 /* Test outline font */
5852 memset(&lf, 0, sizeof(lf));
5853 strcpy(lf.lfFaceName, "Wingdings");
5854 lf.lfWeight = FW_NORMAL;
5855 lf.lfCharSet = SYMBOL_CHARSET;
5856 hfont = CreateFontIndirectA(&lf);
5858 hdc = GetDC(NULL);
5859 hfont_old = SelectObject(hdc, hfont);
5861 /* base metrics */
5862 ret = GetTextMetricsA(hdc, &tm[0]);
5863 ok(ret, "got %d\n", ret);
5864 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[0]);
5865 ok(ret, "got %d\n", ret);
5867 lf.lfWeight = FW_BOLD;
5868 hfont = CreateFontIndirectA(&lf);
5869 DeleteObject(SelectObject(hdc, hfont));
5871 /* bold metrics */
5872 ret = GetTextMetricsA(hdc, &tm[1]);
5873 ok(ret, "got %d\n", ret);
5874 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[1]);
5875 ok(ret, "got %d\n", ret);
5877 DeleteObject(SelectObject(hdc, hfont_old));
5878 ReleaseDC(NULL, hdc);
5880 /* compare results (outline) */
5881 ok(tm[0].tmHeight == tm[1].tmHeight, "expected %d, got %d\n", tm[0].tmHeight, tm[1].tmHeight);
5882 ok(tm[0].tmAscent == tm[1].tmAscent, "expected %d, got %d\n", tm[0].tmAscent, tm[1].tmAscent);
5883 ok(tm[0].tmDescent == tm[1].tmDescent, "expected %d, got %d\n", tm[0].tmDescent, tm[1].tmDescent);
5884 ok((tm[0].tmAveCharWidth + 1) == tm[1].tmAveCharWidth,
5885 "expected %d, got %d\n", tm[0].tmAveCharWidth + 1, tm[1].tmAveCharWidth);
5886 ok((tm[0].tmMaxCharWidth + 1) == tm[1].tmMaxCharWidth,
5887 "expected %d, got %d\n", tm[0].tmMaxCharWidth + 1, tm[1].tmMaxCharWidth);
5888 ok(tm[0].tmOverhang == tm[1].tmOverhang, "expected %d, got %d\n", tm[0].tmOverhang, tm[1].tmOverhang);
5889 w[0] = abc[0].abcA + abc[0].abcB + abc[0].abcC;
5890 w[1] = abc[1].abcA + abc[1].abcB + abc[1].abcC;
5891 ok((w[0] + 1) == w[1], "expected %d, got %d\n", w[0] + 1, w[1]);
5895 static void test_bitmap_font_glyph_index(void)
5897 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
5898 const struct {
5899 LPCSTR face;
5900 BYTE charset;
5901 } bitmap_font_list[] = {
5902 { "Courier", ANSI_CHARSET },
5903 { "Small Fonts", ANSI_CHARSET },
5904 { "Fixedsys", DEFAULT_CHARSET },
5905 { "System", DEFAULT_CHARSET }
5907 HDC hdc;
5908 LOGFONTA lf;
5909 HFONT hFont;
5910 CHAR facename[LF_FACESIZE];
5911 BITMAPINFO bmi;
5912 HBITMAP hBmp[2];
5913 void *pixels[2];
5914 int i, j;
5915 DWORD ret;
5916 BITMAP bmp;
5917 TEXTMETRICA tm;
5918 CHARSETINFO ci;
5919 BYTE chr = '\xA9';
5921 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
5922 win_skip("GetGlyphIndices is unavailable\n");
5923 return;
5926 hdc = CreateCompatibleDC(0);
5927 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5929 memset(&bmi, 0, sizeof(bmi));
5930 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
5931 bmi.bmiHeader.biBitCount = 32;
5932 bmi.bmiHeader.biPlanes = 1;
5933 bmi.bmiHeader.biWidth = 128;
5934 bmi.bmiHeader.biHeight = 32;
5935 bmi.bmiHeader.biCompression = BI_RGB;
5937 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
5938 memset(&lf, 0, sizeof(lf));
5939 lf.lfCharSet = bitmap_font_list[i].charset;
5940 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
5941 hFont = CreateFontIndirectA(&lf);
5942 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
5943 hFont = SelectObject(hdc, hFont);
5944 ret = GetTextMetricsA(hdc, &tm);
5945 ok(ret, "GetTextMetric failed\n");
5946 ret = GetTextFaceA(hdc, sizeof(facename), facename);
5947 ok(ret, "GetTextFace failed\n");
5948 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
5949 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
5950 continue;
5952 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
5953 skip("expected %s, got %s\n", lf.lfFaceName, facename);
5954 continue;
5957 for (j = 0; j < 2; j++) {
5958 HBITMAP hBmpPrev;
5959 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
5960 ok(hBmp[j] != NULL, "Can't create DIB\n");
5961 hBmpPrev = SelectObject(hdc, hBmp[j]);
5962 switch (j) {
5963 case 0:
5964 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
5965 break;
5966 case 1:
5968 int len = lstrlenW(text);
5969 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
5970 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
5971 ok(ret, "GetGlyphIndices failed\n");
5972 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
5973 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
5974 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
5975 HeapFree(GetProcessHeap(), 0, indices);
5976 break;
5979 ok(ret, "ExtTextOutW failed\n");
5980 SelectObject(hdc, hBmpPrev);
5983 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
5984 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
5985 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5987 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
5988 if (!ret) {
5989 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5990 goto next;
5992 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
5993 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
5994 goto next;
5997 for (j = 0; j < 2; j++) {
5998 HBITMAP hBmpPrev;
5999 WORD code;
6000 hBmpPrev = SelectObject(hdc, hBmp[j]);
6001 switch (j) {
6002 case 0:
6003 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6004 break;
6005 case 1:
6006 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6007 ok(ret, "GetGlyphIndices failed\n");
6008 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6009 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6010 break;
6012 ok(ret, "ExtTextOutA failed\n");
6013 SelectObject(hdc, hBmpPrev);
6016 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6017 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6018 next:
6019 for (j = 0; j < 2; j++)
6020 DeleteObject(hBmp[j]);
6021 hFont = SelectObject(hdc, hFont);
6022 DeleteObject(hFont);
6025 DeleteDC(hdc);
6028 START_TEST(font)
6030 init();
6032 test_stock_fonts();
6033 test_logfont();
6034 test_bitmap_font();
6035 test_outline_font();
6036 test_bitmap_font_metrics();
6037 test_GdiGetCharDimensions();
6038 test_GetCharABCWidths();
6039 test_text_extents();
6040 test_GetGlyphIndices();
6041 test_GetKerningPairs();
6042 test_GetOutlineTextMetrics();
6043 test_SetTextJustification();
6044 test_font_charset();
6045 test_GdiGetCodePage();
6046 test_GetFontUnicodeRanges();
6047 test_nonexistent_font();
6048 test_orientation();
6049 test_height_selection();
6050 test_AddFontMemResource();
6051 test_EnumFonts();
6053 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6054 * I'd like to avoid them in this test.
6056 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6057 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6058 if (is_truetype_font_installed("Arial Black") &&
6059 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6061 test_EnumFontFamilies("", ANSI_CHARSET);
6062 test_EnumFontFamilies("", SYMBOL_CHARSET);
6063 test_EnumFontFamilies("", DEFAULT_CHARSET);
6065 else
6066 skip("Arial Black or Symbol/Wingdings is not installed\n");
6067 test_EnumFontFamiliesEx_default_charset();
6068 test_GetTextMetrics();
6069 test_GdiRealizationInfo();
6070 test_GetTextFace();
6071 test_GetGlyphOutline();
6072 test_GetTextMetrics2("Tahoma", -11);
6073 test_GetTextMetrics2("Tahoma", -55);
6074 test_GetTextMetrics2("Tahoma", -110);
6075 test_GetTextMetrics2("Arial", -11);
6076 test_GetTextMetrics2("Arial", -55);
6077 test_GetTextMetrics2("Arial", -110);
6078 test_CreateFontIndirect();
6079 test_CreateFontIndirectEx();
6080 test_oemcharset();
6081 test_fullname();
6082 test_fullname2();
6083 test_east_asian_font_selection();
6084 test_max_height();
6085 test_vertical_order();
6086 test_GetCharWidth32();
6087 test_fake_bold_font();
6088 test_bitmap_font_glyph_index();
6090 /* These tests should be last test until RemoveFontResource
6091 * is properly implemented.
6093 test_vertical_font();
6094 test_CreateScalableFontResource();