gdi32/tests: Remove some noisy traces.
[wine.git] / dlls / gdi32 / tests / font.c
blob245fd56cef7f80b77f157f9de99b10ef9edbf3db
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b, exact) (abs((a) - (b)) <= ((exact) ? 0 : 1))
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
46 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
47 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
48 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
49 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
50 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
51 LPINT nfit, LPINT dxs, LPSIZE size );
52 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
53 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
54 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
55 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
56 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
57 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
59 static HMODULE hgdi32 = 0;
60 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
61 static WORD system_lang_id;
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
66 #else
67 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
69 #endif
71 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
72 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
73 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
74 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
75 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
76 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
78 static void init(void)
80 hgdi32 = GetModuleHandleA("gdi32.dll");
82 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
83 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
84 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
85 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
86 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
87 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
88 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
89 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
90 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
91 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
92 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
93 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
94 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
95 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
96 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
97 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
98 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
99 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
101 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
104 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
106 if (type != TRUETYPE_FONTTYPE) return 1;
108 return 0;
111 static BOOL is_truetype_font_installed(const char *name)
113 HDC hdc = GetDC(0);
114 BOOL ret = FALSE;
116 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
117 ret = TRUE;
119 ReleaseDC(0, hdc);
120 return ret;
123 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
125 return 0;
128 static BOOL is_font_installed(const char *name)
130 HDC hdc = GetDC(0);
131 BOOL ret = FALSE;
133 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
134 ret = TRUE;
136 ReleaseDC(0, hdc);
137 return ret;
140 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
142 HRSRC rsrc;
143 void *rsrc_data;
145 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
146 if (!rsrc) return NULL;
148 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
149 if (!rsrc_data) return NULL;
151 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
152 if (!*rsrc_size) return NULL;
154 return rsrc_data;
157 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
159 char tmp_path[MAX_PATH];
160 HANDLE hfile;
161 BOOL ret;
163 GetTempPathA(MAX_PATH, tmp_path);
164 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
166 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
167 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
169 ret = WriteFile(hfile, data, *size, size, NULL);
171 CloseHandle(hfile);
172 return ret;
175 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
177 void *rsrc_data;
178 DWORD rsrc_size;
180 rsrc_data = get_res_data( fontname, &rsrc_size );
181 if (!rsrc_data) return FALSE;
183 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
186 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
188 LOGFONTA getobj_lf;
189 int ret, minlen = 0;
191 if (!hfont)
192 return;
194 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
195 /* NT4 tries to be clever and only returns the minimum length */
196 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
197 minlen++;
198 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
199 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
200 ok(lf->lfHeight == getobj_lf.lfHeight ||
201 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
202 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
203 ok(lf->lfWidth == getobj_lf.lfWidth ||
204 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
205 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
206 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
207 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
208 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
209 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
210 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
211 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
212 ok(lf->lfWeight == getobj_lf.lfWeight ||
213 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
214 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
215 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
216 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
217 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
218 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
219 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
220 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
221 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
222 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
223 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
224 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
225 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
228 static HFONT create_font(const char* test, const LOGFONTA* lf)
230 HFONT hfont = CreateFontIndirectA(lf);
231 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
232 if (hfont)
233 check_font(test, lf, hfont);
234 return hfont;
237 static void test_logfont(void)
239 LOGFONTA lf;
240 HFONT hfont;
242 memset(&lf, 0, sizeof lf);
244 lf.lfCharSet = ANSI_CHARSET;
245 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
246 lf.lfWeight = FW_DONTCARE;
247 lf.lfHeight = 16;
248 lf.lfWidth = 16;
249 lf.lfQuality = DEFAULT_QUALITY;
251 lstrcpyA(lf.lfFaceName, "Arial");
252 hfont = create_font("Arial", &lf);
253 DeleteObject(hfont);
255 memset(&lf, 'A', sizeof(lf));
256 hfont = CreateFontIndirectA(&lf);
257 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
259 lf.lfFaceName[LF_FACESIZE - 1] = 0;
260 check_font("AAA...", &lf, hfont);
261 DeleteObject(hfont);
264 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
266 if (type & RASTER_FONTTYPE)
268 LOGFONTA *lf = (LOGFONTA *)lParam;
269 *lf = *elf;
270 return 0; /* stop enumeration */
273 return 1; /* continue enumeration */
276 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
278 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
279 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
280 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
281 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
282 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
283 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
284 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
285 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
286 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
287 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
288 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
289 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
290 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
291 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
292 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
293 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
294 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
295 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
296 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
297 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
300 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
301 LONG lfWidth, const char *test_str,
302 INT test_str_len, const TEXTMETRICA *tm_orig,
303 const SIZE *size_orig, INT width_of_A_orig,
304 INT scale_x, INT scale_y)
306 LOGFONTA lf;
307 OUTLINETEXTMETRICA otm;
308 TEXTMETRICA tm;
309 SIZE size;
310 INT width_of_A, cx, cy;
311 UINT ret;
313 if (!hfont)
314 return;
316 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
318 GetObjectA(hfont, sizeof(lf), &lf);
320 if (GetOutlineTextMetricsA(hdc, 0, NULL))
322 otm.otmSize = sizeof(otm) / 2;
323 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
324 ok(ret == sizeof(otm)/2 /* XP */ ||
325 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
327 memset(&otm, 0x1, sizeof(otm));
328 otm.otmSize = sizeof(otm);
329 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
330 ok(ret == sizeof(otm) /* XP */ ||
331 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
333 memset(&tm, 0x2, sizeof(tm));
334 ret = GetTextMetricsA(hdc, &tm);
335 ok(ret, "GetTextMetricsA failed\n");
336 /* the structure size is aligned */
337 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
339 ok(0, "tm != otm\n");
340 compare_tm(&tm, &otm.otmTextMetrics);
343 tm = otm.otmTextMetrics;
344 if (0) /* these metrics are scaled too, but with rounding errors */
346 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
347 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
349 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
350 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
351 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
352 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
353 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
354 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
356 else
358 ret = GetTextMetricsA(hdc, &tm);
359 ok(ret, "GetTextMetricsA failed\n");
362 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
363 cy = tm.tmHeight / tm_orig->tmHeight;
364 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
365 lfHeight, scale_x, scale_y, cx, cy);
366 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
367 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
368 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
369 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
370 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
372 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
373 if (lf.lfHeight)
375 if (lf.lfWidth)
376 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
378 else
379 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
381 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
383 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
384 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
386 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
388 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
391 /* Test how GDI scales bitmap font metrics */
392 static void test_bitmap_font(void)
394 static const char test_str[11] = "Test String";
395 HDC hdc;
396 LOGFONTA bitmap_lf;
397 HFONT hfont, old_hfont;
398 TEXTMETRICA tm_orig;
399 SIZE size_orig;
400 INT ret, i, width_orig, height_orig, scale, lfWidth;
402 hdc = CreateCompatibleDC(0);
404 /* "System" has only 1 pixel size defined, otherwise the test breaks */
405 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
406 if (ret)
408 ReleaseDC(0, hdc);
409 trace("no bitmap fonts were found, skipping the test\n");
410 return;
413 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
415 height_orig = bitmap_lf.lfHeight;
416 lfWidth = bitmap_lf.lfWidth;
418 hfont = create_font("bitmap", &bitmap_lf);
419 old_hfont = SelectObject(hdc, hfont);
420 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
421 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
422 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
423 SelectObject(hdc, old_hfont);
424 DeleteObject(hfont);
426 bitmap_lf.lfHeight = 0;
427 bitmap_lf.lfWidth = 4;
428 hfont = create_font("bitmap", &bitmap_lf);
429 old_hfont = SelectObject(hdc, hfont);
430 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
431 SelectObject(hdc, old_hfont);
432 DeleteObject(hfont);
434 bitmap_lf.lfHeight = height_orig;
435 bitmap_lf.lfWidth = lfWidth;
437 /* test fractional scaling */
438 for (i = 1; i <= height_orig * 6; i++)
440 INT nearest_height;
442 bitmap_lf.lfHeight = i;
443 hfont = create_font("fractional", &bitmap_lf);
444 scale = (i + height_orig - 1) / height_orig;
445 nearest_height = scale * height_orig;
446 /* Only jump to the next height if the difference <= 25% original height */
447 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
448 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
449 so we'll not test this particular height. */
450 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
451 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
452 old_hfont = SelectObject(hdc, hfont);
453 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
454 SelectObject(hdc, old_hfont);
455 DeleteObject(hfont);
458 /* test integer scaling 3x2 */
459 bitmap_lf.lfHeight = height_orig * 2;
460 bitmap_lf.lfWidth *= 3;
461 hfont = create_font("3x2", &bitmap_lf);
462 old_hfont = SelectObject(hdc, hfont);
463 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
464 SelectObject(hdc, old_hfont);
465 DeleteObject(hfont);
467 /* test integer scaling 3x3 */
468 bitmap_lf.lfHeight = height_orig * 3;
469 bitmap_lf.lfWidth = 0;
470 hfont = create_font("3x3", &bitmap_lf);
471 old_hfont = SelectObject(hdc, hfont);
472 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
473 SelectObject(hdc, old_hfont);
474 DeleteObject(hfont);
476 DeleteDC(hdc);
479 /* Test how GDI scales outline font metrics */
480 static void test_outline_font(void)
482 static const char test_str[11] = "Test String";
483 HDC hdc, hdc_2;
484 LOGFONTA lf;
485 HFONT hfont, old_hfont, old_hfont_2;
486 OUTLINETEXTMETRICA otm;
487 SIZE size_orig;
488 INT width_orig, height_orig, lfWidth;
489 XFORM xform;
490 GLYPHMETRICS gm;
491 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
492 POINT pt;
493 INT ret;
495 if (!is_truetype_font_installed("Arial"))
497 skip("Arial is not installed\n");
498 return;
501 hdc = CreateCompatibleDC(0);
503 memset(&lf, 0, sizeof(lf));
504 strcpy(lf.lfFaceName, "Arial");
505 lf.lfHeight = 72;
506 hfont = create_font("outline", &lf);
507 old_hfont = SelectObject(hdc, hfont);
508 otm.otmSize = sizeof(otm);
509 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
510 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
511 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
513 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
514 SelectObject(hdc, old_hfont);
515 DeleteObject(hfont);
517 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
518 lf.lfHeight = otm.otmEMSquare;
519 lf.lfHeight = -lf.lfHeight;
520 hfont = create_font("outline", &lf);
521 old_hfont = SelectObject(hdc, hfont);
522 otm.otmSize = sizeof(otm);
523 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
524 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
525 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
526 SelectObject(hdc, old_hfont);
527 DeleteObject(hfont);
529 height_orig = otm.otmTextMetrics.tmHeight;
530 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
532 /* test integer scaling 3x2 */
533 lf.lfHeight = height_orig * 2;
534 lf.lfWidth = lfWidth * 3;
535 hfont = create_font("3x2", &lf);
536 old_hfont = SelectObject(hdc, hfont);
537 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
538 SelectObject(hdc, old_hfont);
539 DeleteObject(hfont);
541 /* test integer scaling 3x3 */
542 lf.lfHeight = height_orig * 3;
543 lf.lfWidth = lfWidth * 3;
544 hfont = create_font("3x3", &lf);
545 old_hfont = SelectObject(hdc, hfont);
546 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
547 SelectObject(hdc, old_hfont);
548 DeleteObject(hfont);
550 /* test integer scaling 1x1 */
551 lf.lfHeight = height_orig * 1;
552 lf.lfWidth = lfWidth * 1;
553 hfont = create_font("1x1", &lf);
554 old_hfont = SelectObject(hdc, hfont);
555 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 SelectObject(hdc, old_hfont);
557 DeleteObject(hfont);
559 /* test integer scaling 1x1 */
560 lf.lfHeight = height_orig;
561 lf.lfWidth = 0;
562 hfont = create_font("1x1", &lf);
563 old_hfont = SelectObject(hdc, hfont);
564 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
566 /* with an identity matrix */
567 memset(&gm, 0, sizeof(gm));
568 SetLastError(0xdeadbeef);
569 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
570 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
571 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
572 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
573 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
574 /* with a custom matrix */
575 memset(&gm, 0, sizeof(gm));
576 SetLastError(0xdeadbeef);
577 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
578 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
580 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
581 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
585 * another DC.
587 hdc_2 = CreateCompatibleDC(0);
588 old_hfont_2 = SelectObject(hdc_2, hfont);
589 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
591 SetMapMode(hdc, MM_ANISOTROPIC);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc, 100, 100, NULL);
601 SetViewportExtEx(hdc, 50, 100, NULL);
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc, 100, 200, NULL);
611 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc, MM_TEXT);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 SelectObject(hdc_2, old_hfont_2);
622 DeleteDC(hdc_2);
624 if (!SetGraphicsMode(hdc, GM_ADVANCED))
626 SelectObject(hdc, old_hfont);
627 DeleteObject(hfont);
628 DeleteDC(hdc);
629 skip("GM_ADVANCED is not supported on this platform\n");
630 return;
633 xform.eM11 = 20.0f;
634 xform.eM12 = 0.0f;
635 xform.eM21 = 0.0f;
636 xform.eM22 = 20.0f;
637 xform.eDx = 0.0f;
638 xform.eDy = 0.0f;
640 SetLastError(0xdeadbeef);
641 ret = SetWorldTransform(hdc, &xform);
642 ok(ret, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
646 /* with an identity matrix */
647 memset(&gm, 0, sizeof(gm));
648 SetLastError(0xdeadbeef);
649 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
650 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
651 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
652 pt.x = width_orig; pt.y = 0;
653 LPtoDP(hdc, &pt, 1);
654 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
655 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
656 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
657 /* with a custom matrix */
658 memset(&gm, 0, sizeof(gm));
659 SetLastError(0xdeadbeef);
660 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
661 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
662 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
663 pt.x = width_orig; pt.y = 0;
664 LPtoDP(hdc, &pt, 1);
665 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
666 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
667 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
669 SetLastError(0xdeadbeef);
670 ret = SetMapMode(hdc, MM_LOMETRIC);
671 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
673 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
675 /* with an identity matrix */
676 memset(&gm, 0, sizeof(gm));
677 SetLastError(0xdeadbeef);
678 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
679 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
680 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
681 pt.x = width_orig; pt.y = 0;
682 LPtoDP(hdc, &pt, 1);
683 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
684 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
685 /* with a custom matrix */
686 memset(&gm, 0, sizeof(gm));
687 SetLastError(0xdeadbeef);
688 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
689 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
690 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
691 pt.x = width_orig; pt.y = 0;
692 LPtoDP(hdc, &pt, 1);
693 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
694 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
696 SetLastError(0xdeadbeef);
697 ret = SetMapMode(hdc, MM_TEXT);
698 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
700 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
702 /* with an identity matrix */
703 memset(&gm, 0, sizeof(gm));
704 SetLastError(0xdeadbeef);
705 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
706 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
708 pt.x = width_orig; pt.y = 0;
709 LPtoDP(hdc, &pt, 1);
710 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
711 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
712 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
713 /* with a custom matrix */
714 memset(&gm, 0, sizeof(gm));
715 SetLastError(0xdeadbeef);
716 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
717 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
718 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
719 pt.x = width_orig; pt.y = 0;
720 LPtoDP(hdc, &pt, 1);
721 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
722 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
723 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
725 SelectObject(hdc, old_hfont);
726 DeleteObject(hfont);
727 DeleteDC(hdc);
730 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
732 LOGFONTA *lf = (LOGFONTA *)lParam;
734 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
736 *lf = *elf;
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL is_CJK(void)
744 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const struct font_data
752 const char face_name[LF_FACESIZE];
753 int weight, height, ascent, descent, int_leading, ext_leading;
754 int ave_char_width, max_char_width, dpi;
755 BYTE first_char, last_char, def_char, break_char;
756 DWORD ansi_bitfield;
757 WORD skip_lang_id;
758 int scaled_height;
759 } fd[] =
761 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
762 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
763 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
764 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
765 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
766 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
767 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
768 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
769 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 16 },
770 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
772 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
773 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
775 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
777 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
778 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
781 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
783 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
784 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
785 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
786 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
787 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
788 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
789 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
790 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
791 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
792 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
793 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
794 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
795 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
796 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
797 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
798 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
800 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
801 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
802 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
803 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
804 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
805 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
806 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
807 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
808 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
809 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
813 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
814 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
815 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
816 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
817 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
818 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
819 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
820 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
822 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
823 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
824 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
826 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
827 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
828 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
831 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
833 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
834 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
835 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
836 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
837 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
838 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
839 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
840 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
841 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
843 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
844 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
845 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
847 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
848 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
849 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
851 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
852 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
853 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
855 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
856 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
858 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
859 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
860 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
861 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
862 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
863 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
864 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
865 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
866 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
867 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
868 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
869 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
870 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
871 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
872 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
873 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
874 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
875 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
876 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
877 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
878 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
880 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
881 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
882 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
883 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
884 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
885 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
886 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
887 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
888 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
889 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
890 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
891 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
893 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
894 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
895 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
897 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
899 /* FIXME: add "Terminal" */
901 static const int font_log_pixels[] = { 96, 120 };
902 HDC hdc;
903 LOGFONTA lf;
904 HFONT hfont, old_hfont;
905 TEXTMETRICA tm;
906 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
907 char face_name[LF_FACESIZE];
908 CHARSETINFO csi;
910 trace("system language id %04x\n", system_lang_id);
912 expected_cs = GetACP();
913 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
915 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
916 return;
918 expected_cs = csi.ciCharset;
919 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
921 hdc = CreateCompatibleDC(0);
922 assert(hdc);
924 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
925 GetDeviceCaps(hdc, LOGPIXELSY));
927 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
928 diff = 32768;
929 font_res = 0;
930 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
932 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
933 if (new_diff < diff)
935 diff = new_diff;
936 font_res = font_log_pixels[i];
939 trace("best font resolution is %d\n", font_res);
941 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
943 int bit, height;
945 memset(&lf, 0, sizeof(lf));
947 height = fd[i].height & ~FH_SCALE;
948 lf.lfHeight = height;
949 strcpy(lf.lfFaceName, fd[i].face_name);
951 for(bit = 0; bit < 32; bit++)
953 GLYPHMETRICS gm;
954 DWORD fs[2];
955 BOOL bRet;
957 fs[0] = 1L << bit;
958 fs[1] = 0;
959 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
960 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
962 lf.lfCharSet = csi.ciCharset;
963 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
964 if (fd[i].height & FH_SCALE)
965 ok(ret, "scaled font height %d should not be enumerated\n", height);
966 else
968 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
970 if (ret) /* FIXME: Remove once Wine is fixed */
971 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
972 else
973 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
976 if (ret && !(fd[i].height & FH_SCALE))
977 continue;
979 hfont = create_font(lf.lfFaceName, &lf);
980 old_hfont = SelectObject(hdc, hfont);
982 SetLastError(0xdeadbeef);
983 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
984 ok(ret, "GetTextFace error %u\n", GetLastError());
986 if (strcmp(face_name, fd[i].face_name) != 0)
988 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
989 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
990 SelectObject(hdc, old_hfont);
991 DeleteObject(hfont);
992 continue;
995 memset(&gm, 0, sizeof(gm));
996 SetLastError(0xdeadbeef);
997 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
998 todo_wine {
999 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1000 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1003 bRet = GetTextMetricsA(hdc, &tm);
1004 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1006 SetLastError(0xdeadbeef);
1007 ret = GetTextCharset(hdc);
1008 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1009 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1010 else
1011 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1013 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1014 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1016 if(fd[i].dpi == tm.tmDigitizedAspectX)
1018 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1019 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
1021 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1022 if (fd[i].height & FH_SCALE)
1023 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
1024 else
1025 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
1026 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1027 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1028 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
1029 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
1030 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
1031 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1032 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1033 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1034 make default char test fail */
1035 if (tm.tmCharSet == lf.lfCharSet)
1036 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1037 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1038 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
1040 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1041 that make the max width bigger */
1042 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1043 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
1045 else
1046 skip("Skipping font metrics test for system langid 0x%x\n",
1047 system_lang_id);
1049 SelectObject(hdc, old_hfont);
1050 DeleteObject(hfont);
1054 DeleteDC(hdc);
1057 static void test_GdiGetCharDimensions(void)
1059 HDC hdc;
1060 TEXTMETRICW tm;
1061 LONG ret;
1062 SIZE size;
1063 LONG avgwidth, height;
1064 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1066 if (!pGdiGetCharDimensions)
1068 win_skip("GdiGetCharDimensions not available on this platform\n");
1069 return;
1072 hdc = CreateCompatibleDC(NULL);
1074 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1075 avgwidth = ((size.cx / 26) + 1) / 2;
1077 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1078 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1079 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1081 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1082 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1084 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1085 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1087 height = 0;
1088 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1089 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1090 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1092 DeleteDC(hdc);
1095 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1096 const TEXTMETRICA *lpntme,
1097 DWORD FontType, LPARAM lParam)
1099 if (FontType & TRUETYPE_FONTTYPE)
1101 HFONT hfont;
1103 hfont = CreateFontIndirectA(lpelfe);
1104 if (hfont)
1106 *(HFONT *)lParam = hfont;
1107 return 0;
1111 return 1;
1114 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1116 ABC abc[1];
1117 ABCFLOAT abcf[1];
1118 BOOL ret = FALSE;
1120 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1121 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1122 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1123 if (todo) todo_wine ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1124 else ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1125 if (todo) todo_wine ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1126 else ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1128 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1129 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1130 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1131 if (todo) todo_wine ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1132 else ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1133 if (todo) todo_wine ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1134 else ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's should be unchanged\n", description);
1136 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1137 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1138 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1139 if (todo) todo_wine ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1140 else ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's should be unchanged\n", description);
1141 if (todo) todo_wine ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1142 else ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1145 static void test_GetCharABCWidths(void)
1147 static const WCHAR str[] = {'i',0};
1148 BOOL ret;
1149 HDC hdc;
1150 LOGFONTA lf;
1151 HFONT hfont;
1152 ABC abc[1];
1153 ABC abcw[1];
1154 ABCFLOAT abcf[1];
1155 WORD glyphs[1];
1156 DWORD nb;
1157 HWND hwnd;
1158 static const struct
1160 UINT first;
1161 UINT last;
1162 } range[] =
1164 {0xff, 0xff},
1165 {0x100, 0x100},
1166 {0xff, 0x100},
1167 {0x1ff, 0xff00},
1168 {0xffff, 0xffff},
1169 {0x10000, 0x10000},
1170 {0xffff, 0x10000},
1171 {0xffffff, 0xffffff},
1172 {0x1000000, 0x1000000},
1173 {0xffffff, 0x1000000},
1174 {0xffffffff, 0xffffffff},
1175 {0x00, 0xff}
1177 static const struct
1179 UINT cs;
1180 UINT a;
1181 UINT w;
1182 BOOL r[sizeof range / sizeof range[0]];
1183 } c[] =
1185 {ANSI_CHARSET, 0x30, 0x30,
1186 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1187 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1188 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1189 {HANGEUL_CHARSET, 0x8141, 0xac02,
1190 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1191 {GB2312_CHARSET, 0x8141, 0x4e04,
1192 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1193 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1194 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1196 UINT i;
1198 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1200 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1201 return;
1204 memset(&lf, 0, sizeof(lf));
1205 strcpy(lf.lfFaceName, "System");
1206 lf.lfHeight = 20;
1208 hfont = CreateFontIndirectA(&lf);
1209 hdc = GetDC(0);
1210 hfont = SelectObject(hdc, hfont);
1212 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1213 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1215 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1216 ok(!ret, "GetCharABCWidthsI should have failed\n");
1218 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1219 ok(!ret, "GetCharABCWidthsI should have failed\n");
1221 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1222 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1224 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1225 ok(!ret, "GetCharABCWidthsW should have failed\n");
1227 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1228 ok(!ret, "GetCharABCWidthsW should have failed\n");
1230 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1231 ok(!ret, "GetCharABCWidthsW should have failed\n");
1233 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1234 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1236 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1237 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1239 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1240 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1242 hfont = SelectObject(hdc, hfont);
1243 DeleteObject(hfont);
1245 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1247 ABC a[2], w[2];
1248 ABC full[256];
1249 UINT code = 0x41, j;
1251 lf.lfFaceName[0] = '\0';
1252 lf.lfCharSet = c[i].cs;
1253 lf.lfPitchAndFamily = 0;
1254 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1256 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1257 continue;
1260 memset(a, 0, sizeof a);
1261 memset(w, 0, sizeof w);
1262 hfont = SelectObject(hdc, hfont);
1263 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1264 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1265 memcmp(a, w, sizeof a) == 0,
1266 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1268 memset(a, 0xbb, sizeof a);
1269 ret = pGetCharABCWidthsA(hdc, code, code, a);
1270 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1271 memset(full, 0xcc, sizeof full);
1272 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1273 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1274 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1275 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1277 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1279 memset(full, 0xdd, sizeof full);
1280 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1281 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1282 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1283 if (ret)
1285 UINT last = range[j].last - range[j].first;
1286 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1287 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1288 "GetCharABCWidthsA %x should match. codepage = %u\n",
1289 range[j].last, c[i].cs);
1293 hfont = SelectObject(hdc, hfont);
1294 DeleteObject(hfont);
1297 memset(&lf, 0, sizeof(lf));
1298 strcpy(lf.lfFaceName, "Tahoma");
1299 lf.lfHeight = 200;
1300 hfont = CreateFontIndirectA(&lf);
1302 /* test empty glyph's metrics */
1303 hfont = SelectObject(hdc, hfont);
1304 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1305 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1306 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1307 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1308 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1309 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1311 /* 1) prepare unrotated font metrics */
1312 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1313 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1314 DeleteObject(SelectObject(hdc, hfont));
1316 /* 2) get rotated font metrics */
1317 lf.lfEscapement = lf.lfOrientation = 900;
1318 hfont = CreateFontIndirectA(&lf);
1319 hfont = SelectObject(hdc, hfont);
1320 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1321 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1323 /* 3) compare ABC results */
1324 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1325 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1326 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1327 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1328 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1329 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1331 DeleteObject(SelectObject(hdc, hfont));
1332 ReleaseDC(NULL, hdc);
1334 trace("ABC sign test for a variety of transforms:\n");
1335 memset(&lf, 0, sizeof(lf));
1336 strcpy(lf.lfFaceName, "Tahoma");
1337 lf.lfHeight = 20;
1338 hfont = CreateFontIndirectA(&lf);
1339 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1340 0, 0, 0, NULL);
1341 hdc = GetDC(hwnd);
1342 SetMapMode(hdc, MM_ANISOTROPIC);
1343 SelectObject(hdc, hfont);
1345 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1346 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1348 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1349 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1350 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1351 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1352 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1353 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1355 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1356 SetWindowExtEx(hdc, -1, -1, NULL);
1357 SetGraphicsMode(hdc, GM_COMPATIBLE);
1358 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1359 SetGraphicsMode(hdc, GM_ADVANCED);
1360 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1361 SetWindowExtEx(hdc, 1, 1, NULL);
1362 SetGraphicsMode(hdc, GM_COMPATIBLE);
1363 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1364 SetGraphicsMode(hdc, GM_ADVANCED);
1365 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1367 ReleaseDC(hwnd, hdc);
1368 DestroyWindow(hwnd);
1370 trace("RTL layout\n");
1371 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1372 0, 0, 0, NULL);
1373 hdc = GetDC(hwnd);
1374 SetMapMode(hdc, MM_ANISOTROPIC);
1375 SelectObject(hdc, hfont);
1377 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1378 SetWindowExtEx(hdc, -1, -1, NULL);
1379 SetGraphicsMode(hdc, GM_COMPATIBLE);
1380 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1381 SetGraphicsMode(hdc, GM_ADVANCED);
1382 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1383 SetWindowExtEx(hdc, 1, 1, NULL);
1384 SetGraphicsMode(hdc, GM_COMPATIBLE);
1385 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1386 SetGraphicsMode(hdc, GM_ADVANCED);
1387 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1389 ReleaseDC(hwnd, hdc);
1390 DestroyWindow(hwnd);
1391 DeleteObject(hfont);
1394 static void test_text_extents(void)
1396 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1397 LPINT extents;
1398 INT i, len, fit1, fit2, extents2[3];
1399 LOGFONTA lf;
1400 TEXTMETRICA tm;
1401 HDC hdc;
1402 HFONT hfont;
1403 SIZE sz;
1404 SIZE sz1, sz2;
1405 BOOL ret;
1407 memset(&lf, 0, sizeof(lf));
1408 strcpy(lf.lfFaceName, "Arial");
1409 lf.lfHeight = 20;
1411 hfont = CreateFontIndirectA(&lf);
1412 hdc = GetDC(0);
1413 hfont = SelectObject(hdc, hfont);
1414 GetTextMetricsA(hdc, &tm);
1415 GetTextExtentPointA(hdc, "o", 1, &sz);
1416 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1418 SetLastError(0xdeadbeef);
1419 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1420 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1422 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1423 hfont = SelectObject(hdc, hfont);
1424 DeleteObject(hfont);
1425 ReleaseDC(0, hdc);
1426 return;
1429 len = lstrlenW(wt);
1430 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1431 extents[0] = 1; /* So that the increasing sequence test will fail
1432 if the extents array is untouched. */
1433 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1434 GetTextExtentPointW(hdc, wt, len, &sz2);
1435 ok(sz1.cy == sz2.cy,
1436 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1437 /* Because of the '\n' in the string GetTextExtentExPoint and
1438 GetTextExtentPoint return different widths under Win2k, but
1439 under WinXP they return the same width. So we don't test that
1440 here. */
1442 for (i = 1; i < len; ++i)
1443 ok(extents[i-1] <= extents[i],
1444 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1446 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1447 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1448 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1449 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1450 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1451 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1452 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1453 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1455 ok(extents[0] == extents[2] && extents[1] == extents[3],
1456 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1457 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1458 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1459 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1461 /* extents functions fail with -ve counts (the interesting case being -1) */
1462 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1463 ok(ret == FALSE, "got %d\n", ret);
1464 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1465 ok(ret == FALSE, "got %d\n", ret);
1466 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1467 ok(ret == FALSE, "got %d\n", ret);
1469 /* max_extent = 0 succeeds and returns zero */
1470 fit1 = fit2 = -215;
1471 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1472 ok(ret == TRUE ||
1473 broken(ret == FALSE), /* NT4, 2k */
1474 "got %d\n", ret);
1475 ok(fit1 == 0 ||
1476 broken(fit1 == -215), /* NT4, 2k */
1477 "fit = %d\n", fit1);
1478 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1479 ok(ret == TRUE, "got %d\n", ret);
1480 ok(fit2 == 0, "fit = %d\n", fit2);
1482 /* max_extent = -1 is interpreted as a very large width that will
1483 * definitely fit our three characters */
1484 fit1 = fit2 = -215;
1485 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1486 ok(ret == TRUE, "got %d\n", ret);
1487 ok(fit1 == 3, "fit = %d\n", fit1);
1488 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1489 ok(ret == TRUE, "got %d\n", ret);
1490 ok(fit2 == 3, "fit = %d\n", fit2);
1492 /* max_extent = -2 is interpreted similarly, but the Ansi version
1493 * rejects it while the Unicode one accepts it */
1494 fit1 = fit2 = -215;
1495 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1496 ok(ret == FALSE, "got %d\n", ret);
1497 ok(fit1 == -215, "fit = %d\n", fit1);
1498 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1499 ok(ret == TRUE, "got %d\n", ret);
1500 ok(fit2 == 3, "fit = %d\n", fit2);
1502 hfont = SelectObject(hdc, hfont);
1503 DeleteObject(hfont);
1505 /* non-MM_TEXT mapping mode */
1506 lf.lfHeight = 2000;
1507 hfont = CreateFontIndirectA(&lf);
1508 hfont = SelectObject(hdc, hfont);
1510 SetMapMode( hdc, MM_HIMETRIC );
1511 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1512 ok(ret, "got %d\n", ret);
1513 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1515 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1516 ok(ret, "got %d\n", ret);
1517 ok(fit1 == 2, "got %d\n", fit1);
1518 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1519 for(i = 0; i < 2; i++)
1520 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1522 hfont = SelectObject(hdc, hfont);
1523 DeleteObject(hfont);
1524 HeapFree(GetProcessHeap(), 0, extents);
1525 ReleaseDC(NULL, hdc);
1528 static void test_GetGlyphIndices(void)
1530 HDC hdc;
1531 HFONT hfont;
1532 DWORD charcount;
1533 LOGFONTA lf;
1534 DWORD flags = 0;
1535 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1536 WORD glyphs[(sizeof(testtext)/2)-1];
1537 TEXTMETRICA textm;
1538 HFONT hOldFont;
1540 if (!pGetGlyphIndicesW) {
1541 win_skip("GetGlyphIndicesW not available on platform\n");
1542 return;
1545 hdc = GetDC(0);
1547 memset(&lf, 0, sizeof(lf));
1548 strcpy(lf.lfFaceName, "System");
1549 lf.lfHeight = 16;
1550 lf.lfCharSet = ANSI_CHARSET;
1552 hfont = CreateFontIndirectA(&lf);
1553 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1554 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1555 if (textm.tmCharSet == ANSI_CHARSET)
1557 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1558 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1559 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1560 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1561 flags = 0;
1562 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1563 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1564 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1565 textm.tmDefaultChar, glyphs[4]);
1567 else
1568 /* FIXME: Write tests for non-ANSI charsets. */
1569 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1571 if(!is_font_installed("Tahoma"))
1573 skip("Tahoma is not installed so skipping this test\n");
1574 return;
1576 memset(&lf, 0, sizeof(lf));
1577 strcpy(lf.lfFaceName, "Tahoma");
1578 lf.lfHeight = 20;
1580 hfont = CreateFontIndirectA(&lf);
1581 hOldFont = SelectObject(hdc, hfont);
1582 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1583 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1584 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1585 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1586 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1587 flags = 0;
1588 testtext[0] = textm.tmDefaultChar;
1589 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1590 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1591 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1592 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1593 DeleteObject(SelectObject(hdc, hOldFont));
1596 static void test_GetKerningPairs(void)
1598 static const struct kerning_data
1600 const char face_name[LF_FACESIZE];
1601 LONG height;
1602 /* some interesting fields from OUTLINETEXTMETRIC */
1603 LONG tmHeight, tmAscent, tmDescent;
1604 UINT otmEMSquare;
1605 INT otmAscent;
1606 INT otmDescent;
1607 UINT otmLineGap;
1608 UINT otmsCapEmHeight;
1609 UINT otmsXHeight;
1610 INT otmMacAscent;
1611 INT otmMacDescent;
1612 UINT otmMacLineGap;
1613 UINT otmusMinimumPPEM;
1614 /* small subset of kerning pairs to test */
1615 DWORD total_kern_pairs;
1616 const KERNINGPAIR kern_pair[26];
1617 } kd[] =
1619 {"Arial", 12, 12, 9, 3,
1620 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1623 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1624 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1625 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1626 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1627 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1628 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1629 {933,970,+1},{933,972,-1}
1632 {"Arial", -34, 39, 32, 7,
1633 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1636 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1637 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1638 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1639 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1640 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1641 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1642 {933,970,+2},{933,972,-3}
1645 { "Arial", 120, 120, 97, 23,
1646 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1649 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1650 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1651 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1652 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1653 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1654 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1655 {933,970,+6},{933,972,-10}
1658 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1659 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1660 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1663 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1664 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1665 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1666 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1667 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1668 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1669 {933,970,+54},{933,972,-83}
1672 #endif
1674 LOGFONTA lf;
1675 HFONT hfont, hfont_old;
1676 KERNINGPAIR *kern_pair;
1677 HDC hdc;
1678 DWORD total_kern_pairs, ret, i, n, matches;
1680 hdc = GetDC(0);
1682 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1683 * which may render this test unusable, so we're trying to avoid that.
1685 SetLastError(0xdeadbeef);
1686 GetKerningPairsW(hdc, 0, NULL);
1687 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1689 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1690 ReleaseDC(0, hdc);
1691 return;
1694 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1696 OUTLINETEXTMETRICW otm;
1697 UINT uiRet;
1699 if (!is_font_installed(kd[i].face_name))
1701 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1702 continue;
1705 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1707 memset(&lf, 0, sizeof(lf));
1708 strcpy(lf.lfFaceName, kd[i].face_name);
1709 lf.lfHeight = kd[i].height;
1710 hfont = CreateFontIndirectA(&lf);
1711 assert(hfont != 0);
1713 hfont_old = SelectObject(hdc, hfont);
1715 SetLastError(0xdeadbeef);
1716 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1717 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1718 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1720 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1721 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1722 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1723 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1724 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1725 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1727 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1728 kd[i].otmEMSquare, otm.otmEMSquare);
1729 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1730 kd[i].otmAscent, otm.otmAscent);
1731 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1732 kd[i].otmDescent, otm.otmDescent);
1733 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1734 kd[i].otmLineGap, otm.otmLineGap);
1735 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1736 kd[i].otmMacDescent, otm.otmMacDescent);
1737 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1738 kd[i].otmMacAscent, otm.otmMacAscent);
1739 todo_wine {
1740 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1741 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1742 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1743 kd[i].otmsXHeight, otm.otmsXHeight);
1744 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1745 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1746 kd[i].otmMacLineGap, otm.otmMacLineGap);
1747 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1748 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1751 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1752 trace("total_kern_pairs %u\n", total_kern_pairs);
1753 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1755 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1756 * passes on XP.
1758 SetLastError(0xdeadbeef);
1759 ret = GetKerningPairsW(hdc, 0, kern_pair);
1760 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1761 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1762 ok(ret == 0, "got %u, expected 0\n", ret);
1764 ret = GetKerningPairsW(hdc, 100, NULL);
1765 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1767 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1768 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1770 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1771 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1773 matches = 0;
1775 for (n = 0; n < ret; n++)
1777 DWORD j;
1778 /* Disabled to limit console spam */
1779 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1780 trace("{'%c','%c',%d},\n",
1781 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1782 for (j = 0; j < kd[i].total_kern_pairs; j++)
1784 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1785 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1787 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1788 "pair %d:%d got %d, expected %d\n",
1789 kern_pair[n].wFirst, kern_pair[n].wSecond,
1790 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1791 matches++;
1796 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1797 matches, kd[i].total_kern_pairs);
1799 HeapFree(GetProcessHeap(), 0, kern_pair);
1801 SelectObject(hdc, hfont_old);
1802 DeleteObject(hfont);
1805 ReleaseDC(0, hdc);
1808 struct font_data
1810 const char face_name[LF_FACESIZE];
1811 int requested_height;
1812 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1813 BOOL exact;
1816 static void test_height( HDC hdc, const struct font_data *fd )
1818 LOGFONTA lf;
1819 HFONT hfont, old_hfont;
1820 TEXTMETRICA tm;
1821 INT ret, i;
1823 for (i = 0; fd[i].face_name[0]; i++)
1825 if (!is_truetype_font_installed(fd[i].face_name))
1827 skip("%s is not installed\n", fd[i].face_name);
1828 continue;
1831 memset(&lf, 0, sizeof(lf));
1832 lf.lfHeight = fd[i].requested_height;
1833 lf.lfWeight = fd[i].weight;
1834 strcpy(lf.lfFaceName, fd[i].face_name);
1836 hfont = CreateFontIndirectA(&lf);
1837 assert(hfont);
1839 old_hfont = SelectObject(hdc, hfont);
1840 ret = GetTextMetricsA(hdc, &tm);
1841 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1842 if(fd[i].dpi == tm.tmDigitizedAspectX)
1844 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1845 ok(match_off_by_1(tm.tmHeight, fd[i].height, fd[i].exact), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1846 ok(match_off_by_1(tm.tmAscent, fd[i].ascent, fd[i].exact), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1847 ok(match_off_by_1(tm.tmDescent, fd[i].descent, fd[i].exact), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1848 ok(match_off_by_1(tm.tmInternalLeading, fd[i].int_leading, fd[i].exact), "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1849 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1852 SelectObject(hdc, old_hfont);
1853 DeleteObject(hfont);
1857 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1859 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1860 DWORD *table = (DWORD *)ttf + 3;
1862 for (i = 0; i < num_tables; i++)
1864 if (table[0] == tag)
1865 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1866 table += 4;
1868 return NULL;
1871 static void test_height_selection_vdmx( HDC hdc )
1873 static const struct font_data charset_0[] = /* doesn't use VDMX */
1875 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1876 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1877 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1878 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1879 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1880 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1881 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1882 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1883 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1884 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1885 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1886 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1887 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1888 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1889 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1890 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1891 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1892 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1893 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1894 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1895 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1896 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1897 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1898 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1899 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1900 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1901 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1902 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1903 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1904 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1905 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1906 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1907 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1908 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1909 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1910 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1911 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1912 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1913 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1914 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1915 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1916 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1917 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1918 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1919 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1920 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1921 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1922 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1923 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1924 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1925 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1926 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1927 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1930 static const struct font_data charset_1[] = /* Uses VDMX */
1932 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1933 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1934 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1935 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1936 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1937 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1938 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1939 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1940 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1941 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1942 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1943 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1944 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1945 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1946 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1947 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1948 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1949 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1950 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1951 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1952 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1953 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1954 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1955 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
1956 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
1957 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
1958 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1959 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1960 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1961 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1962 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1963 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1964 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1965 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1966 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1967 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1968 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1969 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1970 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1971 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1972 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1973 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
1974 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
1975 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
1976 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
1977 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
1978 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
1979 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
1980 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
1981 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
1982 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
1983 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
1984 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1987 static const struct vdmx_data
1989 WORD version;
1990 BYTE bCharSet;
1991 const struct font_data *fd;
1992 } data[] =
1994 { 0, 0, charset_0 },
1995 { 0, 1, charset_1 },
1996 { 1, 0, charset_0 },
1997 { 1, 1, charset_1 }
1999 int i;
2000 DWORD size, num;
2001 WORD *vdmx_header;
2002 BYTE *ratio_rec;
2003 char ttf_name[MAX_PATH];
2004 void *res, *copy;
2006 if (!pAddFontResourceExA)
2008 win_skip("AddFontResourceExA unavailable\n");
2009 return;
2012 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2014 res = get_res_data( "wine_vdmx.ttf", &size );
2016 copy = HeapAlloc( GetProcessHeap(), 0, size );
2017 memcpy( copy, res, size );
2018 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2019 vdmx_header[0] = GET_BE_WORD( data[i].version );
2020 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2021 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2022 ratio_rec = (BYTE *)&vdmx_header[3];
2023 ratio_rec[0] = data[i].bCharSet;
2025 write_tmp_file( copy, &size, ttf_name );
2026 HeapFree( GetProcessHeap(), 0, copy );
2028 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2029 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2030 if (!num) win_skip("Unable to add ttf font resource\n");
2031 else
2033 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2034 test_height( hdc, data[i].fd );
2035 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2037 DeleteFileA( ttf_name );
2041 static void test_height_selection(void)
2043 static const struct font_data tahoma[] =
2045 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2046 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2047 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2048 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2049 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2050 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2051 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2052 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2053 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2054 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2055 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2057 HDC hdc = CreateCompatibleDC(0);
2058 assert(hdc);
2060 test_height( hdc, tahoma );
2061 test_height_selection_vdmx( hdc );
2063 DeleteDC(hdc);
2066 static void test_GetOutlineTextMetrics(void)
2068 OUTLINETEXTMETRICA *otm;
2069 LOGFONTA lf;
2070 HFONT hfont, hfont_old;
2071 HDC hdc;
2072 DWORD ret, otm_size;
2073 LPSTR unset_ptr;
2075 if (!is_font_installed("Arial"))
2077 skip("Arial is not installed\n");
2078 return;
2081 hdc = GetDC(0);
2083 memset(&lf, 0, sizeof(lf));
2084 strcpy(lf.lfFaceName, "Arial");
2085 lf.lfHeight = -13;
2086 lf.lfWeight = FW_NORMAL;
2087 lf.lfPitchAndFamily = DEFAULT_PITCH;
2088 lf.lfQuality = PROOF_QUALITY;
2089 hfont = CreateFontIndirectA(&lf);
2090 assert(hfont != 0);
2092 hfont_old = SelectObject(hdc, hfont);
2093 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2094 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2096 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2098 memset(otm, 0xAA, otm_size);
2099 SetLastError(0xdeadbeef);
2100 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2101 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2102 ok(ret == 1 /* Win9x */ ||
2103 ret == otm->otmSize /* XP*/,
2104 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2105 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2107 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2108 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2109 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2110 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2113 memset(otm, 0xAA, otm_size);
2114 SetLastError(0xdeadbeef);
2115 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2116 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2117 ok(ret == 1 /* Win9x */ ||
2118 ret == otm->otmSize /* XP*/,
2119 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2120 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2122 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2123 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2124 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2125 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2128 /* ask about truncated data */
2129 memset(otm, 0xAA, otm_size);
2130 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2131 SetLastError(0xdeadbeef);
2132 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2133 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2134 ok(ret == 1 /* Win9x */ ||
2135 ret == otm->otmSize /* XP*/,
2136 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2137 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2139 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2140 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2141 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2143 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2145 HeapFree(GetProcessHeap(), 0, otm);
2147 SelectObject(hdc, hfont_old);
2148 DeleteObject(hfont);
2150 ReleaseDC(0, hdc);
2153 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2155 INT y,
2156 breakCount,
2157 areaWidth = clientArea->right - clientArea->left,
2158 nErrors = 0, e;
2159 const char *pFirstChar, *pLastChar;
2160 SIZE size;
2161 TEXTMETRICA tm;
2162 struct err
2164 const char *start;
2165 int len;
2166 int GetTextExtentExPointWWidth;
2167 } error[20];
2169 GetTextMetricsA(hdc, &tm);
2170 y = clientArea->top;
2171 do {
2172 breakCount = 0;
2173 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2174 pFirstChar = str;
2176 do {
2177 pLastChar = str;
2179 /* if not at the end of the string, ... */
2180 if (*str == '\0') break;
2181 /* ... add the next word to the current extent */
2182 while (*str != '\0' && *str++ != tm.tmBreakChar);
2183 breakCount++;
2184 SetTextJustification(hdc, 0, 0);
2185 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2186 } while ((int) size.cx < areaWidth);
2188 /* ignore trailing break chars */
2189 breakCount--;
2190 while (*(pLastChar - 1) == tm.tmBreakChar)
2192 pLastChar--;
2193 breakCount--;
2196 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2198 SetTextJustification(hdc, 0, 0);
2199 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2201 /* do not justify the last extent */
2202 if (*str != '\0' && breakCount > 0)
2204 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2205 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2206 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2208 error[nErrors].start = pFirstChar;
2209 error[nErrors].len = pLastChar - pFirstChar;
2210 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2211 nErrors++;
2215 y += size.cy;
2216 str = pLastChar;
2217 } while (*str && y < clientArea->bottom);
2219 for (e = 0; e < nErrors; e++)
2221 /* The width returned by GetTextExtentPoint32() is exactly the same
2222 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2223 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2224 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2225 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2229 static void test_SetTextJustification(void)
2231 HDC hdc;
2232 RECT clientArea;
2233 LOGFONTA lf;
2234 HFONT hfont;
2235 HWND hwnd;
2236 SIZE size, expect;
2237 int i;
2238 WORD indices[2];
2239 static const char testText[] =
2240 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2241 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2242 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2243 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2244 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2245 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2246 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2248 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2249 GetClientRect( hwnd, &clientArea );
2250 hdc = GetDC( hwnd );
2252 if (!is_font_installed("Times New Roman"))
2254 skip("Times New Roman is not installed\n");
2255 return;
2258 memset(&lf, 0, sizeof lf);
2259 lf.lfCharSet = ANSI_CHARSET;
2260 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2261 lf.lfWeight = FW_DONTCARE;
2262 lf.lfHeight = 20;
2263 lf.lfQuality = DEFAULT_QUALITY;
2264 lstrcpyA(lf.lfFaceName, "Times New Roman");
2265 hfont = create_font("Times New Roman", &lf);
2266 SelectObject(hdc, hfont);
2268 testJustification(hdc, testText, &clientArea);
2270 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2271 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2273 SetTextJustification(hdc, 0, 0);
2274 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2275 GetTextExtentPoint32A(hdc, " ", 3, &size);
2276 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2277 SetTextJustification(hdc, 4, 1);
2278 GetTextExtentPoint32A(hdc, " ", 1, &size);
2279 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2280 SetTextJustification(hdc, 9, 2);
2281 GetTextExtentPoint32A(hdc, " ", 2, &size);
2282 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2283 SetTextJustification(hdc, 7, 3);
2284 GetTextExtentPoint32A(hdc, " ", 3, &size);
2285 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2286 SetTextJustification(hdc, 7, 3);
2287 SetTextCharacterExtra(hdc, 2 );
2288 GetTextExtentPoint32A(hdc, " ", 3, &size);
2289 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2290 SetTextJustification(hdc, 0, 0);
2291 SetTextCharacterExtra(hdc, 0);
2292 size.cx = size.cy = 1234;
2293 GetTextExtentPoint32A(hdc, " ", 0, &size);
2294 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2295 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2296 SetTextJustification(hdc, 5, 1);
2297 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2298 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2299 SetTextJustification(hdc, 0, 0);
2301 SetMapMode( hdc, MM_ANISOTROPIC );
2302 SetWindowExtEx( hdc, 2, 2, NULL );
2303 GetClientRect( hwnd, &clientArea );
2304 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2305 testJustification(hdc, testText, &clientArea);
2307 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2308 for (i = 0; i < 10; i++)
2310 SetTextCharacterExtra(hdc, i);
2311 GetTextExtentPoint32A(hdc, "A", 1, &size);
2312 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2314 SetTextCharacterExtra(hdc, 0);
2315 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2316 for (i = 0; i < 10; i++)
2318 SetTextCharacterExtra(hdc, i);
2319 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2320 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2322 SetTextCharacterExtra(hdc, 0);
2324 SetViewportExtEx( hdc, 3, 3, NULL );
2325 GetClientRect( hwnd, &clientArea );
2326 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2327 testJustification(hdc, testText, &clientArea);
2329 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2330 for (i = 0; i < 10; i++)
2332 SetTextCharacterExtra(hdc, i);
2333 GetTextExtentPoint32A(hdc, "A", 1, &size);
2334 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2337 done:
2338 DeleteObject(hfont);
2339 ReleaseDC(hwnd, hdc);
2340 DestroyWindow(hwnd);
2343 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2345 HDC hdc;
2346 LOGFONTA lf;
2347 HFONT hfont, hfont_old;
2348 CHARSETINFO csi;
2349 FONTSIGNATURE fs;
2350 INT cs;
2351 DWORD i, ret;
2352 char name[64];
2354 assert(count <= 128);
2356 memset(&lf, 0, sizeof(lf));
2358 lf.lfCharSet = charset;
2359 lf.lfHeight = 10;
2360 lstrcpyA(lf.lfFaceName, "Arial");
2361 SetLastError(0xdeadbeef);
2362 hfont = CreateFontIndirectA(&lf);
2363 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2365 hdc = GetDC(0);
2366 hfont_old = SelectObject(hdc, hfont);
2368 cs = GetTextCharsetInfo(hdc, &fs, 0);
2369 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2371 SetLastError(0xdeadbeef);
2372 ret = GetTextFaceA(hdc, sizeof(name), name);
2373 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2375 if (charset == SYMBOL_CHARSET)
2377 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2378 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
2380 else
2382 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2383 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2386 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2388 trace("Can't find codepage for charset %d\n", cs);
2389 ReleaseDC(0, hdc);
2390 return FALSE;
2392 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2394 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2396 skip("Font code page %d, looking for code page %d\n",
2397 pGdiGetCodePage(hdc), code_page);
2398 ReleaseDC(0, hdc);
2399 return FALSE;
2402 if (unicode)
2404 char ansi_buf[128];
2405 WCHAR unicode_buf[128];
2407 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2409 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2411 SetLastError(0xdeadbeef);
2412 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2413 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2414 count, ret, GetLastError());
2416 else
2418 char ansi_buf[128];
2420 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2422 SetLastError(0xdeadbeef);
2423 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2424 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2425 count, ret, GetLastError());
2428 SelectObject(hdc, hfont_old);
2429 DeleteObject(hfont);
2431 ReleaseDC(0, hdc);
2433 return TRUE;
2436 static void test_font_charset(void)
2438 static struct charset_data
2440 INT charset;
2441 UINT code_page;
2442 WORD font_idxA[128], font_idxW[128];
2443 } cd[] =
2445 { ANSI_CHARSET, 1252 },
2446 { RUSSIAN_CHARSET, 1251 },
2447 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2449 int i;
2451 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2453 win_skip("Skipping the font charset test on a Win9x platform\n");
2454 return;
2457 if (!is_font_installed("Arial"))
2459 skip("Arial is not installed\n");
2460 return;
2463 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2465 if (cd[i].charset == SYMBOL_CHARSET)
2467 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2469 skip("Symbol or Wingdings is not installed\n");
2470 break;
2473 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2474 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2475 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2478 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2479 if (i > 2)
2481 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2482 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2484 else
2485 skip("Symbol or Wingdings is not installed\n");
2488 static void test_GdiGetCodePage(void)
2490 static const struct _matching_data
2492 UINT current_codepage;
2493 LPCSTR lfFaceName;
2494 UCHAR lfCharSet;
2495 UINT expected_codepage;
2496 } matching_data[] = {
2497 {1251, "Arial", ANSI_CHARSET, 1252},
2498 {1251, "Tahoma", ANSI_CHARSET, 1252},
2500 {1252, "Arial", ANSI_CHARSET, 1252},
2501 {1252, "Tahoma", ANSI_CHARSET, 1252},
2503 {1253, "Arial", ANSI_CHARSET, 1252},
2504 {1253, "Tahoma", ANSI_CHARSET, 1252},
2506 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2507 { 932, "Tahoma", ANSI_CHARSET, 1252},
2508 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2510 { 936, "Arial", ANSI_CHARSET, 936},
2511 { 936, "Tahoma", ANSI_CHARSET, 936},
2512 { 936, "Simsun", ANSI_CHARSET, 936},
2514 { 949, "Arial", ANSI_CHARSET, 949},
2515 { 949, "Tahoma", ANSI_CHARSET, 949},
2516 { 949, "Gulim", ANSI_CHARSET, 949},
2518 { 950, "Arial", ANSI_CHARSET, 950},
2519 { 950, "Tahoma", ANSI_CHARSET, 950},
2520 { 950, "PMingLiU", ANSI_CHARSET, 950},
2522 HDC hdc;
2523 LOGFONTA lf;
2524 HFONT hfont;
2525 UINT charset, acp;
2526 DWORD codepage;
2527 int i;
2529 if (!pGdiGetCodePage)
2531 skip("GdiGetCodePage not available on this platform\n");
2532 return;
2535 acp = GetACP();
2537 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2539 /* only test data matched current locale codepage */
2540 if (matching_data[i].current_codepage != acp)
2541 continue;
2543 if (!is_font_installed(matching_data[i].lfFaceName))
2545 skip("%s is not installed\n", matching_data[i].lfFaceName);
2546 continue;
2549 hdc = GetDC(0);
2551 memset(&lf, 0, sizeof(lf));
2552 lf.lfHeight = -16;
2553 lf.lfCharSet = matching_data[i].lfCharSet;
2554 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2555 hfont = CreateFontIndirectA(&lf);
2556 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2558 hfont = SelectObject(hdc, hfont);
2559 charset = GetTextCharset(hdc);
2560 codepage = pGdiGetCodePage(hdc);
2561 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2562 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2563 ok(codepage == matching_data[i].expected_codepage,
2564 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2566 hfont = SelectObject(hdc, hfont);
2567 DeleteObject(hfont);
2569 /* CLIP_DFA_DISABLE turns off the font association */
2570 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2571 hfont = CreateFontIndirectA(&lf);
2572 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2574 hfont = SelectObject(hdc, hfont);
2575 charset = GetTextCharset(hdc);
2576 codepage = pGdiGetCodePage(hdc);
2577 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2578 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2579 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2581 hfont = SelectObject(hdc, hfont);
2582 DeleteObject(hfont);
2584 ReleaseDC(NULL, hdc);
2588 static void test_GetFontUnicodeRanges(void)
2590 LOGFONTA lf;
2591 HDC hdc;
2592 HFONT hfont, hfont_old;
2593 DWORD size;
2594 GLYPHSET *gs;
2595 DWORD i;
2597 if (!pGetFontUnicodeRanges)
2599 win_skip("GetFontUnicodeRanges not available before W2K\n");
2600 return;
2603 memset(&lf, 0, sizeof(lf));
2604 lstrcpyA(lf.lfFaceName, "Arial");
2605 hfont = create_font("Arial", &lf);
2607 hdc = GetDC(0);
2608 hfont_old = SelectObject(hdc, hfont);
2610 size = pGetFontUnicodeRanges(NULL, NULL);
2611 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2613 size = pGetFontUnicodeRanges(hdc, NULL);
2614 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2616 gs = HeapAlloc(GetProcessHeap(), 0, size);
2618 size = pGetFontUnicodeRanges(hdc, gs);
2619 ok(size, "GetFontUnicodeRanges failed\n");
2621 if (0) /* Disabled to limit console spam */
2622 for (i = 0; i < gs->cRanges; i++)
2623 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2624 trace("found %u ranges\n", gs->cRanges);
2626 HeapFree(GetProcessHeap(), 0, gs);
2628 SelectObject(hdc, hfont_old);
2629 DeleteObject(hfont);
2630 ReleaseDC(NULL, hdc);
2633 #define MAX_ENUM_FONTS 4096
2635 struct enum_font_data
2637 int total;
2638 LOGFONTA lf[MAX_ENUM_FONTS];
2641 struct enum_fullname_data
2643 int total;
2644 ENUMLOGFONTA elf[MAX_ENUM_FONTS];
2647 struct enum_font_dataW
2649 int total;
2650 LOGFONTW lf[MAX_ENUM_FONTS];
2653 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2655 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2656 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2658 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2659 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2661 if (type != TRUETYPE_FONTTYPE) return 1;
2663 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2665 if (0) /* Disabled to limit console spam */
2666 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2667 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2668 if (efd->total < MAX_ENUM_FONTS)
2669 efd->lf[efd->total++] = *lf;
2670 else
2671 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2673 return 1;
2676 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2678 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2679 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2681 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2682 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2684 if (type != TRUETYPE_FONTTYPE) return 1;
2686 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2688 if (0) /* Disabled to limit console spam */
2689 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2690 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2691 if (efd->total < MAX_ENUM_FONTS)
2692 efd->lf[efd->total++] = *lf;
2693 else
2694 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2696 return 1;
2699 static void get_charset_stats(struct enum_font_data *efd,
2700 int *ansi_charset, int *symbol_charset,
2701 int *russian_charset)
2703 int i;
2705 *ansi_charset = 0;
2706 *symbol_charset = 0;
2707 *russian_charset = 0;
2709 for (i = 0; i < efd->total; i++)
2711 switch (efd->lf[i].lfCharSet)
2713 case ANSI_CHARSET:
2714 (*ansi_charset)++;
2715 break;
2716 case SYMBOL_CHARSET:
2717 (*symbol_charset)++;
2718 break;
2719 case RUSSIAN_CHARSET:
2720 (*russian_charset)++;
2721 break;
2726 static void get_charset_statsW(struct enum_font_dataW *efd,
2727 int *ansi_charset, int *symbol_charset,
2728 int *russian_charset)
2730 int i;
2732 *ansi_charset = 0;
2733 *symbol_charset = 0;
2734 *russian_charset = 0;
2736 for (i = 0; i < efd->total; i++)
2738 switch (efd->lf[i].lfCharSet)
2740 case ANSI_CHARSET:
2741 (*ansi_charset)++;
2742 break;
2743 case SYMBOL_CHARSET:
2744 (*symbol_charset)++;
2745 break;
2746 case RUSSIAN_CHARSET:
2747 (*russian_charset)++;
2748 break;
2753 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2755 struct enum_font_data efd;
2756 struct enum_font_dataW efdw;
2757 LOGFONTA lf;
2758 HDC hdc;
2759 int i, ret, ansi_charset, symbol_charset, russian_charset;
2761 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2763 if (*font_name && !is_truetype_font_installed(font_name))
2765 skip("%s is not installed\n", font_name);
2766 return;
2769 hdc = GetDC(0);
2771 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2772 * while EnumFontFamiliesEx doesn't.
2774 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2777 * Use EnumFontFamiliesW since win98 crashes when the
2778 * second parameter is NULL using EnumFontFamilies
2780 efdw.total = 0;
2781 SetLastError(0xdeadbeef);
2782 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2783 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2784 if(ret)
2786 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2787 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2788 ansi_charset, symbol_charset, russian_charset);
2789 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2790 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2791 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2792 ok(russian_charset > 0 ||
2793 broken(russian_charset == 0), /* NT4 */
2794 "NULL family should enumerate RUSSIAN_CHARSET\n");
2797 efdw.total = 0;
2798 SetLastError(0xdeadbeef);
2799 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2800 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2801 if(ret)
2803 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2804 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2805 ansi_charset, symbol_charset, russian_charset);
2806 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2807 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2808 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2809 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2813 efd.total = 0;
2814 SetLastError(0xdeadbeef);
2815 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2816 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2817 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2818 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2819 ansi_charset, symbol_charset, russian_charset,
2820 *font_name ? font_name : "<empty>");
2821 if (*font_name)
2822 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2823 else
2824 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2825 for (i = 0; i < efd.total; i++)
2827 /* FIXME: remove completely once Wine is fixed */
2828 if (efd.lf[i].lfCharSet != font_charset)
2830 todo_wine
2831 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2833 else
2834 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2835 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2836 font_name, efd.lf[i].lfFaceName);
2839 memset(&lf, 0, sizeof(lf));
2840 lf.lfCharSet = ANSI_CHARSET;
2841 strcpy(lf.lfFaceName, font_name);
2842 efd.total = 0;
2843 SetLastError(0xdeadbeef);
2844 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2845 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2846 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2847 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2848 ansi_charset, symbol_charset, russian_charset,
2849 *font_name ? font_name : "<empty>");
2850 if (font_charset == SYMBOL_CHARSET)
2852 if (*font_name)
2853 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2854 else
2855 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2857 else
2859 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2860 for (i = 0; i < efd.total; i++)
2862 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2863 if (*font_name)
2864 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2865 font_name, efd.lf[i].lfFaceName);
2869 /* DEFAULT_CHARSET should enumerate all available charsets */
2870 memset(&lf, 0, sizeof(lf));
2871 lf.lfCharSet = DEFAULT_CHARSET;
2872 strcpy(lf.lfFaceName, font_name);
2873 efd.total = 0;
2874 SetLastError(0xdeadbeef);
2875 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2876 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2877 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2878 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2879 ansi_charset, symbol_charset, russian_charset,
2880 *font_name ? font_name : "<empty>");
2881 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2882 for (i = 0; i < efd.total; i++)
2884 if (*font_name)
2885 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2886 font_name, efd.lf[i].lfFaceName);
2888 if (*font_name)
2890 switch (font_charset)
2892 case ANSI_CHARSET:
2893 ok(ansi_charset > 0,
2894 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2895 ok(!symbol_charset,
2896 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2897 ok(russian_charset > 0,
2898 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2899 break;
2900 case SYMBOL_CHARSET:
2901 ok(!ansi_charset,
2902 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2903 ok(symbol_charset,
2904 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2905 ok(!russian_charset,
2906 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2907 break;
2908 case DEFAULT_CHARSET:
2909 ok(ansi_charset > 0,
2910 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2911 ok(symbol_charset > 0,
2912 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2913 ok(russian_charset > 0,
2914 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2915 break;
2918 else
2920 ok(ansi_charset > 0,
2921 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2922 ok(symbol_charset > 0,
2923 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2924 ok(russian_charset > 0,
2925 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2928 memset(&lf, 0, sizeof(lf));
2929 lf.lfCharSet = SYMBOL_CHARSET;
2930 strcpy(lf.lfFaceName, font_name);
2931 efd.total = 0;
2932 SetLastError(0xdeadbeef);
2933 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2934 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2935 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2936 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2937 ansi_charset, symbol_charset, russian_charset,
2938 *font_name ? font_name : "<empty>");
2939 if (*font_name && font_charset == ANSI_CHARSET)
2940 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2941 else
2943 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2944 for (i = 0; i < efd.total; i++)
2946 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2947 if (*font_name)
2948 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2949 font_name, efd.lf[i].lfFaceName);
2952 ok(!ansi_charset,
2953 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2954 ok(symbol_charset > 0,
2955 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2956 ok(!russian_charset,
2957 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2960 ReleaseDC(0, hdc);
2963 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2965 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
2966 LOGFONTA *target = (LOGFONTA *)lParam;
2967 const DWORD valid_bits = 0x003f01ff;
2968 CHARSETINFO csi;
2969 DWORD fs;
2971 if (type != TRUETYPE_FONTTYPE) return TRUE;
2973 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
2974 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
2975 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
2976 *target = *lf;
2977 return FALSE;
2981 return TRUE;
2984 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
2986 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2988 if (type != TRUETYPE_FONTTYPE) return 1;
2990 if (efd->total < MAX_ENUM_FONTS)
2991 efd->lf[efd->total++] = *lf;
2992 else
2993 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2995 return 1;
2998 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3000 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3002 if (type != TRUETYPE_FONTTYPE) return 1;
3004 if (efnd->total < MAX_ENUM_FONTS)
3005 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3006 else
3007 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
3009 return 1;
3012 static void test_EnumFontFamiliesEx_default_charset(void)
3014 struct enum_font_data efd;
3015 LOGFONTA target, enum_font;
3016 UINT acp;
3017 HDC hdc;
3018 CHARSETINFO csi;
3020 acp = GetACP();
3021 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3022 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3023 return;
3026 hdc = GetDC(0);
3027 memset(&enum_font, 0, sizeof(enum_font));
3028 enum_font.lfCharSet = csi.ciCharset;
3029 target.lfFaceName[0] = '\0';
3030 target.lfCharSet = csi.ciCharset;
3031 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3032 if (target.lfFaceName[0] == '\0') {
3033 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3034 return;
3036 if (acp == 874 || acp == 1255 || acp == 1256) {
3037 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3038 target.lfCharSet = ANSI_CHARSET;
3041 efd.total = 0;
3042 memset(&enum_font, 0, sizeof(enum_font));
3043 strcpy(enum_font.lfFaceName, target.lfFaceName);
3044 enum_font.lfCharSet = DEFAULT_CHARSET;
3045 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3046 ReleaseDC(0, hdc);
3048 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3049 if (efd.total < 2) {
3050 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3051 return;
3054 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3055 "(%s) got charset %d expected %d\n",
3056 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3058 return;
3061 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3063 HFONT hfont, hfont_prev;
3064 DWORD ret;
3065 GLYPHMETRICS gm1, gm2;
3066 LOGFONTA lf2 = *lf;
3067 WORD idx;
3069 if(!pGetGlyphIndicesA)
3070 return;
3072 /* negative widths are handled just as positive ones */
3073 lf2.lfWidth = -lf->lfWidth;
3075 SetLastError(0xdeadbeef);
3076 hfont = CreateFontIndirectA(lf);
3077 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3078 check_font("original", lf, hfont);
3080 hfont_prev = SelectObject(hdc, hfont);
3082 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3083 if (ret == GDI_ERROR || idx == 0xffff)
3085 SelectObject(hdc, hfont_prev);
3086 DeleteObject(hfont);
3087 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3088 return;
3091 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3092 memset(&gm1, 0xab, sizeof(gm1));
3093 SetLastError(0xdeadbeef);
3094 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3095 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3097 SelectObject(hdc, hfont_prev);
3098 DeleteObject(hfont);
3100 SetLastError(0xdeadbeef);
3101 hfont = CreateFontIndirectA(&lf2);
3102 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3103 check_font("negative width", &lf2, hfont);
3105 hfont_prev = SelectObject(hdc, hfont);
3107 memset(&gm2, 0xbb, sizeof(gm2));
3108 SetLastError(0xdeadbeef);
3109 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3110 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3112 SelectObject(hdc, hfont_prev);
3113 DeleteObject(hfont);
3115 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3116 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3117 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3118 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3119 gm1.gmCellIncX == gm2.gmCellIncX &&
3120 gm1.gmCellIncY == gm2.gmCellIncY,
3121 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3122 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3123 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3124 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3125 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3128 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3129 #include "pshpack2.h"
3130 typedef struct
3132 USHORT version;
3133 SHORT xAvgCharWidth;
3134 USHORT usWeightClass;
3135 USHORT usWidthClass;
3136 SHORT fsType;
3137 SHORT ySubscriptXSize;
3138 SHORT ySubscriptYSize;
3139 SHORT ySubscriptXOffset;
3140 SHORT ySubscriptYOffset;
3141 SHORT ySuperscriptXSize;
3142 SHORT ySuperscriptYSize;
3143 SHORT ySuperscriptXOffset;
3144 SHORT ySuperscriptYOffset;
3145 SHORT yStrikeoutSize;
3146 SHORT yStrikeoutPosition;
3147 SHORT sFamilyClass;
3148 PANOSE panose;
3149 ULONG ulUnicodeRange1;
3150 ULONG ulUnicodeRange2;
3151 ULONG ulUnicodeRange3;
3152 ULONG ulUnicodeRange4;
3153 CHAR achVendID[4];
3154 USHORT fsSelection;
3155 USHORT usFirstCharIndex;
3156 USHORT usLastCharIndex;
3157 /* According to the Apple spec, original version didn't have the below fields,
3158 * version numbers were taken from the OpenType spec.
3160 /* version 0 (TrueType 1.5) */
3161 USHORT sTypoAscender;
3162 USHORT sTypoDescender;
3163 USHORT sTypoLineGap;
3164 USHORT usWinAscent;
3165 USHORT usWinDescent;
3166 /* version 1 (TrueType 1.66) */
3167 ULONG ulCodePageRange1;
3168 ULONG ulCodePageRange2;
3169 /* version 2 (OpenType 1.2) */
3170 SHORT sxHeight;
3171 SHORT sCapHeight;
3172 USHORT usDefaultChar;
3173 USHORT usBreakChar;
3174 USHORT usMaxContext;
3175 } TT_OS2_V2;
3176 #include "poppack.h"
3178 typedef struct
3180 USHORT version;
3181 USHORT num_tables;
3182 } cmap_header;
3184 typedef struct
3186 USHORT plat_id;
3187 USHORT enc_id;
3188 ULONG offset;
3189 } cmap_encoding_record;
3191 typedef struct
3193 USHORT format;
3194 USHORT length;
3195 USHORT language;
3197 BYTE glyph_ids[256];
3198 } cmap_format_0;
3200 typedef struct
3202 USHORT format;
3203 USHORT length;
3204 USHORT language;
3206 USHORT seg_countx2;
3207 USHORT search_range;
3208 USHORT entry_selector;
3209 USHORT range_shift;
3211 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3212 /* Then follows:
3213 USHORT pad;
3214 USHORT start_count[seg_countx2 / 2];
3215 USHORT id_delta[seg_countx2 / 2];
3216 USHORT id_range_offset[seg_countx2 / 2];
3217 USHORT glyph_ids[];
3219 } cmap_format_4;
3221 typedef struct
3223 USHORT end_count;
3224 USHORT start_count;
3225 USHORT id_delta;
3226 USHORT id_range_offset;
3227 } cmap_format_4_seg;
3229 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
3231 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3232 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3233 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3234 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3235 os2->panose.bWeight, os2->panose.bProportion);
3238 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3240 int i;
3241 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3243 *first = 256;
3245 for(i = 0; i < 256; i++)
3247 if(cmap->glyph_ids[i] == 0) continue;
3248 *last = i;
3249 if(*first == 256) *first = i;
3251 if(*first == 256) return FALSE;
3252 return TRUE;
3255 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3257 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3258 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3259 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3260 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3261 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3264 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3266 int i;
3267 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3268 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3270 *first = 0x10000;
3272 for(i = 0; i < seg_count; i++)
3274 cmap_format_4_seg seg;
3276 get_seg4(cmap, i, &seg);
3278 if(seg.start_count > 0xfffe) break;
3280 if(*first == 0x10000) *first = seg.start_count;
3282 *last = min(seg.end_count, 0xfffe);
3285 if(*first == 0x10000) return FALSE;
3286 return TRUE;
3289 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3291 USHORT i;
3292 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3294 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3296 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3297 return (BYTE *)header + GET_BE_DWORD(record->offset);
3298 record++;
3300 return NULL;
3303 typedef enum
3305 cmap_none,
3306 cmap_ms_unicode,
3307 cmap_ms_symbol
3308 } cmap_type;
3310 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3312 LONG size, ret;
3313 cmap_header *header;
3314 void *cmap;
3315 BOOL r = FALSE;
3316 WORD format;
3318 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3319 ok(size != GDI_ERROR, "no cmap table found\n");
3320 if(size == GDI_ERROR) return FALSE;
3322 header = HeapAlloc(GetProcessHeap(), 0, size);
3323 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3324 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3325 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3327 cmap = get_cmap(header, 3, 1);
3328 if(cmap)
3329 *cmap_type = cmap_ms_unicode;
3330 else
3332 cmap = get_cmap(header, 3, 0);
3333 if(cmap) *cmap_type = cmap_ms_symbol;
3335 if(!cmap)
3337 *cmap_type = cmap_none;
3338 goto end;
3341 format = GET_BE_WORD(*(WORD *)cmap);
3342 switch(format)
3344 case 0:
3345 r = get_first_last_from_cmap0(cmap, first, last);
3346 break;
3347 case 4:
3348 r = get_first_last_from_cmap4(cmap, first, last, size);
3349 break;
3350 default:
3351 trace("unhandled cmap format %d\n", format);
3352 break;
3355 end:
3356 HeapFree(GetProcessHeap(), 0, header);
3357 return r;
3360 #define TT_PLATFORM_MICROSOFT 3
3361 #define TT_MS_ID_SYMBOL_CS 0
3362 #define TT_MS_ID_UNICODE_CS 1
3363 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3364 #define TT_NAME_ID_FONT_FAMILY 1
3365 #define TT_NAME_ID_FONT_SUBFAMILY 2
3366 #define TT_NAME_ID_UNIQUE_ID 3
3367 #define TT_NAME_ID_FULL_NAME 4
3369 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3371 struct sfnt_name_header
3373 USHORT format;
3374 USHORT number_of_record;
3375 USHORT storage_offset;
3376 } *header;
3377 struct sfnt_name
3379 USHORT platform_id;
3380 USHORT encoding_id;
3381 USHORT language_id;
3382 USHORT name_id;
3383 USHORT length;
3384 USHORT offset;
3385 } *entry;
3386 BOOL r = FALSE;
3387 LONG size, offset, length;
3388 LONG c, ret;
3389 WCHAR *name;
3390 BYTE *data;
3391 USHORT i;
3393 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3394 ok(size != GDI_ERROR, "no name table found\n");
3395 if(size == GDI_ERROR) return FALSE;
3397 data = HeapAlloc(GetProcessHeap(), 0, size);
3398 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3399 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3401 header = (void *)data;
3402 header->format = GET_BE_WORD(header->format);
3403 header->number_of_record = GET_BE_WORD(header->number_of_record);
3404 header->storage_offset = GET_BE_WORD(header->storage_offset);
3405 if (header->format != 0)
3407 trace("got format %u\n", header->format);
3408 goto out;
3410 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3412 trace("number records out of range: %d\n", header->number_of_record);
3413 goto out;
3415 if (header->storage_offset >= size)
3417 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3418 goto out;
3421 entry = (void *)&header[1];
3422 for (i = 0; i < header->number_of_record; i++)
3424 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
3425 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
3426 GET_BE_WORD(entry[i].language_id) != language_id ||
3427 GET_BE_WORD(entry[i].name_id) != name_id)
3429 continue;
3432 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
3433 length = GET_BE_WORD(entry[i].length);
3434 if (offset + length > size)
3436 trace("entry %d is out of range\n", i);
3437 break;
3439 if (length >= out_size)
3441 trace("buffer too small for entry %d\n", i);
3442 break;
3445 name = (WCHAR *)(data + offset);
3446 for (c = 0; c < length / 2; c++)
3447 out_buf[c] = GET_BE_WORD(name[c]);
3448 out_buf[c] = 0;
3450 r = TRUE;
3451 break;
3454 out:
3455 HeapFree(GetProcessHeap(), 0, data);
3456 return r;
3459 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3461 HDC hdc;
3462 HFONT hfont, hfont_old;
3463 TEXTMETRICA tmA;
3464 TT_OS2_V2 tt_os2;
3465 LONG size, ret;
3466 const char *font_name = lf->lfFaceName;
3467 DWORD cmap_first = 0, cmap_last = 0;
3468 UINT ascent, descent, cell_height;
3469 cmap_type cmap_type;
3470 BOOL sys_lang_non_english;
3472 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3473 hdc = GetDC(0);
3475 SetLastError(0xdeadbeef);
3476 hfont = CreateFontIndirectA(lf);
3477 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3479 hfont_old = SelectObject(hdc, hfont);
3481 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3482 if (size == GDI_ERROR)
3484 trace("OS/2 chunk was not found\n");
3485 goto end_of_test;
3487 if (size > sizeof(tt_os2))
3489 trace("got too large OS/2 chunk of size %u\n", size);
3490 size = sizeof(tt_os2);
3493 memset(&tt_os2, 0, sizeof(tt_os2));
3494 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3495 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3497 SetLastError(0xdeadbeef);
3498 ret = GetTextMetricsA(hdc, &tmA);
3499 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3501 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3503 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3505 else
3507 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3508 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3509 UINT os2_first_char, os2_last_char, default_char, break_char;
3510 USHORT version;
3511 TEXTMETRICW tmW;
3513 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3514 descent = GET_BE_WORD(tt_os2.usWinDescent);
3515 cell_height = ascent + descent;
3516 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3517 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3519 version = GET_BE_WORD(tt_os2.version);
3521 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3522 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3523 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3524 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3526 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3527 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3528 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3530 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3532 expect_first_W = 0;
3533 switch(GetACP())
3535 case 1255: /* Hebrew */
3536 expect_last_W = 0xf896;
3537 break;
3538 case 1257: /* Baltic */
3539 expect_last_W = 0xf8fd;
3540 break;
3541 default:
3542 expect_last_W = 0xf0ff;
3544 expect_break_W = 0x20;
3545 expect_default_W = expect_break_W - 1;
3546 expect_first_A = 0x1e;
3547 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3549 else
3551 expect_first_W = cmap_first;
3552 expect_last_W = cmap_last;
3553 if(os2_first_char <= 1)
3554 expect_break_W = os2_first_char + 2;
3555 else if(os2_first_char > 0xff)
3556 expect_break_W = 0x20;
3557 else
3558 expect_break_W = os2_first_char;
3559 expect_default_W = expect_break_W - 1;
3560 expect_first_A = expect_default_W - 1;
3561 expect_last_A = min(expect_last_W, 0xff);
3563 expect_break_A = expect_break_W;
3564 expect_default_A = expect_default_W;
3566 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3567 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3568 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3569 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3570 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3571 else
3572 ok(tmA.tmFirstChar == expect_first_A ||
3573 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3574 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3575 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3576 ok(tmA.tmLastChar == expect_last_A ||
3577 tmA.tmLastChar == 0xff /* win9x */,
3578 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3579 else
3580 skip("tmLastChar is DBCS lead byte\n");
3581 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3582 font_name, tmA.tmBreakChar, expect_break_A);
3583 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3584 "A: tmDefaultChar for %s got %02x expected %02x\n",
3585 font_name, tmA.tmDefaultChar, expect_default_A);
3588 SetLastError(0xdeadbeef);
3589 ret = GetTextMetricsW(hdc, &tmW);
3590 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3591 "GetTextMetricsW error %u\n", GetLastError());
3592 if (ret)
3594 /* Wine uses the os2 first char */
3595 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3596 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3597 font_name, tmW.tmFirstChar, expect_first_W);
3598 else
3599 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3600 font_name, tmW.tmFirstChar, expect_first_W);
3602 /* Wine uses the os2 last char */
3603 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3604 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3605 font_name, tmW.tmLastChar, expect_last_W);
3606 else
3607 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3608 font_name, tmW.tmLastChar, expect_last_W);
3609 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3610 font_name, tmW.tmBreakChar, expect_break_W);
3611 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3612 "W: tmDefaultChar for %s got %02x expected %02x\n",
3613 font_name, tmW.tmDefaultChar, expect_default_W);
3615 /* Test the aspect ratio while we have tmW */
3616 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3617 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3618 tmW.tmDigitizedAspectX, ret);
3619 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3620 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3621 tmW.tmDigitizedAspectX, ret);
3625 /* test FF_ values */
3626 switch(tt_os2.panose.bFamilyType)
3628 case PAN_ANY:
3629 case PAN_NO_FIT:
3630 case PAN_FAMILY_TEXT_DISPLAY:
3631 case PAN_FAMILY_PICTORIAL:
3632 default:
3633 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3634 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3636 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3637 break;
3639 switch(tt_os2.panose.bSerifStyle)
3641 case PAN_ANY:
3642 case PAN_NO_FIT:
3643 default:
3644 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3645 break;
3647 case PAN_SERIF_COVE:
3648 case PAN_SERIF_OBTUSE_COVE:
3649 case PAN_SERIF_SQUARE_COVE:
3650 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3651 case PAN_SERIF_SQUARE:
3652 case PAN_SERIF_THIN:
3653 case PAN_SERIF_BONE:
3654 case PAN_SERIF_EXAGGERATED:
3655 case PAN_SERIF_TRIANGLE:
3656 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3657 break;
3659 case PAN_SERIF_NORMAL_SANS:
3660 case PAN_SERIF_OBTUSE_SANS:
3661 case PAN_SERIF_PERP_SANS:
3662 case PAN_SERIF_FLARED:
3663 case PAN_SERIF_ROUNDED:
3664 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3665 break;
3667 break;
3669 case PAN_FAMILY_SCRIPT:
3670 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3671 break;
3673 case PAN_FAMILY_DECORATIVE:
3674 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3675 break;
3678 test_negative_width(hdc, lf);
3680 end_of_test:
3681 SelectObject(hdc, hfont_old);
3682 DeleteObject(hfont);
3684 ReleaseDC(0, hdc);
3687 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3689 INT *enumed = (INT *)lParam;
3691 if (type == TRUETYPE_FONTTYPE)
3693 (*enumed)++;
3694 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
3696 return 1;
3699 static void test_GetTextMetrics(void)
3701 LOGFONTA lf;
3702 HDC hdc;
3703 INT enumed;
3705 /* Report only once */
3706 if(!pGetGlyphIndicesA)
3707 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3709 hdc = GetDC(0);
3711 memset(&lf, 0, sizeof(lf));
3712 lf.lfCharSet = DEFAULT_CHARSET;
3713 enumed = 0;
3714 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3715 trace("Tested metrics of %d truetype fonts\n", enumed);
3717 ReleaseDC(0, hdc);
3720 static void test_nonexistent_font(void)
3722 static const struct
3724 const char *name;
3725 int charset;
3726 } font_subst[] =
3728 { "Times New Roman Baltic", 186 },
3729 { "Times New Roman CE", 238 },
3730 { "Times New Roman CYR", 204 },
3731 { "Times New Roman Greek", 161 },
3732 { "Times New Roman TUR", 162 }
3734 LOGFONTA lf;
3735 HDC hdc;
3736 HFONT hfont;
3737 CHARSETINFO csi;
3738 INT cs, expected_cs, i;
3739 char buf[LF_FACESIZE];
3741 if (!is_truetype_font_installed("Arial") ||
3742 !is_truetype_font_installed("Times New Roman"))
3744 skip("Arial or Times New Roman not installed\n");
3745 return;
3748 expected_cs = GetACP();
3749 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3751 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3752 return;
3754 expected_cs = csi.ciCharset;
3755 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3757 hdc = GetDC(0);
3759 memset(&lf, 0, sizeof(lf));
3760 lf.lfHeight = 100;
3761 lf.lfWeight = FW_REGULAR;
3762 lf.lfCharSet = ANSI_CHARSET;
3763 lf.lfPitchAndFamily = FF_SWISS;
3764 strcpy(lf.lfFaceName, "Nonexistent font");
3765 hfont = CreateFontIndirectA(&lf);
3766 hfont = SelectObject(hdc, hfont);
3767 GetTextFaceA(hdc, sizeof(buf), buf);
3768 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3769 cs = GetTextCharset(hdc);
3770 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3771 DeleteObject(SelectObject(hdc, hfont));
3773 memset(&lf, 0, sizeof(lf));
3774 lf.lfHeight = -13;
3775 lf.lfWeight = FW_DONTCARE;
3776 strcpy(lf.lfFaceName, "Nonexistent font");
3777 hfont = CreateFontIndirectA(&lf);
3778 hfont = SelectObject(hdc, hfont);
3779 GetTextFaceA(hdc, sizeof(buf), buf);
3780 todo_wine /* Wine uses Arial for all substitutions */
3781 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3782 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3783 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3784 "Got %s\n", buf);
3785 cs = GetTextCharset(hdc);
3786 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3787 DeleteObject(SelectObject(hdc, hfont));
3789 memset(&lf, 0, sizeof(lf));
3790 lf.lfHeight = -13;
3791 lf.lfWeight = FW_REGULAR;
3792 strcpy(lf.lfFaceName, "Nonexistent font");
3793 hfont = CreateFontIndirectA(&lf);
3794 hfont = SelectObject(hdc, hfont);
3795 GetTextFaceA(hdc, sizeof(buf), buf);
3796 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3797 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3798 cs = GetTextCharset(hdc);
3799 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3800 DeleteObject(SelectObject(hdc, hfont));
3802 memset(&lf, 0, sizeof(lf));
3803 lf.lfHeight = -13;
3804 lf.lfWeight = FW_DONTCARE;
3805 strcpy(lf.lfFaceName, "Times New Roman");
3806 hfont = CreateFontIndirectA(&lf);
3807 hfont = SelectObject(hdc, hfont);
3808 GetTextFaceA(hdc, sizeof(buf), buf);
3809 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3810 cs = GetTextCharset(hdc);
3811 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3812 DeleteObject(SelectObject(hdc, hfont));
3814 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3816 memset(&lf, 0, sizeof(lf));
3817 lf.lfHeight = -13;
3818 lf.lfWeight = FW_REGULAR;
3819 strcpy(lf.lfFaceName, font_subst[i].name);
3820 hfont = CreateFontIndirectA(&lf);
3821 hfont = SelectObject(hdc, hfont);
3822 cs = GetTextCharset(hdc);
3823 if (font_subst[i].charset == expected_cs)
3825 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3826 GetTextFaceA(hdc, sizeof(buf), buf);
3827 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3829 else
3831 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3832 GetTextFaceA(hdc, sizeof(buf), buf);
3833 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3834 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3836 DeleteObject(SelectObject(hdc, hfont));
3838 memset(&lf, 0, sizeof(lf));
3839 lf.lfHeight = -13;
3840 lf.lfWeight = FW_DONTCARE;
3841 strcpy(lf.lfFaceName, font_subst[i].name);
3842 hfont = CreateFontIndirectA(&lf);
3843 hfont = SelectObject(hdc, hfont);
3844 GetTextFaceA(hdc, sizeof(buf), buf);
3845 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3846 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3847 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3848 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3849 "got %s for font %s\n", buf, font_subst[i].name);
3850 cs = GetTextCharset(hdc);
3851 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3852 DeleteObject(SelectObject(hdc, hfont));
3855 ReleaseDC(0, hdc);
3858 static void test_GdiRealizationInfo(void)
3860 HDC hdc;
3861 DWORD info[4];
3862 BOOL r;
3863 HFONT hfont, hfont_old;
3864 LOGFONTA lf;
3866 if(!pGdiRealizationInfo)
3868 win_skip("GdiRealizationInfo not available\n");
3869 return;
3872 hdc = GetDC(0);
3874 memset(info, 0xcc, sizeof(info));
3875 r = pGdiRealizationInfo(hdc, info);
3876 ok(r != 0, "ret 0\n");
3877 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3878 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3880 if (!is_truetype_font_installed("Arial"))
3882 skip("skipping GdiRealizationInfo with truetype font\n");
3883 goto end;
3886 memset(&lf, 0, sizeof(lf));
3887 strcpy(lf.lfFaceName, "Arial");
3888 lf.lfHeight = 20;
3889 lf.lfWeight = FW_NORMAL;
3890 hfont = CreateFontIndirectA(&lf);
3891 hfont_old = SelectObject(hdc, hfont);
3893 memset(info, 0xcc, sizeof(info));
3894 r = pGdiRealizationInfo(hdc, info);
3895 ok(r != 0, "ret 0\n");
3896 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3897 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3899 DeleteObject(SelectObject(hdc, hfont_old));
3901 end:
3902 ReleaseDC(0, hdc);
3905 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3906 the nul in the count of characters copied when the face name buffer is not
3907 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3908 always includes it. */
3909 static void test_GetTextFace(void)
3911 static const char faceA[] = "Tahoma";
3912 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3913 LOGFONTA fA = {0};
3914 LOGFONTW fW = {0};
3915 char bufA[LF_FACESIZE];
3916 WCHAR bufW[LF_FACESIZE];
3917 HFONT f, g;
3918 HDC dc;
3919 int n;
3921 if(!is_font_installed("Tahoma"))
3923 skip("Tahoma is not installed so skipping this test\n");
3924 return;
3927 /* 'A' case. */
3928 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3929 f = CreateFontIndirectA(&fA);
3930 ok(f != NULL, "CreateFontIndirectA failed\n");
3932 dc = GetDC(NULL);
3933 g = SelectObject(dc, f);
3934 n = GetTextFaceA(dc, sizeof bufA, bufA);
3935 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3936 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3938 /* Play with the count arg. */
3939 bufA[0] = 'x';
3940 n = GetTextFaceA(dc, 0, bufA);
3941 ok(n == 0, "GetTextFaceA returned %d\n", n);
3942 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3944 bufA[0] = 'x';
3945 n = GetTextFaceA(dc, 1, bufA);
3946 ok(n == 0, "GetTextFaceA returned %d\n", n);
3947 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3949 bufA[0] = 'x'; bufA[1] = 'y';
3950 n = GetTextFaceA(dc, 2, bufA);
3951 ok(n == 1, "GetTextFaceA returned %d\n", n);
3952 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3954 n = GetTextFaceA(dc, 0, NULL);
3955 ok(n == sizeof faceA ||
3956 broken(n == 0), /* win98, winMe */
3957 "GetTextFaceA returned %d\n", n);
3959 DeleteObject(SelectObject(dc, g));
3960 ReleaseDC(NULL, dc);
3962 /* 'W' case. */
3963 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3964 SetLastError(0xdeadbeef);
3965 f = CreateFontIndirectW(&fW);
3966 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3968 win_skip("CreateFontIndirectW is not implemented\n");
3969 return;
3971 ok(f != NULL, "CreateFontIndirectW failed\n");
3973 dc = GetDC(NULL);
3974 g = SelectObject(dc, f);
3975 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3976 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3977 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3979 /* Play with the count arg. */
3980 bufW[0] = 'x';
3981 n = GetTextFaceW(dc, 0, bufW);
3982 ok(n == 0, "GetTextFaceW returned %d\n", n);
3983 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3985 bufW[0] = 'x';
3986 n = GetTextFaceW(dc, 1, bufW);
3987 ok(n == 1, "GetTextFaceW returned %d\n", n);
3988 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3990 bufW[0] = 'x'; bufW[1] = 'y';
3991 n = GetTextFaceW(dc, 2, bufW);
3992 ok(n == 2, "GetTextFaceW returned %d\n", n);
3993 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3995 n = GetTextFaceW(dc, 0, NULL);
3996 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3998 DeleteObject(SelectObject(dc, g));
3999 ReleaseDC(NULL, dc);
4002 static void test_orientation(void)
4004 static const char test_str[11] = "Test String";
4005 HDC hdc;
4006 LOGFONTA lf;
4007 HFONT hfont, old_hfont;
4008 SIZE size;
4010 if (!is_truetype_font_installed("Arial"))
4012 skip("Arial is not installed\n");
4013 return;
4016 hdc = CreateCompatibleDC(0);
4017 memset(&lf, 0, sizeof(lf));
4018 lstrcpyA(lf.lfFaceName, "Arial");
4019 lf.lfHeight = 72;
4020 lf.lfOrientation = lf.lfEscapement = 900;
4021 hfont = create_font("orientation", &lf);
4022 old_hfont = SelectObject(hdc, hfont);
4023 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4024 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4025 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4026 SelectObject(hdc, old_hfont);
4027 DeleteObject(hfont);
4028 DeleteDC(hdc);
4031 static void test_oemcharset(void)
4033 HDC hdc;
4034 LOGFONTA lf, clf;
4035 HFONT hfont, old_hfont;
4036 int charset;
4038 hdc = CreateCompatibleDC(0);
4039 ZeroMemory(&lf, sizeof(lf));
4040 lf.lfHeight = 12;
4041 lf.lfCharSet = OEM_CHARSET;
4042 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4043 lstrcpyA(lf.lfFaceName, "Terminal");
4044 hfont = CreateFontIndirectA(&lf);
4045 old_hfont = SelectObject(hdc, hfont);
4046 charset = GetTextCharset(hdc);
4047 todo_wine
4048 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4049 hfont = SelectObject(hdc, old_hfont);
4050 GetObjectA(hfont, sizeof(clf), &clf);
4051 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4052 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4053 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4054 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4055 DeleteObject(hfont);
4056 DeleteDC(hdc);
4059 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4060 const TEXTMETRICA *lpntme,
4061 DWORD FontType, LPARAM lParam)
4063 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4064 CHARSETINFO csi;
4065 LOGFONTA lf = *lpelfe;
4066 HFONT hfont;
4067 DWORD found_subset;
4069 /* skip bitmap, proportional or vertical font */
4070 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4071 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4072 lf.lfFaceName[0] == '@')
4073 return 1;
4075 /* skip linked font */
4076 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4077 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4078 return 1;
4080 /* skip linked font, like SimSun-ExtB */
4081 switch (lpelfe->lfCharSet) {
4082 case SHIFTJIS_CHARSET:
4083 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4084 break;
4085 case GB2312_CHARSET:
4086 case CHINESEBIG5_CHARSET:
4087 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4088 break;
4089 case HANGEUL_CHARSET:
4090 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4091 break;
4092 default:
4093 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4094 break;
4096 if (!found_subset)
4097 return 1;
4099 /* test with an odd height */
4100 lf.lfHeight = -19;
4101 lf.lfWidth = 0;
4102 hfont = CreateFontIndirectA(&lf);
4103 if (hfont)
4105 *(HFONT *)lParam = hfont;
4106 return 0;
4108 return 1;
4111 static void test_GetGlyphOutline(void)
4113 HDC hdc;
4114 GLYPHMETRICS gm, gm2;
4115 LOGFONTA lf;
4116 HFONT hfont, old_hfont;
4117 INT ret, ret2;
4118 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4119 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4120 static const struct
4122 UINT cs;
4123 UINT a;
4124 UINT w;
4125 } c[] =
4127 {ANSI_CHARSET, 0x30, 0x30},
4128 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4129 {HANGEUL_CHARSET, 0x8141, 0xac02},
4130 {GB2312_CHARSET, 0x8141, 0x4e04},
4131 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4133 UINT i;
4135 if (!is_truetype_font_installed("Tahoma"))
4137 skip("Tahoma is not installed\n");
4138 return;
4141 hdc = CreateCompatibleDC(0);
4142 memset(&lf, 0, sizeof(lf));
4143 lf.lfHeight = 72;
4144 lstrcpyA(lf.lfFaceName, "Tahoma");
4145 SetLastError(0xdeadbeef);
4146 hfont = CreateFontIndirectA(&lf);
4147 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4148 old_hfont = SelectObject(hdc, hfont);
4150 memset(&gm, 0, sizeof(gm));
4151 SetLastError(0xdeadbeef);
4152 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4153 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4155 memset(&gm, 0, sizeof(gm));
4156 SetLastError(0xdeadbeef);
4157 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4158 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4159 ok(GetLastError() == 0xdeadbeef ||
4160 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4161 "expected 0xdeadbeef, got %u\n", GetLastError());
4163 memset(&gm, 0, sizeof(gm));
4164 SetLastError(0xdeadbeef);
4165 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4166 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4167 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4169 memset(&gm, 0, sizeof(gm));
4170 SetLastError(0xdeadbeef);
4171 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4172 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4174 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4175 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4178 /* test for needed buffer size request on space char */
4179 memset(&gm, 0, sizeof(gm));
4180 SetLastError(0xdeadbeef);
4181 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4182 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4183 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4185 /* requesting buffer size for space char + error */
4186 memset(&gm, 0, sizeof(gm));
4187 SetLastError(0xdeadbeef);
4188 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4189 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4191 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4192 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4195 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4197 DWORD dummy;
4199 memset(&gm, 0xab, sizeof(gm));
4200 SetLastError(0xdeadbeef);
4201 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4202 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4204 if (fmt[i] == GGO_METRICS)
4205 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4206 else
4207 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4208 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4209 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4212 memset(&gm, 0xab, sizeof(gm));
4213 SetLastError(0xdeadbeef);
4214 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4215 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4217 if (fmt[i] == GGO_METRICS)
4218 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4219 else
4220 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4221 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4222 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4225 memset(&gm, 0xab, sizeof(gm));
4226 SetLastError(0xdeadbeef);
4227 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4228 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4230 if (fmt[i] == GGO_METRICS)
4231 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4232 else
4233 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4234 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4235 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4238 memset(&gm, 0xab, sizeof(gm));
4239 SetLastError(0xdeadbeef);
4240 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4241 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4243 if (fmt[i] == GGO_METRICS) {
4244 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, 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);
4248 else
4250 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4251 memset(&gm2, 0xab, sizeof(gm2));
4252 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4253 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4258 SelectObject(hdc, old_hfont);
4259 DeleteObject(hfont);
4261 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4263 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4264 TEXTMETRICA tm;
4266 lf.lfFaceName[0] = '\0';
4267 lf.lfCharSet = c[i].cs;
4268 lf.lfPitchAndFamily = 0;
4269 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4271 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4272 continue;
4275 old_hfont = SelectObject(hdc, hfont);
4277 /* expected to ignore superfluous bytes (sigle-byte character) */
4278 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4279 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4280 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4282 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4283 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4284 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4286 /* expected to ignore superfluous bytes (double-byte character) */
4287 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4288 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4289 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4290 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4292 /* expected to match wide-char version results */
4293 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4294 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4296 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4298 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4299 continue;
4301 DeleteObject(SelectObject(hdc, hfont));
4302 if (c[i].a <= 0xff)
4304 DeleteObject(SelectObject(hdc, old_hfont));
4305 continue;
4308 ret = GetObjectA(hfont, sizeof lf, &lf);
4309 ok(ret > 0, "GetObject error %u\n", GetLastError());
4311 ret = GetTextMetricsA(hdc, &tm);
4312 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4313 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4314 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4315 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4316 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4317 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4318 "expected %d, got %d (%s:%d)\n",
4319 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4321 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4322 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4323 ok(gm2.gmCellIncY == -lf.lfHeight,
4324 "expected %d, got %d (%s:%d)\n",
4325 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4327 lf.lfItalic = TRUE;
4328 hfont = CreateFontIndirectA(&lf);
4329 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4330 DeleteObject(SelectObject(hdc, hfont));
4331 ret = GetTextMetricsA(hdc, &tm);
4332 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4333 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4334 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4335 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4336 "expected %d, got %d (%s:%d)\n",
4337 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4339 lf.lfItalic = FALSE;
4340 lf.lfEscapement = lf.lfOrientation = 2700;
4341 hfont = CreateFontIndirectA(&lf);
4342 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4343 DeleteObject(SelectObject(hdc, hfont));
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.gmCellIncY == -lf.lfHeight,
4347 "expected %d, got %d (%s:%d)\n",
4348 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4350 hfont = SelectObject(hdc, old_hfont);
4351 DeleteObject(hfont);
4354 DeleteDC(hdc);
4357 /* bug #9995: there is a limit to the character width that can be specified */
4358 static void test_GetTextMetrics2(const char *fontname, int font_height)
4360 HFONT of, hf;
4361 HDC hdc;
4362 TEXTMETRICA tm;
4363 BOOL ret;
4364 int ave_width, height, width, ratio, scale;
4366 if (!is_truetype_font_installed( fontname)) {
4367 skip("%s is not installed\n", fontname);
4368 return;
4370 hdc = CreateCompatibleDC(0);
4371 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4372 /* select width = 0 */
4373 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4374 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4375 DEFAULT_QUALITY, VARIABLE_PITCH,
4376 fontname);
4377 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4378 of = SelectObject( hdc, hf);
4379 ret = GetTextMetricsA( hdc, &tm);
4380 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4381 height = tm.tmHeight;
4382 ave_width = tm.tmAveCharWidth;
4383 SelectObject( hdc, of);
4384 DeleteObject( hf);
4386 trace("height %d, ave width %d\n", height, ave_width);
4388 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4390 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4391 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4392 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4393 ok(hf != 0, "CreateFont failed\n");
4394 of = SelectObject(hdc, hf);
4395 ret = GetTextMetricsA(hdc, &tm);
4396 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4397 SelectObject(hdc, of);
4398 DeleteObject(hf);
4400 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4401 break;
4404 DeleteDC(hdc);
4406 ratio = width / height;
4407 scale = width / ave_width;
4409 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4410 width, height, ratio, width, ave_width, scale);
4412 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4415 static void test_CreateFontIndirect(void)
4417 LOGFONTA lf, getobj_lf;
4418 int ret, i;
4419 HFONT hfont;
4420 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4422 memset(&lf, 0, sizeof(lf));
4423 lf.lfCharSet = ANSI_CHARSET;
4424 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4425 lf.lfHeight = 16;
4426 lf.lfWidth = 16;
4427 lf.lfQuality = DEFAULT_QUALITY;
4428 lf.lfItalic = FALSE;
4429 lf.lfWeight = FW_DONTCARE;
4431 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4433 lstrcpyA(lf.lfFaceName, TestName[i]);
4434 hfont = CreateFontIndirectA(&lf);
4435 ok(hfont != 0, "CreateFontIndirectA failed\n");
4436 SetLastError(0xdeadbeef);
4437 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4438 ok(ret, "GetObject failed: %d\n", GetLastError());
4439 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4440 ok(lf.lfWeight == getobj_lf.lfWeight ||
4441 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4442 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4443 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4444 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4445 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4446 DeleteObject(hfont);
4450 static void test_CreateFontIndirectEx(void)
4452 ENUMLOGFONTEXDVA lfex;
4453 HFONT hfont;
4455 if (!pCreateFontIndirectExA)
4457 win_skip("CreateFontIndirectExA is not available\n");
4458 return;
4461 if (!is_truetype_font_installed("Arial"))
4463 skip("Arial is not installed\n");
4464 return;
4467 SetLastError(0xdeadbeef);
4468 hfont = pCreateFontIndirectExA(NULL);
4469 ok(hfont == NULL, "got %p\n", hfont);
4470 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4472 memset(&lfex, 0, sizeof(lfex));
4473 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
4474 hfont = pCreateFontIndirectExA(&lfex);
4475 ok(hfont != 0, "CreateFontIndirectEx failed\n");
4476 if (hfont)
4477 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
4478 DeleteObject(hfont);
4481 static void free_font(void *font)
4483 UnmapViewOfFile(font);
4486 static void *load_font(const char *font_name, DWORD *font_size)
4488 char file_name[MAX_PATH];
4489 HANDLE file, mapping;
4490 void *font;
4492 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
4493 strcat(file_name, "\\fonts\\");
4494 strcat(file_name, font_name);
4496 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4497 if (file == INVALID_HANDLE_VALUE) return NULL;
4499 *font_size = GetFileSize(file, NULL);
4501 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4502 if (!mapping)
4504 CloseHandle(file);
4505 return NULL;
4508 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4510 CloseHandle(file);
4511 CloseHandle(mapping);
4512 return font;
4515 static void test_AddFontMemResource(void)
4517 void *font;
4518 DWORD font_size, num_fonts;
4519 HANDLE ret;
4520 BOOL bRet;
4522 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4524 win_skip("AddFontMemResourceEx is not available on this platform\n");
4525 return;
4528 font = load_font("sserife.fon", &font_size);
4529 if (!font)
4531 skip("Unable to locate and load font sserife.fon\n");
4532 return;
4535 SetLastError(0xdeadbeef);
4536 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4537 ok(!ret, "AddFontMemResourceEx should fail\n");
4538 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4539 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4540 GetLastError());
4542 SetLastError(0xdeadbeef);
4543 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4544 ok(!ret, "AddFontMemResourceEx should fail\n");
4545 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4546 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4547 GetLastError());
4549 SetLastError(0xdeadbeef);
4550 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4551 ok(!ret, "AddFontMemResourceEx should fail\n");
4552 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4553 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4554 GetLastError());
4556 SetLastError(0xdeadbeef);
4557 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4558 ok(!ret, "AddFontMemResourceEx should fail\n");
4559 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4560 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4561 GetLastError());
4563 SetLastError(0xdeadbeef);
4564 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4565 ok(!ret, "AddFontMemResourceEx should fail\n");
4566 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4567 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4568 GetLastError());
4570 SetLastError(0xdeadbeef);
4571 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4572 ok(!ret, "AddFontMemResourceEx should fail\n");
4573 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4574 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4575 GetLastError());
4577 num_fonts = 0xdeadbeef;
4578 SetLastError(0xdeadbeef);
4579 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4580 ok(!ret, "AddFontMemResourceEx should fail\n");
4581 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4582 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4583 GetLastError());
4584 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4586 if (0) /* hangs under windows 2000 */
4588 num_fonts = 0xdeadbeef;
4589 SetLastError(0xdeadbeef);
4590 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4591 ok(!ret, "AddFontMemResourceEx should fail\n");
4592 ok(GetLastError() == 0xdeadbeef,
4593 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4594 GetLastError());
4595 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4598 num_fonts = 0xdeadbeef;
4599 SetLastError(0xdeadbeef);
4600 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4601 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4602 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4603 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4605 free_font(font);
4607 SetLastError(0xdeadbeef);
4608 bRet = pRemoveFontMemResourceEx(ret);
4609 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4611 /* test invalid pointer to number of loaded fonts */
4612 font = load_font("sserife.fon", &font_size);
4613 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4615 SetLastError(0xdeadbeef);
4616 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4617 ok(!ret, "AddFontMemResourceEx should fail\n");
4618 ok(GetLastError() == 0xdeadbeef,
4619 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4620 GetLastError());
4622 SetLastError(0xdeadbeef);
4623 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4624 ok(!ret, "AddFontMemResourceEx should fail\n");
4625 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4626 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4627 GetLastError());
4629 free_font(font);
4632 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4634 LOGFONTA *lf;
4636 if (type != TRUETYPE_FONTTYPE) return 1;
4638 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4640 lf = (LOGFONTA *)lparam;
4641 *lf = *elf;
4642 return 0;
4645 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4647 int ret;
4648 LOGFONTA *lf;
4650 if (type != TRUETYPE_FONTTYPE) return 1;
4652 lf = (LOGFONTA *)lparam;
4653 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
4654 if(ret == 0)
4656 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4657 *lf = *elf;
4658 return 0;
4660 return 1;
4663 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4665 return lparam;
4668 static void test_EnumFonts(void)
4670 int ret;
4671 LOGFONTA lf;
4672 HDC hdc;
4673 struct enum_fullname_data efnd;
4675 if (!is_truetype_font_installed("Arial"))
4677 skip("Arial is not installed\n");
4678 return;
4681 /* Windows uses localized font face names, so Arial Bold won't be found */
4682 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4684 skip("User locale is not English, skipping the test\n");
4685 return;
4688 hdc = CreateCompatibleDC(0);
4690 /* check that the enumproc's retval is returned */
4691 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4692 ok(ret == 0xcafe, "got %08x\n", ret);
4694 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4695 ok(!ret, "font Arial is not enumerated\n");
4696 ret = strcmp(lf.lfFaceName, "Arial");
4697 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4698 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4700 strcpy(lf.lfFaceName, "Arial");
4701 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4702 ok(!ret, "font Arial is not enumerated\n");
4703 ret = strcmp(lf.lfFaceName, "Arial");
4704 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4705 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4707 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4708 ok(!ret, "font Arial Bold is not enumerated\n");
4709 ret = strcmp(lf.lfFaceName, "Arial");
4710 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4711 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4713 strcpy(lf.lfFaceName, "Arial Bold");
4714 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4715 ok(ret, "font Arial Bold should not be enumerated\n");
4717 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4718 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4719 ret = strcmp(lf.lfFaceName, "Arial");
4720 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4721 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4723 strcpy(lf.lfFaceName, "Arial Bold Italic");
4724 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4725 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4727 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4728 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4730 strcpy(lf.lfFaceName, "Arial Italic Bold");
4731 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4732 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4734 /* MS Shell Dlg and MS Shell Dlg 2 must exist */
4735 memset(&lf, 0, sizeof(lf));
4736 lf.lfCharSet = DEFAULT_CHARSET;
4738 memset(&efnd, 0, sizeof(efnd));
4739 strcpy(lf.lfFaceName, "MS Shell Dlg");
4740 ret = EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4741 ok(ret, "font MS Shell Dlg is not enumerated\n");
4742 ret = strcmp((char*)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
4743 todo_wine ok(!ret, "expected MS Shell Dlg got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
4744 ret = strcmp((char*)efnd.elf[0].elfFullName, "MS Shell Dlg");
4745 ok(ret, "did not expect MS Shell Dlg\n");
4747 memset(&efnd, 0, sizeof(efnd));
4748 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
4749 ret = EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4750 ok(ret, "font MS Shell Dlg 2 is not enumerated\n");
4751 ret = strcmp((char*)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
4752 todo_wine ok(!ret, "expected MS Shell Dlg 2 got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
4753 ret = strcmp((char*)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
4754 ok(ret, "did not expect MS Shell Dlg 2\n");
4756 DeleteDC(hdc);
4759 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4761 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
4762 const char *fullname = (const char *)lParam;
4764 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4766 return 1;
4769 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4771 HDC hdc = GetDC(0);
4772 BOOL ret = FALSE;
4774 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4775 ret = TRUE;
4777 ReleaseDC(0, hdc);
4778 return ret;
4781 static void test_fullname(void)
4783 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4784 WCHAR bufW[LF_FULLFACESIZE];
4785 char bufA[LF_FULLFACESIZE];
4786 HFONT hfont, of;
4787 LOGFONTA lf;
4788 HDC hdc;
4789 int i;
4790 DWORD ret;
4792 hdc = CreateCompatibleDC(0);
4793 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4795 memset(&lf, 0, sizeof(lf));
4796 lf.lfCharSet = ANSI_CHARSET;
4797 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4798 lf.lfHeight = 16;
4799 lf.lfWidth = 16;
4800 lf.lfQuality = DEFAULT_QUALITY;
4801 lf.lfItalic = FALSE;
4802 lf.lfWeight = FW_DONTCARE;
4804 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4806 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4808 skip("%s is not installed\n", TestName[i]);
4809 continue;
4812 lstrcpyA(lf.lfFaceName, TestName[i]);
4813 hfont = CreateFontIndirectA(&lf);
4814 ok(hfont != 0, "CreateFontIndirectA failed\n");
4816 of = SelectObject(hdc, hfont);
4817 bufW[0] = 0;
4818 bufA[0] = 0;
4819 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4820 ok(ret, "face full name could not be read\n");
4821 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4822 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4823 SelectObject(hdc, of);
4824 DeleteObject(hfont);
4826 DeleteDC(hdc);
4829 static WCHAR *prepend_at(WCHAR *family)
4831 if (!family)
4832 return NULL;
4834 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4835 family[0] = '@';
4836 return family;
4839 static void test_fullname2_helper(const char *Family)
4841 char *FamilyName, *FaceName, *StyleName, *otmStr;
4842 struct enum_fullname_data efnd;
4843 WCHAR *bufW;
4844 char *bufA;
4845 HFONT hfont, of;
4846 LOGFONTA lf;
4847 HDC hdc;
4848 int i;
4849 DWORD otm_size, ret, buf_size;
4850 OUTLINETEXTMETRICA *otm;
4851 BOOL want_vertical, get_vertical;
4852 want_vertical = ( Family[0] == '@' );
4854 hdc = CreateCompatibleDC(0);
4855 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4857 memset(&lf, 0, sizeof(lf));
4858 lf.lfCharSet = DEFAULT_CHARSET;
4859 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4860 lf.lfHeight = 16;
4861 lf.lfWidth = 16;
4862 lf.lfQuality = DEFAULT_QUALITY;
4863 lf.lfItalic = FALSE;
4864 lf.lfWeight = FW_DONTCARE;
4865 strcpy(lf.lfFaceName, Family);
4866 efnd.total = 0;
4867 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4868 if (efnd.total == 0)
4869 skip("%s is not installed\n", lf.lfFaceName);
4871 for (i = 0; i < efnd.total; i++)
4873 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4874 FaceName = (char *)efnd.elf[i].elfFullName;
4875 StyleName = (char *)efnd.elf[i].elfStyle;
4877 get_vertical = ( FamilyName[0] == '@' );
4878 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4880 lstrcpyA(lf.lfFaceName, FaceName);
4881 hfont = CreateFontIndirectA(&lf);
4882 ok(hfont != 0, "CreateFontIndirectA failed\n");
4884 of = SelectObject(hdc, hfont);
4885 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4886 ok(buf_size != GDI_ERROR, "no name table found\n");
4887 if (buf_size == GDI_ERROR) continue;
4889 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4890 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4892 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4893 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4894 memset(otm, 0, otm_size);
4895 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
4896 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4897 if (ret == 0) continue;
4899 bufW[0] = 0;
4900 bufA[0] = 0;
4901 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4902 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4903 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
4904 if (want_vertical) bufW = prepend_at(bufW);
4905 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4906 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4907 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4908 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4910 bufW[0] = 0;
4911 bufA[0] = 0;
4912 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4913 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4914 ok(ret, "FULL_NAME (face name) could not be read\n");
4915 if (want_vertical) bufW = prepend_at(bufW);
4916 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4917 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
4918 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4919 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
4921 bufW[0] = 0;
4922 bufA[0] = 0;
4923 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4924 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4925 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
4926 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4927 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
4928 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4929 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
4931 bufW[0] = 0;
4932 bufA[0] = 0;
4933 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4934 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4935 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
4936 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4937 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4938 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
4940 SelectObject(hdc, of);
4941 DeleteObject(hfont);
4943 HeapFree(GetProcessHeap(), 0, otm);
4944 HeapFree(GetProcessHeap(), 0, bufW);
4945 HeapFree(GetProcessHeap(), 0, bufA);
4947 DeleteDC(hdc);
4950 static void test_fullname2(void)
4952 test_fullname2_helper("Arial");
4953 test_fullname2_helper("DejaVu Sans");
4954 test_fullname2_helper("Lucida Sans");
4955 test_fullname2_helper("Tahoma");
4956 test_fullname2_helper("Webdings");
4957 test_fullname2_helper("Wingdings");
4958 test_fullname2_helper("SimSun");
4959 test_fullname2_helper("NSimSun");
4960 test_fullname2_helper("MingLiu");
4961 test_fullname2_helper("PMingLiu");
4962 test_fullname2_helper("WenQuanYi Micro Hei");
4963 test_fullname2_helper("MS UI Gothic");
4964 test_fullname2_helper("Ume UI Gothic");
4965 test_fullname2_helper("MS Gothic");
4966 test_fullname2_helper("Ume Gothic");
4967 test_fullname2_helper("MS PGothic");
4968 test_fullname2_helper("Ume P Gothic");
4969 test_fullname2_helper("Gulim");
4970 test_fullname2_helper("Batang");
4971 test_fullname2_helper("UnBatang");
4972 test_fullname2_helper("UnDotum");
4973 test_fullname2_helper("@SimSun");
4974 test_fullname2_helper("@NSimSun");
4975 test_fullname2_helper("@MingLiu");
4976 test_fullname2_helper("@PMingLiu");
4977 test_fullname2_helper("@WenQuanYi Micro Hei");
4978 test_fullname2_helper("@MS UI Gothic");
4979 test_fullname2_helper("@Ume UI Gothic");
4980 test_fullname2_helper("@MS Gothic");
4981 test_fullname2_helper("@Ume Gothic");
4982 test_fullname2_helper("@MS PGothic");
4983 test_fullname2_helper("@Ume P Gothic");
4984 test_fullname2_helper("@Gulim");
4985 test_fullname2_helper("@Batang");
4986 test_fullname2_helper("@UnBatang");
4987 test_fullname2_helper("@UnDotum");
4991 static void test_GetGlyphOutline_empty_contour(void)
4993 HDC hdc;
4994 LOGFONTA lf;
4995 HFONT hfont, hfont_prev;
4996 TTPOLYGONHEADER *header;
4997 GLYPHMETRICS gm;
4998 char buf[1024];
4999 DWORD ret;
5001 memset(&lf, 0, sizeof(lf));
5002 lf.lfHeight = 72;
5003 lstrcpyA(lf.lfFaceName, "wine_test");
5005 hfont = CreateFontIndirectA(&lf);
5006 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5008 hdc = GetDC(NULL);
5010 hfont_prev = SelectObject(hdc, hfont);
5011 ok(hfont_prev != NULL, "SelectObject failed\n");
5013 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5014 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5016 header = (TTPOLYGONHEADER*)buf;
5017 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5018 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5019 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5020 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5021 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5022 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5023 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5024 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5026 SelectObject(hdc, hfont_prev);
5027 DeleteObject(hfont);
5028 ReleaseDC(NULL, hdc);
5031 static void test_GetGlyphOutline_metric_clipping(void)
5033 HDC hdc;
5034 LOGFONTA lf;
5035 HFONT hfont, hfont_prev;
5036 GLYPHMETRICS gm;
5037 TEXTMETRICA tm;
5038 TEXTMETRICW tmW;
5039 DWORD ret;
5041 memset(&lf, 0, sizeof(lf));
5042 lf.lfHeight = 72;
5043 lstrcpyA(lf.lfFaceName, "wine_test");
5045 SetLastError(0xdeadbeef);
5046 hfont = CreateFontIndirectA(&lf);
5047 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5049 hdc = GetDC(NULL);
5051 hfont_prev = SelectObject(hdc, hfont);
5052 ok(hfont_prev != NULL, "SelectObject failed\n");
5054 SetLastError(0xdeadbeef);
5055 ret = GetTextMetricsA(hdc, &tm);
5056 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5058 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5059 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5060 "Glyph top(%d) exceeds ascent(%d)\n",
5061 gm.gmptGlyphOrigin.y, tm.tmAscent);
5062 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5063 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5064 "Glyph bottom(%d) exceeds descent(%d)\n",
5065 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5067 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5068 GetTextMetricsW(hdc, &tmW);
5069 todo_wine
5070 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5072 SelectObject(hdc, hfont_prev);
5073 DeleteObject(hfont);
5074 ReleaseDC(NULL, hdc);
5077 static void test_CreateScalableFontResource(void)
5079 char ttf_name[MAX_PATH];
5080 char tmp_path[MAX_PATH];
5081 char fot_name[MAX_PATH];
5082 char *file_part;
5083 DWORD ret;
5084 int i;
5086 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5088 win_skip("AddFontResourceExA is not available on this platform\n");
5089 return;
5092 if (!write_ttf_file("wine_test.ttf", ttf_name))
5094 skip("Failed to create ttf file for testing\n");
5095 return;
5098 trace("created %s\n", ttf_name);
5100 ret = is_truetype_font_installed("wine_test");
5101 ok(!ret, "font wine_test should not be enumerated\n");
5103 ret = GetTempPathA(MAX_PATH, tmp_path);
5104 ok(ret, "GetTempPath() error %d\n", GetLastError());
5105 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5106 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5108 ret = GetFileAttributesA(fot_name);
5109 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5111 SetLastError(0xdeadbeef);
5112 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5113 ok(!ret, "CreateScalableFontResource() should fail\n");
5114 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5116 SetLastError(0xdeadbeef);
5117 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5118 ok(!ret, "CreateScalableFontResource() should fail\n");
5119 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5121 file_part = strrchr(ttf_name, '\\');
5122 SetLastError(0xdeadbeef);
5123 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5124 ok(!ret, "CreateScalableFontResource() should fail\n");
5125 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5127 SetLastError(0xdeadbeef);
5128 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5129 ok(!ret, "CreateScalableFontResource() should fail\n");
5130 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5132 SetLastError(0xdeadbeef);
5133 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5134 ok(!ret, "CreateScalableFontResource() should fail\n");
5135 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5137 ret = DeleteFileA(fot_name);
5138 ok(ret, "DeleteFile() error %d\n", GetLastError());
5140 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5141 ok(!ret, "RemoveFontResourceEx() should fail\n");
5143 /* test public font resource */
5144 SetLastError(0xdeadbeef);
5145 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5146 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5148 ret = is_truetype_font_installed("wine_test");
5149 ok(!ret, "font wine_test should not be enumerated\n");
5151 SetLastError(0xdeadbeef);
5152 ret = pAddFontResourceExA(fot_name, 0, 0);
5153 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5155 ret = is_truetype_font_installed("wine_test");
5156 ok(ret, "font wine_test should be enumerated\n");
5158 test_GetGlyphOutline_empty_contour();
5159 test_GetGlyphOutline_metric_clipping();
5161 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5162 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5164 SetLastError(0xdeadbeef);
5165 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5166 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5168 ret = is_truetype_font_installed("wine_test");
5169 ok(!ret, "font wine_test should not be enumerated\n");
5171 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5172 ok(!ret, "RemoveFontResourceEx() should fail\n");
5174 /* test refcounting */
5175 for (i = 0; i < 5; i++)
5177 SetLastError(0xdeadbeef);
5178 ret = pAddFontResourceExA(fot_name, 0, 0);
5179 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5181 for (i = 0; i < 5; i++)
5183 SetLastError(0xdeadbeef);
5184 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5185 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5187 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5188 ok(!ret, "RemoveFontResourceEx() should fail\n");
5190 DeleteFileA(fot_name);
5192 /* test hidden font resource */
5193 SetLastError(0xdeadbeef);
5194 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5195 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5197 ret = is_truetype_font_installed("wine_test");
5198 ok(!ret, "font wine_test should not be enumerated\n");
5200 SetLastError(0xdeadbeef);
5201 ret = pAddFontResourceExA(fot_name, 0, 0);
5202 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5204 ret = is_truetype_font_installed("wine_test");
5205 todo_wine
5206 ok(!ret, "font wine_test should not be enumerated\n");
5208 /* XP allows removing a private font added with 0 flags */
5209 SetLastError(0xdeadbeef);
5210 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5211 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5213 ret = is_truetype_font_installed("wine_test");
5214 ok(!ret, "font wine_test should not be enumerated\n");
5216 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5217 ok(!ret, "RemoveFontResourceEx() should fail\n");
5219 DeleteFileA(fot_name);
5220 DeleteFileA(ttf_name);
5223 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5225 LOGFONTA lf;
5226 HFONT hfont, hfont_prev;
5227 HDC hdc;
5228 char facename[100];
5229 DWORD ret;
5230 static const WCHAR str[] = { 0x2025 };
5232 *installed = is_truetype_font_installed(name);
5234 lf.lfHeight = -18;
5235 lf.lfWidth = 0;
5236 lf.lfEscapement = 0;
5237 lf.lfOrientation = 0;
5238 lf.lfWeight = FW_DONTCARE;
5239 lf.lfItalic = 0;
5240 lf.lfUnderline = 0;
5241 lf.lfStrikeOut = 0;
5242 lf.lfCharSet = DEFAULT_CHARSET;
5243 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5244 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5245 lf.lfQuality = DEFAULT_QUALITY;
5246 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5247 strcpy(lf.lfFaceName, name);
5249 hfont = CreateFontIndirectA(&lf);
5250 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5252 hdc = GetDC(NULL);
5254 hfont_prev = SelectObject(hdc, hfont);
5255 ok(hfont_prev != NULL, "SelectObject failed\n");
5257 ret = GetTextFaceA(hdc, sizeof facename, facename);
5258 ok(ret, "GetTextFaceA failed\n");
5259 *selected = !strcmp(facename, name);
5261 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5262 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5263 if (!*selected)
5264 memset(gm, 0, sizeof *gm);
5266 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5267 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5269 SelectObject(hdc, hfont_prev);
5270 DeleteObject(hfont);
5271 ReleaseDC(NULL, hdc);
5274 static void check_vertical_metrics(const char *face)
5276 LOGFONTA lf;
5277 HFONT hfont, hfont_prev;
5278 HDC hdc;
5279 DWORD ret;
5280 GLYPHMETRICS rgm, vgm;
5281 const UINT code = 0x5EAD, height = 1000;
5282 WORD idx;
5283 ABC abc;
5284 OUTLINETEXTMETRICA otm;
5285 USHORT numOfLongVerMetrics;
5287 hdc = GetDC(NULL);
5289 memset(&lf, 0, sizeof(lf));
5290 strcpy(lf.lfFaceName, face);
5291 lf.lfHeight = -height;
5292 lf.lfCharSet = DEFAULT_CHARSET;
5293 lf.lfEscapement = lf.lfOrientation = 900;
5294 hfont = CreateFontIndirectA(&lf);
5295 hfont_prev = SelectObject(hdc, hfont);
5296 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5297 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5298 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5299 ok(ret, "GetCharABCWidthsW failed\n");
5300 DeleteObject(SelectObject(hdc, hfont_prev));
5302 memset(&lf, 0, sizeof(lf));
5303 strcpy(lf.lfFaceName, "@");
5304 strcat(lf.lfFaceName, face);
5305 lf.lfHeight = -height;
5306 lf.lfCharSet = DEFAULT_CHARSET;
5307 hfont = CreateFontIndirectA(&lf);
5308 hfont_prev = SelectObject(hdc, hfont);
5309 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5310 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5312 memset(&otm, 0, sizeof(otm));
5313 otm.otmSize = sizeof(otm);
5314 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5315 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5317 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5318 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5319 int offset;
5320 SHORT topSideBearing;
5322 if (!pGetGlyphIndicesW) {
5323 win_skip("GetGlyphIndices is not available on this platform\n");
5325 else {
5326 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5327 ok(ret != 0, "GetGlyphIndicesW failed\n");
5328 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5329 if (numOfLongVerMetrics > idx)
5330 offset = idx * 2 + 1;
5331 else
5332 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5333 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5334 &topSideBearing, sizeof(SHORT));
5335 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5336 topSideBearing = GET_BE_WORD(topSideBearing);
5337 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5338 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5339 "expected %d, got %d\n",
5340 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5343 else
5345 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5346 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5347 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5350 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
5351 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
5352 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5353 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
5355 DeleteObject(SelectObject(hdc, hfont_prev));
5356 ReleaseDC(NULL, hdc);
5359 static void test_vertical_font(void)
5361 char ttf_name[MAX_PATH];
5362 int num, i;
5363 BOOL ret, installed, selected;
5364 GLYPHMETRICS gm;
5365 WORD hgi, vgi;
5366 const char* face_list[] = {
5367 "@WineTestVertical", /* has vmtx table */
5368 "@Ume Gothic", /* doesn't have vmtx table */
5369 "@MS UI Gothic", /* has vmtx table, available on native */
5372 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
5374 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5375 return;
5378 if (!write_ttf_file("vertical.ttf", ttf_name))
5380 skip("Failed to create ttf file for testing\n");
5381 return;
5384 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
5385 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5387 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
5388 ok(installed, "WineTestVertical is not installed\n");
5389 ok(selected, "WineTestVertical is not selected\n");
5390 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5391 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5392 gm.gmBlackBoxX, gm.gmBlackBoxY);
5394 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
5395 ok(installed, "@WineTestVertical is not installed\n");
5396 ok(selected, "@WineTestVertical is not selected\n");
5397 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5398 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5399 gm.gmBlackBoxX, gm.gmBlackBoxY);
5401 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
5403 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
5404 const char* face = face_list[i];
5405 if (!is_truetype_font_installed(face)) {
5406 skip("%s is not installed\n", face);
5407 continue;
5409 trace("Testing %s...\n", face);
5410 check_vertical_metrics(&face[1]);
5413 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
5414 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5416 DeleteFileA(ttf_name);
5419 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
5420 DWORD type, LPARAM lParam)
5422 if (lf->lfFaceName[0] == '@') {
5423 return 0;
5425 return 1;
5428 static void test_east_asian_font_selection(void)
5430 HDC hdc;
5431 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
5432 GB2312_CHARSET, CHINESEBIG5_CHARSET };
5433 size_t i;
5435 hdc = GetDC(NULL);
5437 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
5439 LOGFONTA lf;
5440 HFONT hfont;
5441 char face_name[LF_FACESIZE];
5442 int ret;
5444 memset(&lf, 0, sizeof lf);
5445 lf.lfFaceName[0] = '\0';
5446 lf.lfCharSet = charset[i];
5448 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
5450 skip("Vertical font for charset %u is not installed\n", charset[i]);
5451 continue;
5454 hfont = CreateFontIndirectA(&lf);
5455 hfont = SelectObject(hdc, hfont);
5456 memset(face_name, 0, sizeof face_name);
5457 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5458 ok(ret && face_name[0] != '@',
5459 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
5460 DeleteObject(SelectObject(hdc, hfont));
5462 memset(&lf, 0, sizeof lf);
5463 strcpy(lf.lfFaceName, "@");
5464 lf.lfCharSet = charset[i];
5465 hfont = CreateFontIndirectA(&lf);
5466 hfont = SelectObject(hdc, hfont);
5467 memset(face_name, 0, sizeof face_name);
5468 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5469 ok(ret && face_name[0] == '@',
5470 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
5471 DeleteObject(SelectObject(hdc, hfont));
5473 ReleaseDC(NULL, hdc);
5476 static int get_font_dpi(const LOGFONTA *lf, int *height)
5478 HDC hdc = CreateCompatibleDC(0);
5479 HFONT hfont;
5480 TEXTMETRICA tm;
5481 int ret;
5483 hfont = CreateFontIndirectA(lf);
5484 ok(hfont != 0, "CreateFontIndirect failed\n");
5486 SelectObject(hdc, hfont);
5487 ret = GetTextMetricsA(hdc, &tm);
5488 ok(ret, "GetTextMetrics failed\n");
5489 ret = tm.tmDigitizedAspectX;
5490 if (height) *height = tm.tmHeight;
5492 DeleteDC(hdc);
5493 DeleteObject(hfont);
5495 return ret;
5498 static void test_stock_fonts(void)
5500 static const int font[] =
5502 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
5503 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5505 static const struct test_data
5507 int charset, weight, height, height_pixels, dpi;
5508 const char face_name[LF_FACESIZE];
5509 } td[][11] =
5511 { /* ANSI_FIXED_FONT */
5512 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
5513 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
5514 { 0 }
5516 { /* ANSI_VAR_FONT */
5517 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
5518 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
5519 { 0 }
5521 { /* SYSTEM_FONT */
5522 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5523 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5524 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5525 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5526 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5527 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5528 { 0 }
5530 { /* DEVICE_DEFAULT_FONT */
5531 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5532 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5533 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5534 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5535 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5536 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5537 { 0 }
5539 { /* DEFAULT_GUI_FONT */
5540 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
5541 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
5542 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
5543 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
5544 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
5545 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
5546 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
5547 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
5548 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5549 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
5550 { 0 }
5553 int i, j;
5555 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
5557 HFONT hfont;
5558 LOGFONTA lf;
5559 int ret, height;
5561 hfont = GetStockObject(font[i]);
5562 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
5564 ret = GetObjectA(hfont, sizeof(lf), &lf);
5565 if (ret != sizeof(lf))
5567 /* NT4 */
5568 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
5569 continue;
5572 for (j = 0; td[i][j].face_name[0] != 0; j++)
5574 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
5576 continue;
5579 ret = get_font_dpi(&lf, &height);
5580 if (ret != td[i][j].dpi)
5582 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5583 i, j, lf.lfFaceName, ret, td[i][j].dpi);
5584 continue;
5587 /* FIXME: Remove once Wine is fixed */
5588 if (td[i][j].dpi != 96 &&
5589 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5590 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
5591 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5592 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
5593 todo_wine
5594 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5595 else
5596 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5598 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
5599 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
5600 if (td[i][j].face_name[0] == '?')
5602 /* Wine doesn't have this font, skip this case for now.
5603 Actually, the face name is localized on Windows and varies
5604 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5605 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
5607 else
5609 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);
5611 break;
5616 static void test_max_height(void)
5618 HDC hdc;
5619 LOGFONTA lf;
5620 HFONT hfont, hfont_old;
5621 TEXTMETRICA tm1, tm;
5622 BOOL r;
5623 LONG invalid_height[] = { -65536, -123456, 123456 };
5624 size_t i;
5626 memset(&tm1, 0, sizeof(tm1));
5627 memset(&lf, 0, sizeof(lf));
5628 strcpy(lf.lfFaceName, "Tahoma");
5629 lf.lfHeight = -1;
5631 hdc = GetDC(NULL);
5633 /* get 1 ppem value */
5634 hfont = CreateFontIndirectA(&lf);
5635 hfont_old = SelectObject(hdc, hfont);
5636 r = GetTextMetricsA(hdc, &tm1);
5637 ok(r, "GetTextMetrics failed\n");
5638 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5639 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5640 DeleteObject(SelectObject(hdc, hfont_old));
5642 /* test the largest value */
5643 lf.lfHeight = -((1 << 16) - 1);
5644 hfont = CreateFontIndirectA(&lf);
5645 hfont_old = SelectObject(hdc, hfont);
5646 memset(&tm, 0, sizeof(tm));
5647 r = GetTextMetricsA(hdc, &tm);
5648 ok(r, "GetTextMetrics failed\n");
5649 ok(tm.tmHeight > tm1.tmHeight,
5650 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5651 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
5652 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5653 DeleteObject(SelectObject(hdc, hfont_old));
5655 /* test an invalid value */
5656 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
5657 lf.lfHeight = invalid_height[i];
5658 hfont = CreateFontIndirectA(&lf);
5659 hfont_old = SelectObject(hdc, hfont);
5660 memset(&tm, 0, sizeof(tm));
5661 r = GetTextMetricsA(hdc, &tm);
5662 ok(r, "GetTextMetrics failed\n");
5663 ok(tm.tmHeight == tm1.tmHeight,
5664 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5665 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
5666 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5667 DeleteObject(SelectObject(hdc, hfont_old));
5670 ReleaseDC(NULL, hdc);
5671 return;
5674 static void test_vertical_order(void)
5676 struct enum_font_data efd;
5677 LOGFONTA lf;
5678 HDC hdc;
5679 int i, j;
5681 hdc = CreateCompatibleDC(0);
5682 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5684 memset(&lf, 0, sizeof(lf));
5685 lf.lfCharSet = DEFAULT_CHARSET;
5686 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5687 lf.lfHeight = 16;
5688 lf.lfWidth = 16;
5689 lf.lfQuality = DEFAULT_QUALITY;
5690 lf.lfItalic = FALSE;
5691 lf.lfWeight = FW_DONTCARE;
5692 efd.total = 0;
5693 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
5694 for (i = 0; i < efd.total; i++)
5696 if (efd.lf[i].lfFaceName[0] != '@') continue;
5697 for (j = 0; j < efd.total; j++)
5699 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
5701 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
5702 break;
5706 DeleteDC( hdc );
5709 static void test_GetCharWidth32(void)
5711 BOOL ret;
5712 HDC hdc;
5713 LOGFONTA lf;
5714 HFONT hfont;
5715 INT bufferA;
5716 INT bufferW;
5717 HWND hwnd;
5719 if (!pGetCharWidth32A || !pGetCharWidth32W)
5721 win_skip("GetCharWidth32A/W not available on this platform\n");
5722 return;
5725 memset(&lf, 0, sizeof(lf));
5726 strcpy(lf.lfFaceName, "System");
5727 lf.lfHeight = 20;
5729 hfont = CreateFontIndirectA(&lf);
5730 hdc = GetDC(0);
5731 hfont = SelectObject(hdc, hfont);
5733 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5734 ok(ret, "GetCharWidth32W should have succeeded\n");
5735 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
5736 ok(ret, "GetCharWidth32A should have succeeded\n");
5737 ok (bufferA == bufferW, "Widths should be the same\n");
5738 ok (bufferA > 0," Width should be greater than zero\n");
5740 hfont = SelectObject(hdc, hfont);
5741 DeleteObject(hfont);
5742 ReleaseDC(NULL, hdc);
5744 memset(&lf, 0, sizeof(lf));
5745 strcpy(lf.lfFaceName, "Tahoma");
5746 lf.lfHeight = 20;
5748 hfont = CreateFontIndirectA(&lf);
5749 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
5750 0, 0, 0, NULL);
5751 hdc = GetDC(hwnd);
5752 SetMapMode( hdc, MM_ANISOTROPIC );
5753 SelectObject(hdc, hfont);
5755 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5756 ok(ret, "GetCharWidth32W should have succeeded\n");
5757 ok (bufferW > 0," Width should be greater than zero\n");
5758 SetWindowExtEx(hdc, -1,-1,NULL);
5759 SetGraphicsMode(hdc, GM_COMPATIBLE);
5760 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5761 ok(ret, "GetCharWidth32W should have succeeded\n");
5762 ok (bufferW > 0," Width should be greater than zero\n");
5763 SetGraphicsMode(hdc, GM_ADVANCED);
5764 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5765 ok(ret, "GetCharWidth32W should have succeeded\n");
5766 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
5767 SetWindowExtEx(hdc, 1,1,NULL);
5768 SetGraphicsMode(hdc, GM_COMPATIBLE);
5769 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5770 ok(ret, "GetCharWidth32W should have succeeded\n");
5771 ok (bufferW > 0," Width should be greater than zero\n");
5772 SetGraphicsMode(hdc, GM_ADVANCED);
5773 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5774 ok(ret, "GetCharWidth32W should have succeeded\n");
5775 ok (bufferW > 0," Width should be greater than zero\n");
5777 ReleaseDC(hwnd, hdc);
5778 DestroyWindow(hwnd);
5780 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
5781 0, 0, 0, NULL);
5782 hdc = GetDC(hwnd);
5783 SetMapMode( hdc, MM_ANISOTROPIC );
5784 SelectObject(hdc, hfont);
5786 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5787 ok(ret, "GetCharWidth32W should have succeeded\n");
5788 ok (bufferW > 0," Width should be greater than zero\n");
5789 SetWindowExtEx(hdc, -1,-1,NULL);
5790 SetGraphicsMode(hdc, GM_COMPATIBLE);
5791 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5792 ok(ret, "GetCharWidth32W should have succeeded\n");
5793 ok (bufferW > 0," Width should be greater than zero\n");
5794 SetGraphicsMode(hdc, GM_ADVANCED);
5795 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5796 ok(ret, "GetCharWidth32W should have succeeded\n");
5797 ok (bufferW > 0," Width should be greater than zero\n");
5798 SetWindowExtEx(hdc, 1,1,NULL);
5799 SetGraphicsMode(hdc, GM_COMPATIBLE);
5800 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5801 ok(ret, "GetCharWidth32W should have succeeded\n");
5802 ok (bufferW > 0," Width should be greater than zero\n");
5803 SetGraphicsMode(hdc, GM_ADVANCED);
5804 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5805 ok(ret, "GetCharWidth32W should have succeeded\n");
5806 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
5808 ReleaseDC(hwnd, hdc);
5809 DestroyWindow(hwnd);
5810 DeleteObject(hfont);
5813 static void test_fake_bold_font(void)
5815 HDC hdc;
5816 HFONT hfont, hfont_old;
5817 LOGFONTA lf;
5818 BOOL ret;
5819 TEXTMETRICA tm[2];
5820 ABC abc[2];
5821 INT w[2];
5823 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
5824 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
5825 return;
5828 /* Test outline font */
5829 memset(&lf, 0, sizeof(lf));
5830 strcpy(lf.lfFaceName, "Wingdings");
5831 lf.lfWeight = FW_NORMAL;
5832 lf.lfCharSet = SYMBOL_CHARSET;
5833 hfont = CreateFontIndirectA(&lf);
5835 hdc = GetDC(NULL);
5836 hfont_old = SelectObject(hdc, hfont);
5838 /* base metrics */
5839 ret = GetTextMetricsA(hdc, &tm[0]);
5840 ok(ret, "got %d\n", ret);
5841 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[0]);
5842 ok(ret, "got %d\n", ret);
5844 lf.lfWeight = FW_BOLD;
5845 hfont = CreateFontIndirectA(&lf);
5846 DeleteObject(SelectObject(hdc, hfont));
5848 /* bold metrics */
5849 ret = GetTextMetricsA(hdc, &tm[1]);
5850 ok(ret, "got %d\n", ret);
5851 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[1]);
5852 ok(ret, "got %d\n", ret);
5854 DeleteObject(SelectObject(hdc, hfont_old));
5855 ReleaseDC(NULL, hdc);
5857 /* compare results (outline) */
5858 ok(tm[0].tmHeight == tm[1].tmHeight, "expected %d, got %d\n", tm[0].tmHeight, tm[1].tmHeight);
5859 ok(tm[0].tmAscent == tm[1].tmAscent, "expected %d, got %d\n", tm[0].tmAscent, tm[1].tmAscent);
5860 ok(tm[0].tmDescent == tm[1].tmDescent, "expected %d, got %d\n", tm[0].tmDescent, tm[1].tmDescent);
5861 ok((tm[0].tmAveCharWidth + 1) == tm[1].tmAveCharWidth,
5862 "expected %d, got %d\n", tm[0].tmAveCharWidth + 1, tm[1].tmAveCharWidth);
5863 ok((tm[0].tmMaxCharWidth + 1) == tm[1].tmMaxCharWidth,
5864 "expected %d, got %d\n", tm[0].tmMaxCharWidth + 1, tm[1].tmMaxCharWidth);
5865 ok(tm[0].tmOverhang == tm[1].tmOverhang, "expected %d, got %d\n", tm[0].tmOverhang, tm[1].tmOverhang);
5866 w[0] = abc[0].abcA + abc[0].abcB + abc[0].abcC;
5867 w[1] = abc[1].abcA + abc[1].abcB + abc[1].abcC;
5868 ok((w[0] + 1) == w[1], "expected %d, got %d\n", w[0] + 1, w[1]);
5872 static void test_bitmap_font_glyph_index(void)
5874 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
5875 const struct {
5876 LPCSTR face;
5877 BYTE charset;
5878 } bitmap_font_list[] = {
5879 { "Courier", ANSI_CHARSET },
5880 { "Small Fonts", ANSI_CHARSET },
5881 { "Fixedsys", DEFAULT_CHARSET },
5882 { "System", DEFAULT_CHARSET }
5884 HDC hdc;
5885 LOGFONTA lf;
5886 HFONT hFont;
5887 CHAR facename[LF_FACESIZE];
5888 BITMAPINFO bmi;
5889 HBITMAP hBmp[2];
5890 void *pixels[2];
5891 int i, j;
5892 DWORD ret;
5893 BITMAP bmp;
5894 TEXTMETRICA tm;
5895 CHARSETINFO ci;
5896 BYTE chr = '\xA9';
5898 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
5899 win_skip("GetGlyphIndices is unavailable\n");
5900 return;
5903 hdc = CreateCompatibleDC(0);
5904 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5906 memset(&bmi, 0, sizeof(bmi));
5907 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
5908 bmi.bmiHeader.biBitCount = 32;
5909 bmi.bmiHeader.biPlanes = 1;
5910 bmi.bmiHeader.biWidth = 128;
5911 bmi.bmiHeader.biHeight = 32;
5912 bmi.bmiHeader.biCompression = BI_RGB;
5914 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
5915 memset(&lf, 0, sizeof(lf));
5916 lf.lfCharSet = bitmap_font_list[i].charset;
5917 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
5918 hFont = CreateFontIndirectA(&lf);
5919 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
5920 hFont = SelectObject(hdc, hFont);
5921 ret = GetTextMetricsA(hdc, &tm);
5922 ok(ret, "GetTextMetric failed\n");
5923 ret = GetTextFaceA(hdc, sizeof(facename), facename);
5924 ok(ret, "GetTextFace failed\n");
5925 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
5926 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
5927 continue;
5929 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
5930 skip("expected %s, got %s\n", lf.lfFaceName, facename);
5931 continue;
5934 for (j = 0; j < 2; j++) {
5935 HBITMAP hBmpPrev;
5936 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
5937 ok(hBmp[j] != NULL, "Can't create DIB\n");
5938 hBmpPrev = SelectObject(hdc, hBmp[j]);
5939 switch (j) {
5940 case 0:
5941 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
5942 break;
5943 case 1:
5945 int len = lstrlenW(text);
5946 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
5947 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
5948 ok(ret, "GetGlyphIndices failed\n");
5949 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
5950 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
5951 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
5952 HeapFree(GetProcessHeap(), 0, indices);
5953 break;
5956 ok(ret, "ExtTextOutW failed\n");
5957 SelectObject(hdc, hBmpPrev);
5960 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
5961 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
5962 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5964 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
5965 if (!ret) {
5966 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5967 goto next;
5969 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
5970 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
5971 goto next;
5974 for (j = 0; j < 2; j++) {
5975 HBITMAP hBmpPrev;
5976 WORD code;
5977 hBmpPrev = SelectObject(hdc, hBmp[j]);
5978 switch (j) {
5979 case 0:
5980 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
5981 break;
5982 case 1:
5983 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
5984 ok(ret, "GetGlyphIndices failed\n");
5985 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
5986 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
5987 break;
5989 ok(ret, "ExtTextOutA failed\n");
5990 SelectObject(hdc, hBmpPrev);
5993 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
5994 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5995 next:
5996 for (j = 0; j < 2; j++)
5997 DeleteObject(hBmp[j]);
5998 hFont = SelectObject(hdc, hFont);
5999 DeleteObject(hFont);
6002 DeleteDC(hdc);
6005 START_TEST(font)
6007 init();
6009 test_stock_fonts();
6010 test_logfont();
6011 test_bitmap_font();
6012 test_outline_font();
6013 test_bitmap_font_metrics();
6014 test_GdiGetCharDimensions();
6015 test_GetCharABCWidths();
6016 test_text_extents();
6017 test_GetGlyphIndices();
6018 test_GetKerningPairs();
6019 test_GetOutlineTextMetrics();
6020 test_SetTextJustification();
6021 test_font_charset();
6022 test_GdiGetCodePage();
6023 test_GetFontUnicodeRanges();
6024 test_nonexistent_font();
6025 test_orientation();
6026 test_height_selection();
6027 test_AddFontMemResource();
6028 test_EnumFonts();
6030 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6031 * I'd like to avoid them in this test.
6033 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6034 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6035 if (is_truetype_font_installed("Arial Black") &&
6036 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6038 test_EnumFontFamilies("", ANSI_CHARSET);
6039 test_EnumFontFamilies("", SYMBOL_CHARSET);
6040 test_EnumFontFamilies("", DEFAULT_CHARSET);
6042 else
6043 skip("Arial Black or Symbol/Wingdings is not installed\n");
6044 test_EnumFontFamiliesEx_default_charset();
6045 test_GetTextMetrics();
6046 test_GdiRealizationInfo();
6047 test_GetTextFace();
6048 test_GetGlyphOutline();
6049 test_GetTextMetrics2("Tahoma", -11);
6050 test_GetTextMetrics2("Tahoma", -55);
6051 test_GetTextMetrics2("Tahoma", -110);
6052 test_GetTextMetrics2("Arial", -11);
6053 test_GetTextMetrics2("Arial", -55);
6054 test_GetTextMetrics2("Arial", -110);
6055 test_CreateFontIndirect();
6056 test_CreateFontIndirectEx();
6057 test_oemcharset();
6058 test_fullname();
6059 test_fullname2();
6060 test_east_asian_font_selection();
6061 test_max_height();
6062 test_vertical_order();
6063 test_GetCharWidth32();
6064 test_fake_bold_font();
6065 test_bitmap_font_glyph_index();
6067 /* These tests should be last test until RemoveFontResource
6068 * is properly implemented.
6070 test_vertical_font();
6071 test_CreateScalableFontResource();