gdi32/tests: GetGlyphOutlineA is broken for johab charset on windows.
[wine/multimedia.git] / dlls / gdi32 / tests / font.c
bloba205ac7c610a7d3f330c28eabfa7ec9cbb5bed17
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b, exact) (abs((a) - (b)) <= ((exact) ? 0 : 1))
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
46 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
47 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
48 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
49 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
50 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
51 LPINT nfit, LPINT dxs, LPSIZE size );
52 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
53 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
54 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
55 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
56 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
57 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
59 static HMODULE hgdi32 = 0;
60 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
61 static WORD system_lang_id;
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
66 #else
67 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
69 #endif
71 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
72 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
73 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
74 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
75 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
76 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
78 static void init(void)
80 hgdi32 = GetModuleHandleA("gdi32.dll");
82 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
83 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
84 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
85 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
86 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
87 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
88 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
89 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
90 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
91 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
92 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
93 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
94 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
95 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
96 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
97 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
98 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
99 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
101 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
104 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
106 if (type != TRUETYPE_FONTTYPE) return 1;
108 return 0;
111 static BOOL is_truetype_font_installed(const char *name)
113 HDC hdc = GetDC(0);
114 BOOL ret = FALSE;
116 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
117 ret = TRUE;
119 ReleaseDC(0, hdc);
120 return ret;
123 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
125 return 0;
128 static BOOL is_font_installed(const char *name)
130 HDC hdc = GetDC(0);
131 BOOL ret = FALSE;
133 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
134 ret = TRUE;
136 ReleaseDC(0, hdc);
137 return ret;
140 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
142 HRSRC rsrc;
143 void *rsrc_data;
145 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
146 if (!rsrc) return NULL;
148 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
149 if (!rsrc_data) return NULL;
151 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
152 if (!*rsrc_size) return NULL;
154 return rsrc_data;
157 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
159 char tmp_path[MAX_PATH];
160 HANDLE hfile;
161 BOOL ret;
163 GetTempPathA(MAX_PATH, tmp_path);
164 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
166 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
167 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
169 ret = WriteFile(hfile, data, *size, size, NULL);
171 CloseHandle(hfile);
172 return ret;
175 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
177 void *rsrc_data;
178 DWORD rsrc_size;
180 rsrc_data = get_res_data( fontname, &rsrc_size );
181 if (!rsrc_data) return FALSE;
183 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
186 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
188 LOGFONTA getobj_lf;
189 int ret, minlen = 0;
191 if (!hfont)
192 return;
194 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
195 /* NT4 tries to be clever and only returns the minimum length */
196 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
197 minlen++;
198 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
199 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
200 ok(lf->lfHeight == getobj_lf.lfHeight ||
201 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
202 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
203 ok(lf->lfWidth == getobj_lf.lfWidth ||
204 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
205 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
206 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
207 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
208 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
209 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
210 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
211 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
212 ok(lf->lfWeight == getobj_lf.lfWeight ||
213 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
214 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
215 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
216 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
217 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
218 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
219 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
220 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
221 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
222 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
223 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
224 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
225 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
228 static HFONT create_font(const char* test, const LOGFONTA* lf)
230 HFONT hfont = CreateFontIndirectA(lf);
231 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
232 if (hfont)
233 check_font(test, lf, hfont);
234 return hfont;
237 static void test_logfont(void)
239 LOGFONTA lf;
240 HFONT hfont;
242 memset(&lf, 0, sizeof lf);
244 lf.lfCharSet = ANSI_CHARSET;
245 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
246 lf.lfWeight = FW_DONTCARE;
247 lf.lfHeight = 16;
248 lf.lfWidth = 16;
249 lf.lfQuality = DEFAULT_QUALITY;
251 lstrcpyA(lf.lfFaceName, "Arial");
252 hfont = create_font("Arial", &lf);
253 DeleteObject(hfont);
255 memset(&lf, 'A', sizeof(lf));
256 hfont = CreateFontIndirectA(&lf);
257 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
259 lf.lfFaceName[LF_FACESIZE - 1] = 0;
260 check_font("AAA...", &lf, hfont);
261 DeleteObject(hfont);
264 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
266 if (type & RASTER_FONTTYPE)
268 LOGFONTA *lf = (LOGFONTA *)lParam;
269 *lf = *elf;
270 return 0; /* stop enumeration */
273 return 1; /* continue enumeration */
276 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
278 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
279 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
280 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
281 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
282 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
283 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
284 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
285 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
286 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
287 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
288 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
289 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
290 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
291 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
292 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
293 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
294 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
295 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
296 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
297 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
300 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
301 LONG lfWidth, const char *test_str,
302 INT test_str_len, const TEXTMETRICA *tm_orig,
303 const SIZE *size_orig, INT width_of_A_orig,
304 INT scale_x, INT scale_y)
306 LOGFONTA lf;
307 OUTLINETEXTMETRICA otm;
308 TEXTMETRICA tm;
309 SIZE size;
310 INT width_of_A, cx, cy;
311 UINT ret;
313 if (!hfont)
314 return;
316 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
318 GetObjectA(hfont, sizeof(lf), &lf);
320 if (GetOutlineTextMetricsA(hdc, 0, NULL))
322 otm.otmSize = sizeof(otm) / 2;
323 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
324 ok(ret == sizeof(otm)/2 /* XP */ ||
325 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
327 memset(&otm, 0x1, sizeof(otm));
328 otm.otmSize = sizeof(otm);
329 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
330 ok(ret == sizeof(otm) /* XP */ ||
331 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
333 memset(&tm, 0x2, sizeof(tm));
334 ret = GetTextMetricsA(hdc, &tm);
335 ok(ret, "GetTextMetricsA failed\n");
336 /* the structure size is aligned */
337 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
339 ok(0, "tm != otm\n");
340 compare_tm(&tm, &otm.otmTextMetrics);
343 tm = otm.otmTextMetrics;
344 if (0) /* these metrics are scaled too, but with rounding errors */
346 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
347 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
349 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
350 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
351 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
352 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
353 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
354 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
356 else
358 ret = GetTextMetricsA(hdc, &tm);
359 ok(ret, "GetTextMetricsA failed\n");
362 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
363 cy = tm.tmHeight / tm_orig->tmHeight;
364 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
365 lfHeight, scale_x, scale_y, cx, cy);
366 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
367 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
368 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
369 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
370 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
372 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
373 if (lf.lfHeight)
375 if (lf.lfWidth)
376 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
378 else
379 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
381 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
383 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
384 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
386 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
388 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
391 /* Test how GDI scales bitmap font metrics */
392 static void test_bitmap_font(void)
394 static const char test_str[11] = "Test String";
395 HDC hdc;
396 LOGFONTA bitmap_lf;
397 HFONT hfont, old_hfont;
398 TEXTMETRICA tm_orig;
399 SIZE size_orig;
400 INT ret, i, width_orig, height_orig, scale, lfWidth;
402 hdc = CreateCompatibleDC(0);
404 /* "System" has only 1 pixel size defined, otherwise the test breaks */
405 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
406 if (ret)
408 ReleaseDC(0, hdc);
409 trace("no bitmap fonts were found, skipping the test\n");
410 return;
413 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
415 height_orig = bitmap_lf.lfHeight;
416 lfWidth = bitmap_lf.lfWidth;
418 hfont = create_font("bitmap", &bitmap_lf);
419 old_hfont = SelectObject(hdc, hfont);
420 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
421 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
422 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
423 SelectObject(hdc, old_hfont);
424 DeleteObject(hfont);
426 bitmap_lf.lfHeight = 0;
427 bitmap_lf.lfWidth = 4;
428 hfont = create_font("bitmap", &bitmap_lf);
429 old_hfont = SelectObject(hdc, hfont);
430 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
431 SelectObject(hdc, old_hfont);
432 DeleteObject(hfont);
434 bitmap_lf.lfHeight = height_orig;
435 bitmap_lf.lfWidth = lfWidth;
437 /* test fractional scaling */
438 for (i = 1; i <= height_orig * 6; i++)
440 INT nearest_height;
442 bitmap_lf.lfHeight = i;
443 hfont = create_font("fractional", &bitmap_lf);
444 scale = (i + height_orig - 1) / height_orig;
445 nearest_height = scale * height_orig;
446 /* Only jump to the next height if the difference <= 25% original height */
447 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
448 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
449 so we'll not test this particular height. */
450 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
451 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
452 old_hfont = SelectObject(hdc, hfont);
453 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
454 SelectObject(hdc, old_hfont);
455 DeleteObject(hfont);
458 /* test integer scaling 3x2 */
459 bitmap_lf.lfHeight = height_orig * 2;
460 bitmap_lf.lfWidth *= 3;
461 hfont = create_font("3x2", &bitmap_lf);
462 old_hfont = SelectObject(hdc, hfont);
463 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
464 SelectObject(hdc, old_hfont);
465 DeleteObject(hfont);
467 /* test integer scaling 3x3 */
468 bitmap_lf.lfHeight = height_orig * 3;
469 bitmap_lf.lfWidth = 0;
470 hfont = create_font("3x3", &bitmap_lf);
471 old_hfont = SelectObject(hdc, hfont);
472 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
473 SelectObject(hdc, old_hfont);
474 DeleteObject(hfont);
476 DeleteDC(hdc);
479 /* Test how GDI scales outline font metrics */
480 static void test_outline_font(void)
482 static const char test_str[11] = "Test String";
483 HDC hdc, hdc_2;
484 LOGFONTA lf;
485 HFONT hfont, old_hfont, old_hfont_2;
486 OUTLINETEXTMETRICA otm;
487 SIZE size_orig;
488 INT width_orig, height_orig, lfWidth;
489 XFORM xform;
490 GLYPHMETRICS gm;
491 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
492 POINT pt;
493 INT ret;
495 if (!is_truetype_font_installed("Arial"))
497 skip("Arial is not installed\n");
498 return;
501 hdc = CreateCompatibleDC(0);
503 memset(&lf, 0, sizeof(lf));
504 strcpy(lf.lfFaceName, "Arial");
505 lf.lfHeight = 72;
506 hfont = create_font("outline", &lf);
507 old_hfont = SelectObject(hdc, hfont);
508 otm.otmSize = sizeof(otm);
509 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
510 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
511 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
513 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
514 SelectObject(hdc, old_hfont);
515 DeleteObject(hfont);
517 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
518 lf.lfHeight = otm.otmEMSquare;
519 lf.lfHeight = -lf.lfHeight;
520 hfont = create_font("outline", &lf);
521 old_hfont = SelectObject(hdc, hfont);
522 otm.otmSize = sizeof(otm);
523 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
524 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
525 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
526 SelectObject(hdc, old_hfont);
527 DeleteObject(hfont);
529 height_orig = otm.otmTextMetrics.tmHeight;
530 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
532 /* test integer scaling 3x2 */
533 lf.lfHeight = height_orig * 2;
534 lf.lfWidth = lfWidth * 3;
535 hfont = create_font("3x2", &lf);
536 old_hfont = SelectObject(hdc, hfont);
537 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
538 SelectObject(hdc, old_hfont);
539 DeleteObject(hfont);
541 /* test integer scaling 3x3 */
542 lf.lfHeight = height_orig * 3;
543 lf.lfWidth = lfWidth * 3;
544 hfont = create_font("3x3", &lf);
545 old_hfont = SelectObject(hdc, hfont);
546 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
547 SelectObject(hdc, old_hfont);
548 DeleteObject(hfont);
550 /* test integer scaling 1x1 */
551 lf.lfHeight = height_orig * 1;
552 lf.lfWidth = lfWidth * 1;
553 hfont = create_font("1x1", &lf);
554 old_hfont = SelectObject(hdc, hfont);
555 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 SelectObject(hdc, old_hfont);
557 DeleteObject(hfont);
559 /* test integer scaling 1x1 */
560 lf.lfHeight = height_orig;
561 lf.lfWidth = 0;
562 hfont = create_font("1x1", &lf);
563 old_hfont = SelectObject(hdc, hfont);
564 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
566 /* with an identity matrix */
567 memset(&gm, 0, sizeof(gm));
568 SetLastError(0xdeadbeef);
569 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
570 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
571 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
572 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
573 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
574 /* with a custom matrix */
575 memset(&gm, 0, sizeof(gm));
576 SetLastError(0xdeadbeef);
577 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
578 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
580 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
581 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
585 * another DC.
587 hdc_2 = CreateCompatibleDC(0);
588 old_hfont_2 = SelectObject(hdc_2, hfont);
589 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
591 SetMapMode(hdc, MM_ANISOTROPIC);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc, 100, 100, NULL);
601 SetViewportExtEx(hdc, 50, 100, NULL);
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc, 100, 200, NULL);
611 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc, MM_TEXT);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 SelectObject(hdc_2, old_hfont_2);
622 DeleteDC(hdc_2);
624 if (!SetGraphicsMode(hdc, GM_ADVANCED))
626 SelectObject(hdc, old_hfont);
627 DeleteObject(hfont);
628 DeleteDC(hdc);
629 skip("GM_ADVANCED is not supported on this platform\n");
630 return;
633 xform.eM11 = 20.0f;
634 xform.eM12 = 0.0f;
635 xform.eM21 = 0.0f;
636 xform.eM22 = 20.0f;
637 xform.eDx = 0.0f;
638 xform.eDy = 0.0f;
640 SetLastError(0xdeadbeef);
641 ret = SetWorldTransform(hdc, &xform);
642 ok(ret, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
646 /* with an identity matrix */
647 memset(&gm, 0, sizeof(gm));
648 SetLastError(0xdeadbeef);
649 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
650 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
651 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
652 pt.x = width_orig; pt.y = 0;
653 LPtoDP(hdc, &pt, 1);
654 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
655 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
656 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
657 /* with a custom matrix */
658 memset(&gm, 0, sizeof(gm));
659 SetLastError(0xdeadbeef);
660 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
661 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
662 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
663 pt.x = width_orig; pt.y = 0;
664 LPtoDP(hdc, &pt, 1);
665 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
666 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
667 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
669 SetLastError(0xdeadbeef);
670 ret = SetMapMode(hdc, MM_LOMETRIC);
671 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
673 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
675 /* with an identity matrix */
676 memset(&gm, 0, sizeof(gm));
677 SetLastError(0xdeadbeef);
678 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
679 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
680 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
681 pt.x = width_orig; pt.y = 0;
682 LPtoDP(hdc, &pt, 1);
683 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
684 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
685 /* with a custom matrix */
686 memset(&gm, 0, sizeof(gm));
687 SetLastError(0xdeadbeef);
688 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
689 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
690 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
691 pt.x = width_orig; pt.y = 0;
692 LPtoDP(hdc, &pt, 1);
693 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
694 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
696 SetLastError(0xdeadbeef);
697 ret = SetMapMode(hdc, MM_TEXT);
698 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
700 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
702 /* with an identity matrix */
703 memset(&gm, 0, sizeof(gm));
704 SetLastError(0xdeadbeef);
705 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
706 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
708 pt.x = width_orig; pt.y = 0;
709 LPtoDP(hdc, &pt, 1);
710 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
711 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
712 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
713 /* with a custom matrix */
714 memset(&gm, 0, sizeof(gm));
715 SetLastError(0xdeadbeef);
716 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
717 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
718 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
719 pt.x = width_orig; pt.y = 0;
720 LPtoDP(hdc, &pt, 1);
721 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
722 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
723 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
725 SelectObject(hdc, old_hfont);
726 DeleteObject(hfont);
727 DeleteDC(hdc);
730 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
732 LOGFONTA *lf = (LOGFONTA *)lParam;
734 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
736 *lf = *elf;
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL is_CJK(void)
744 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const struct font_data
752 const char face_name[LF_FACESIZE];
753 int weight, height, ascent, descent, int_leading, ext_leading;
754 int ave_char_width, max_char_width, dpi;
755 BYTE first_char, last_char, def_char, break_char;
756 DWORD ansi_bitfield;
757 WORD skip_lang_id;
758 int scaled_height;
759 } fd[] =
761 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
762 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
763 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
764 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
765 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
766 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
767 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
768 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
769 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 16 },
770 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
772 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
773 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
775 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
777 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
778 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
781 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
783 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
784 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
785 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
786 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
787 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
788 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
789 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
790 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
791 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
792 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
793 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
794 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
795 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
796 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
797 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
798 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
800 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
801 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
802 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
803 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
804 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
805 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
806 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
807 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
808 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
809 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
813 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
814 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
815 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
816 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
817 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
818 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
819 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
820 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
822 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
823 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
824 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
826 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
827 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
828 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
831 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
833 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
834 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
835 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
836 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
837 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
838 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
839 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
840 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
841 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
843 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
844 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
845 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
847 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
848 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
849 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
851 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
852 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
853 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
855 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
856 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
858 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
859 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
860 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
861 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
862 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
863 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
864 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
865 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
866 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
867 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
868 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
869 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
870 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
871 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
872 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
873 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
874 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
875 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
876 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
877 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
878 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
880 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
881 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
882 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
883 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
884 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
885 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
886 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
887 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
888 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
889 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
890 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
891 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
893 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
894 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
895 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
897 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
899 /* FIXME: add "Terminal" */
901 static const int font_log_pixels[] = { 96, 120 };
902 HDC hdc;
903 LOGFONTA lf;
904 HFONT hfont, old_hfont;
905 TEXTMETRICA tm;
906 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
907 char face_name[LF_FACESIZE];
908 CHARSETINFO csi;
910 trace("system language id %04x\n", system_lang_id);
912 expected_cs = GetACP();
913 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
915 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
916 return;
918 expected_cs = csi.ciCharset;
919 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
921 hdc = CreateCompatibleDC(0);
922 assert(hdc);
924 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
925 GetDeviceCaps(hdc, LOGPIXELSY));
927 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
928 diff = 32768;
929 font_res = 0;
930 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
932 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
933 if (new_diff < diff)
935 diff = new_diff;
936 font_res = font_log_pixels[i];
939 trace("best font resolution is %d\n", font_res);
941 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
943 int bit, height;
945 memset(&lf, 0, sizeof(lf));
947 height = fd[i].height & ~FH_SCALE;
948 lf.lfHeight = height;
949 strcpy(lf.lfFaceName, fd[i].face_name);
951 for(bit = 0; bit < 32; bit++)
953 GLYPHMETRICS gm;
954 DWORD fs[2];
955 BOOL bRet;
957 fs[0] = 1L << bit;
958 fs[1] = 0;
959 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
960 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
962 lf.lfCharSet = csi.ciCharset;
963 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
964 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
965 if (fd[i].height & FH_SCALE)
966 ok(ret, "scaled font height %d should not be enumerated\n", height);
967 else
969 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
971 if (ret) /* FIXME: Remove once Wine is fixed */
972 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
973 else
974 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
977 if (ret && !(fd[i].height & FH_SCALE))
978 continue;
980 hfont = create_font(lf.lfFaceName, &lf);
981 old_hfont = SelectObject(hdc, hfont);
983 SetLastError(0xdeadbeef);
984 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
985 ok(ret, "GetTextFace error %u\n", GetLastError());
987 if (strcmp(face_name, fd[i].face_name) != 0)
989 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
990 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
991 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
992 SelectObject(hdc, old_hfont);
993 DeleteObject(hfont);
994 continue;
997 memset(&gm, 0, sizeof(gm));
998 SetLastError(0xdeadbeef);
999 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1000 todo_wine {
1001 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1002 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1005 bRet = GetTextMetricsA(hdc, &tm);
1006 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1008 SetLastError(0xdeadbeef);
1009 ret = GetTextCharset(hdc);
1010 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1011 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1012 else
1013 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1015 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1016 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1018 if(fd[i].dpi == tm.tmDigitizedAspectX)
1020 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1021 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
1023 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1024 if (fd[i].height & FH_SCALE)
1025 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
1026 else
1027 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
1028 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1029 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1030 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
1031 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
1032 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
1033 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1034 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1035 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1036 make default char test fail */
1037 if (tm.tmCharSet == lf.lfCharSet)
1038 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1039 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1040 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
1042 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1043 that make the max width bigger */
1044 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1045 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
1047 else
1048 skip("Skipping font metrics test for system langid 0x%x\n",
1049 system_lang_id);
1051 SelectObject(hdc, old_hfont);
1052 DeleteObject(hfont);
1056 DeleteDC(hdc);
1059 static void test_GdiGetCharDimensions(void)
1061 HDC hdc;
1062 TEXTMETRICW tm;
1063 LONG ret;
1064 SIZE size;
1065 LONG avgwidth, height;
1066 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1068 if (!pGdiGetCharDimensions)
1070 win_skip("GdiGetCharDimensions not available on this platform\n");
1071 return;
1074 hdc = CreateCompatibleDC(NULL);
1076 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1077 avgwidth = ((size.cx / 26) + 1) / 2;
1079 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1080 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1081 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1083 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1084 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1086 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1087 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1089 height = 0;
1090 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1091 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1092 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1094 DeleteDC(hdc);
1097 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1098 const TEXTMETRICA *lpntme,
1099 DWORD FontType, LPARAM lParam)
1101 if (FontType & TRUETYPE_FONTTYPE)
1103 HFONT hfont;
1105 hfont = CreateFontIndirectA(lpelfe);
1106 if (hfont)
1108 *(HFONT *)lParam = hfont;
1109 return 0;
1113 return 1;
1116 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1118 ABC abc[1];
1119 ABCFLOAT abcf[1];
1120 BOOL ret = FALSE;
1122 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1123 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1124 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1125 if (todo) todo_wine ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1126 else ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1127 if (todo) todo_wine ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1128 else ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1130 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1131 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1132 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1133 if (todo) todo_wine ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1134 else ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1135 if (todo) todo_wine ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1136 else ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's should be unchanged\n", description);
1138 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1139 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1140 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1141 if (todo) todo_wine ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1142 else ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's should be unchanged\n", description);
1143 if (todo) todo_wine ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1144 else ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1147 static void test_GetCharABCWidths(void)
1149 static const WCHAR str[] = {'i',0};
1150 BOOL ret;
1151 HDC hdc;
1152 LOGFONTA lf;
1153 HFONT hfont;
1154 ABC abc[1];
1155 ABC abcw[1];
1156 ABCFLOAT abcf[1];
1157 WORD glyphs[1];
1158 DWORD nb;
1159 HWND hwnd;
1160 static const struct
1162 UINT first;
1163 UINT last;
1164 } range[] =
1166 {0xff, 0xff},
1167 {0x100, 0x100},
1168 {0xff, 0x100},
1169 {0x1ff, 0xff00},
1170 {0xffff, 0xffff},
1171 {0x10000, 0x10000},
1172 {0xffff, 0x10000},
1173 {0xffffff, 0xffffff},
1174 {0x1000000, 0x1000000},
1175 {0xffffff, 0x1000000},
1176 {0xffffffff, 0xffffffff},
1177 {0x00, 0xff}
1179 static const struct
1181 UINT cs;
1182 UINT a;
1183 UINT w;
1184 BOOL r[sizeof range / sizeof range[0]];
1185 } c[] =
1187 {ANSI_CHARSET, 0x30, 0x30,
1188 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1189 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1190 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1191 {HANGEUL_CHARSET, 0x8141, 0xac02,
1192 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1193 {GB2312_CHARSET, 0x8141, 0x4e04,
1194 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1195 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1196 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1198 UINT i;
1200 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1202 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1203 return;
1206 memset(&lf, 0, sizeof(lf));
1207 strcpy(lf.lfFaceName, "System");
1208 lf.lfHeight = 20;
1210 hfont = CreateFontIndirectA(&lf);
1211 hdc = GetDC(0);
1212 hfont = SelectObject(hdc, hfont);
1214 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1215 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1217 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1218 ok(!ret, "GetCharABCWidthsI should have failed\n");
1220 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1221 ok(!ret, "GetCharABCWidthsI should have failed\n");
1223 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1224 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1226 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1227 ok(!ret, "GetCharABCWidthsW should have failed\n");
1229 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1230 ok(!ret, "GetCharABCWidthsW should have failed\n");
1232 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1233 ok(!ret, "GetCharABCWidthsW should have failed\n");
1235 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1236 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1238 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1239 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1241 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1242 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1244 hfont = SelectObject(hdc, hfont);
1245 DeleteObject(hfont);
1247 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1249 ABC a[2], w[2];
1250 ABC full[256];
1251 UINT code = 0x41, j;
1253 lf.lfFaceName[0] = '\0';
1254 lf.lfCharSet = c[i].cs;
1255 lf.lfPitchAndFamily = 0;
1256 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1258 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1259 continue;
1262 memset(a, 0, sizeof a);
1263 memset(w, 0, sizeof w);
1264 hfont = SelectObject(hdc, hfont);
1265 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1266 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1267 memcmp(a, w, sizeof a) == 0,
1268 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1270 memset(a, 0xbb, sizeof a);
1271 ret = pGetCharABCWidthsA(hdc, code, code, a);
1272 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1273 memset(full, 0xcc, sizeof full);
1274 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1275 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1276 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1277 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1279 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1281 memset(full, 0xdd, sizeof full);
1282 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1283 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1284 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1285 if (ret)
1287 UINT last = range[j].last - range[j].first;
1288 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1289 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1290 "GetCharABCWidthsA %x should match. codepage = %u\n",
1291 range[j].last, c[i].cs);
1295 hfont = SelectObject(hdc, hfont);
1296 DeleteObject(hfont);
1299 memset(&lf, 0, sizeof(lf));
1300 strcpy(lf.lfFaceName, "Tahoma");
1301 lf.lfHeight = 200;
1302 hfont = CreateFontIndirectA(&lf);
1304 /* test empty glyph's metrics */
1305 hfont = SelectObject(hdc, hfont);
1306 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1307 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1308 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1309 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1310 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1311 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1313 /* 1) prepare unrotated font metrics */
1314 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1315 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1316 DeleteObject(SelectObject(hdc, hfont));
1318 /* 2) get rotated font metrics */
1319 lf.lfEscapement = lf.lfOrientation = 900;
1320 hfont = CreateFontIndirectA(&lf);
1321 hfont = SelectObject(hdc, hfont);
1322 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1323 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1325 /* 3) compare ABC results */
1326 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1327 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1328 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1329 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1330 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1331 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1333 DeleteObject(SelectObject(hdc, hfont));
1334 ReleaseDC(NULL, hdc);
1336 trace("ABC sign test for a variety of transforms:\n");
1337 memset(&lf, 0, sizeof(lf));
1338 strcpy(lf.lfFaceName, "Tahoma");
1339 lf.lfHeight = 20;
1340 hfont = CreateFontIndirectA(&lf);
1341 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1342 0, 0, 0, NULL);
1343 hdc = GetDC(hwnd);
1344 SetMapMode(hdc, MM_ANISOTROPIC);
1345 SelectObject(hdc, hfont);
1347 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1348 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1350 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1351 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1352 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1353 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1354 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1355 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1357 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1358 SetWindowExtEx(hdc, -1, -1, NULL);
1359 SetGraphicsMode(hdc, GM_COMPATIBLE);
1360 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1361 SetGraphicsMode(hdc, GM_ADVANCED);
1362 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1363 SetWindowExtEx(hdc, 1, 1, NULL);
1364 SetGraphicsMode(hdc, GM_COMPATIBLE);
1365 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1366 SetGraphicsMode(hdc, GM_ADVANCED);
1367 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1369 ReleaseDC(hwnd, hdc);
1370 DestroyWindow(hwnd);
1372 trace("RTL layout\n");
1373 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1374 0, 0, 0, NULL);
1375 hdc = GetDC(hwnd);
1376 SetMapMode(hdc, MM_ANISOTROPIC);
1377 SelectObject(hdc, hfont);
1379 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1380 SetWindowExtEx(hdc, -1, -1, NULL);
1381 SetGraphicsMode(hdc, GM_COMPATIBLE);
1382 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1383 SetGraphicsMode(hdc, GM_ADVANCED);
1384 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1385 SetWindowExtEx(hdc, 1, 1, NULL);
1386 SetGraphicsMode(hdc, GM_COMPATIBLE);
1387 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1388 SetGraphicsMode(hdc, GM_ADVANCED);
1389 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1391 ReleaseDC(hwnd, hdc);
1392 DestroyWindow(hwnd);
1393 DeleteObject(hfont);
1396 static void test_text_extents(void)
1398 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1399 LPINT extents;
1400 INT i, len, fit1, fit2, extents2[3];
1401 LOGFONTA lf;
1402 TEXTMETRICA tm;
1403 HDC hdc;
1404 HFONT hfont;
1405 SIZE sz;
1406 SIZE sz1, sz2;
1407 BOOL ret;
1409 memset(&lf, 0, sizeof(lf));
1410 strcpy(lf.lfFaceName, "Arial");
1411 lf.lfHeight = 20;
1413 hfont = CreateFontIndirectA(&lf);
1414 hdc = GetDC(0);
1415 hfont = SelectObject(hdc, hfont);
1416 GetTextMetricsA(hdc, &tm);
1417 GetTextExtentPointA(hdc, "o", 1, &sz);
1418 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1420 SetLastError(0xdeadbeef);
1421 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1422 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1424 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1425 hfont = SelectObject(hdc, hfont);
1426 DeleteObject(hfont);
1427 ReleaseDC(0, hdc);
1428 return;
1431 len = lstrlenW(wt);
1432 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1433 extents[0] = 1; /* So that the increasing sequence test will fail
1434 if the extents array is untouched. */
1435 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1436 GetTextExtentPointW(hdc, wt, len, &sz2);
1437 ok(sz1.cy == sz2.cy,
1438 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1439 /* Because of the '\n' in the string GetTextExtentExPoint and
1440 GetTextExtentPoint return different widths under Win2k, but
1441 under WinXP they return the same width. So we don't test that
1442 here. */
1444 for (i = 1; i < len; ++i)
1445 ok(extents[i-1] <= extents[i],
1446 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1448 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1449 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1450 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1451 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1452 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1453 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1455 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1456 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1457 ok(extents[0] == extents[2] && extents[1] == extents[3],
1458 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1459 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1460 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1461 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1463 /* extents functions fail with -ve counts (the interesting case being -1) */
1464 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1465 ok(ret == FALSE, "got %d\n", ret);
1466 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1467 ok(ret == FALSE, "got %d\n", ret);
1468 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1469 ok(ret == FALSE, "got %d\n", ret);
1471 /* max_extent = 0 succeeds and returns zero */
1472 fit1 = fit2 = -215;
1473 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1474 ok(ret == TRUE ||
1475 broken(ret == FALSE), /* NT4, 2k */
1476 "got %d\n", ret);
1477 ok(fit1 == 0 ||
1478 broken(fit1 == -215), /* NT4, 2k */
1479 "fit = %d\n", fit1);
1480 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1481 ok(ret == TRUE, "got %d\n", ret);
1482 ok(fit2 == 0, "fit = %d\n", fit2);
1484 /* max_extent = -1 is interpreted as a very large width that will
1485 * definitely fit our three characters */
1486 fit1 = fit2 = -215;
1487 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1488 ok(ret == TRUE, "got %d\n", ret);
1489 ok(fit1 == 3, "fit = %d\n", fit1);
1490 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1491 ok(ret == TRUE, "got %d\n", ret);
1492 ok(fit2 == 3, "fit = %d\n", fit2);
1494 /* max_extent = -2 is interpreted similarly, but the Ansi version
1495 * rejects it while the Unicode one accepts it */
1496 fit1 = fit2 = -215;
1497 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1498 ok(ret == FALSE, "got %d\n", ret);
1499 ok(fit1 == -215, "fit = %d\n", fit1);
1500 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1501 ok(ret == TRUE, "got %d\n", ret);
1502 ok(fit2 == 3, "fit = %d\n", fit2);
1504 hfont = SelectObject(hdc, hfont);
1505 DeleteObject(hfont);
1507 /* non-MM_TEXT mapping mode */
1508 lf.lfHeight = 2000;
1509 hfont = CreateFontIndirectA(&lf);
1510 hfont = SelectObject(hdc, hfont);
1512 SetMapMode( hdc, MM_HIMETRIC );
1513 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1514 ok(ret, "got %d\n", ret);
1515 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1517 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1518 ok(ret, "got %d\n", ret);
1519 ok(fit1 == 2, "got %d\n", fit1);
1520 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1521 for(i = 0; i < 2; i++)
1522 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1524 hfont = SelectObject(hdc, hfont);
1525 DeleteObject(hfont);
1526 HeapFree(GetProcessHeap(), 0, extents);
1527 ReleaseDC(NULL, hdc);
1530 static void test_GetGlyphIndices(void)
1532 HDC hdc;
1533 HFONT hfont;
1534 DWORD charcount;
1535 LOGFONTA lf;
1536 DWORD flags = 0;
1537 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1538 WORD glyphs[(sizeof(testtext)/2)-1];
1539 TEXTMETRICA textm;
1540 HFONT hOldFont;
1542 if (!pGetGlyphIndicesW) {
1543 win_skip("GetGlyphIndicesW not available on platform\n");
1544 return;
1547 hdc = GetDC(0);
1549 memset(&lf, 0, sizeof(lf));
1550 strcpy(lf.lfFaceName, "System");
1551 lf.lfHeight = 16;
1552 lf.lfCharSet = ANSI_CHARSET;
1554 hfont = CreateFontIndirectA(&lf);
1555 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1556 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1557 if (textm.tmCharSet == ANSI_CHARSET)
1559 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1560 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1561 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1562 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1563 flags = 0;
1564 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1565 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1566 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1567 textm.tmDefaultChar, glyphs[4]);
1569 else
1570 /* FIXME: Write tests for non-ANSI charsets. */
1571 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1573 if(!is_font_installed("Tahoma"))
1575 skip("Tahoma is not installed so skipping this test\n");
1576 return;
1578 memset(&lf, 0, sizeof(lf));
1579 strcpy(lf.lfFaceName, "Tahoma");
1580 lf.lfHeight = 20;
1582 hfont = CreateFontIndirectA(&lf);
1583 hOldFont = SelectObject(hdc, hfont);
1584 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1585 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1586 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1587 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1588 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1589 flags = 0;
1590 testtext[0] = textm.tmDefaultChar;
1591 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1592 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1593 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1594 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1595 DeleteObject(SelectObject(hdc, hOldFont));
1598 static void test_GetKerningPairs(void)
1600 static const struct kerning_data
1602 const char face_name[LF_FACESIZE];
1603 LONG height;
1604 /* some interesting fields from OUTLINETEXTMETRIC */
1605 LONG tmHeight, tmAscent, tmDescent;
1606 UINT otmEMSquare;
1607 INT otmAscent;
1608 INT otmDescent;
1609 UINT otmLineGap;
1610 UINT otmsCapEmHeight;
1611 UINT otmsXHeight;
1612 INT otmMacAscent;
1613 INT otmMacDescent;
1614 UINT otmMacLineGap;
1615 UINT otmusMinimumPPEM;
1616 /* small subset of kerning pairs to test */
1617 DWORD total_kern_pairs;
1618 const KERNINGPAIR kern_pair[26];
1619 } kd[] =
1621 {"Arial", 12, 12, 9, 3,
1622 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1625 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1626 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1627 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1628 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1629 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1630 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1631 {933,970,+1},{933,972,-1}
1634 {"Arial", -34, 39, 32, 7,
1635 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1638 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1639 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1640 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1641 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1642 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1643 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1644 {933,970,+2},{933,972,-3}
1647 { "Arial", 120, 120, 97, 23,
1648 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1651 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1652 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1653 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1654 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1655 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1656 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1657 {933,970,+6},{933,972,-10}
1660 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1661 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1662 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1665 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1666 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1667 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1668 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1669 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1670 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1671 {933,970,+54},{933,972,-83}
1674 #endif
1676 LOGFONTA lf;
1677 HFONT hfont, hfont_old;
1678 KERNINGPAIR *kern_pair;
1679 HDC hdc;
1680 DWORD total_kern_pairs, ret, i, n, matches;
1682 hdc = GetDC(0);
1684 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1685 * which may render this test unusable, so we're trying to avoid that.
1687 SetLastError(0xdeadbeef);
1688 GetKerningPairsW(hdc, 0, NULL);
1689 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1691 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1692 ReleaseDC(0, hdc);
1693 return;
1696 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1698 OUTLINETEXTMETRICW otm;
1699 UINT uiRet;
1701 if (!is_font_installed(kd[i].face_name))
1703 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1704 continue;
1707 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1709 memset(&lf, 0, sizeof(lf));
1710 strcpy(lf.lfFaceName, kd[i].face_name);
1711 lf.lfHeight = kd[i].height;
1712 hfont = CreateFontIndirectA(&lf);
1713 assert(hfont != 0);
1715 hfont_old = SelectObject(hdc, hfont);
1717 SetLastError(0xdeadbeef);
1718 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1719 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1720 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1722 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1723 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1724 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1725 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1726 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1727 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1729 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1730 kd[i].otmEMSquare, otm.otmEMSquare);
1731 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1732 kd[i].otmAscent, otm.otmAscent);
1733 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1734 kd[i].otmDescent, otm.otmDescent);
1735 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1736 kd[i].otmLineGap, otm.otmLineGap);
1737 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1738 kd[i].otmMacDescent, otm.otmMacDescent);
1739 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1740 kd[i].otmMacAscent, otm.otmMacAscent);
1741 todo_wine {
1742 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1743 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1744 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1745 kd[i].otmsXHeight, otm.otmsXHeight);
1746 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1747 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1748 kd[i].otmMacLineGap, otm.otmMacLineGap);
1749 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1750 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1753 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1754 trace("total_kern_pairs %u\n", total_kern_pairs);
1755 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1757 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1758 * passes on XP.
1760 SetLastError(0xdeadbeef);
1761 ret = GetKerningPairsW(hdc, 0, kern_pair);
1762 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1763 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1764 ok(ret == 0, "got %u, expected 0\n", ret);
1766 ret = GetKerningPairsW(hdc, 100, NULL);
1767 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1769 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1770 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1772 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1773 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1775 matches = 0;
1777 for (n = 0; n < ret; n++)
1779 DWORD j;
1780 /* Disabled to limit console spam */
1781 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1782 trace("{'%c','%c',%d},\n",
1783 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1784 for (j = 0; j < kd[i].total_kern_pairs; j++)
1786 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1787 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1789 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1790 "pair %d:%d got %d, expected %d\n",
1791 kern_pair[n].wFirst, kern_pair[n].wSecond,
1792 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1793 matches++;
1798 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1799 matches, kd[i].total_kern_pairs);
1801 HeapFree(GetProcessHeap(), 0, kern_pair);
1803 SelectObject(hdc, hfont_old);
1804 DeleteObject(hfont);
1807 ReleaseDC(0, hdc);
1810 struct font_data
1812 const char face_name[LF_FACESIZE];
1813 int requested_height;
1814 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1815 BOOL exact;
1818 static void test_height( HDC hdc, const struct font_data *fd )
1820 LOGFONTA lf;
1821 HFONT hfont, old_hfont;
1822 TEXTMETRICA tm;
1823 INT ret, i;
1825 for (i = 0; fd[i].face_name[0]; i++)
1827 if (!is_truetype_font_installed(fd[i].face_name))
1829 skip("%s is not installed\n", fd[i].face_name);
1830 continue;
1833 memset(&lf, 0, sizeof(lf));
1834 lf.lfHeight = fd[i].requested_height;
1835 lf.lfWeight = fd[i].weight;
1836 strcpy(lf.lfFaceName, fd[i].face_name);
1838 hfont = CreateFontIndirectA(&lf);
1839 assert(hfont);
1841 old_hfont = SelectObject(hdc, hfont);
1842 ret = GetTextMetricsA(hdc, &tm);
1843 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1844 if(fd[i].dpi == tm.tmDigitizedAspectX)
1846 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1847 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1848 ok(match_off_by_1(tm.tmHeight, fd[i].height, fd[i].exact), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1849 ok(match_off_by_1(tm.tmAscent, fd[i].ascent, fd[i].exact), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1850 ok(match_off_by_1(tm.tmDescent, fd[i].descent, fd[i].exact), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1851 ok(match_off_by_1(tm.tmInternalLeading, fd[i].int_leading, fd[i].exact), "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1852 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1855 SelectObject(hdc, old_hfont);
1856 DeleteObject(hfont);
1860 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1862 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1863 DWORD *table = (DWORD *)ttf + 3;
1865 for (i = 0; i < num_tables; i++)
1867 if (table[0] == tag)
1868 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1869 table += 4;
1871 return NULL;
1874 static void test_height_selection_vdmx( HDC hdc )
1876 static const struct font_data charset_0[] = /* doesn't use VDMX */
1878 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1879 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1880 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1881 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1882 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1883 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1884 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1885 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1886 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1887 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1888 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1889 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1890 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1891 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1892 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1893 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1894 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1895 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1896 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1897 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1898 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1899 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1900 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1901 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1902 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1903 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1904 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1905 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1906 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1907 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1908 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1909 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1910 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1911 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1912 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1913 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1914 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1915 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1916 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1917 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1918 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1919 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1920 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1921 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1922 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1923 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1924 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1925 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1926 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1927 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1928 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1929 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1930 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1933 static const struct font_data charset_1[] = /* Uses VDMX */
1935 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1936 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1937 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1938 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1939 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1940 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1941 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1942 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1943 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1944 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1945 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1946 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1947 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1948 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1949 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1950 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1951 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1952 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1953 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1954 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1955 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1956 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1957 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1958 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
1959 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
1960 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
1961 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1962 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1963 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1964 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1965 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1966 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1967 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1968 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1969 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1970 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1971 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1972 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1973 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1974 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1975 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1976 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
1977 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
1978 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
1979 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
1980 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
1981 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
1982 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
1983 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
1984 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
1985 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
1986 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
1987 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1990 static const struct vdmx_data
1992 WORD version;
1993 BYTE bCharSet;
1994 const struct font_data *fd;
1995 } data[] =
1997 { 0, 0, charset_0 },
1998 { 0, 1, charset_1 },
1999 { 1, 0, charset_0 },
2000 { 1, 1, charset_1 }
2002 int i;
2003 DWORD size, num;
2004 WORD *vdmx_header;
2005 BYTE *ratio_rec;
2006 char ttf_name[MAX_PATH];
2007 void *res, *copy;
2009 if (!pAddFontResourceExA)
2011 win_skip("AddFontResourceExA unavailable\n");
2012 return;
2015 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2017 res = get_res_data( "wine_vdmx.ttf", &size );
2019 copy = HeapAlloc( GetProcessHeap(), 0, size );
2020 memcpy( copy, res, size );
2021 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2022 vdmx_header[0] = GET_BE_WORD( data[i].version );
2023 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2024 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2025 ratio_rec = (BYTE *)&vdmx_header[3];
2026 ratio_rec[0] = data[i].bCharSet;
2028 write_tmp_file( copy, &size, ttf_name );
2029 HeapFree( GetProcessHeap(), 0, copy );
2031 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2032 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2033 if (!num) win_skip("Unable to add ttf font resource\n");
2034 else
2036 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2037 test_height( hdc, data[i].fd );
2038 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2040 DeleteFileA( ttf_name );
2044 static void test_height_selection(void)
2046 static const struct font_data tahoma[] =
2048 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2049 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2050 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2051 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2052 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2053 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2054 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2055 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2056 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2057 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2058 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2060 HDC hdc = CreateCompatibleDC(0);
2061 assert(hdc);
2063 test_height( hdc, tahoma );
2064 test_height_selection_vdmx( hdc );
2066 DeleteDC(hdc);
2069 static void test_GetOutlineTextMetrics(void)
2071 OUTLINETEXTMETRICA *otm;
2072 LOGFONTA lf;
2073 HFONT hfont, hfont_old;
2074 HDC hdc;
2075 DWORD ret, otm_size;
2076 LPSTR unset_ptr;
2078 if (!is_font_installed("Arial"))
2080 skip("Arial is not installed\n");
2081 return;
2084 hdc = GetDC(0);
2086 memset(&lf, 0, sizeof(lf));
2087 strcpy(lf.lfFaceName, "Arial");
2088 lf.lfHeight = -13;
2089 lf.lfWeight = FW_NORMAL;
2090 lf.lfPitchAndFamily = DEFAULT_PITCH;
2091 lf.lfQuality = PROOF_QUALITY;
2092 hfont = CreateFontIndirectA(&lf);
2093 assert(hfont != 0);
2095 hfont_old = SelectObject(hdc, hfont);
2096 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2097 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2099 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2101 memset(otm, 0xAA, otm_size);
2102 SetLastError(0xdeadbeef);
2103 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2104 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2105 ok(ret == 1 /* Win9x */ ||
2106 ret == otm->otmSize /* XP*/,
2107 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2108 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2110 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2111 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2112 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2113 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2116 memset(otm, 0xAA, otm_size);
2117 SetLastError(0xdeadbeef);
2118 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2119 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2120 ok(ret == 1 /* Win9x */ ||
2121 ret == otm->otmSize /* XP*/,
2122 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2123 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2125 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2126 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2127 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2128 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2131 /* ask about truncated data */
2132 memset(otm, 0xAA, otm_size);
2133 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2134 SetLastError(0xdeadbeef);
2135 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2136 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2137 ok(ret == 1 /* Win9x */ ||
2138 ret == otm->otmSize /* XP*/,
2139 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2140 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2142 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2143 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2144 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2146 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2148 HeapFree(GetProcessHeap(), 0, otm);
2150 SelectObject(hdc, hfont_old);
2151 DeleteObject(hfont);
2153 ReleaseDC(0, hdc);
2156 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2158 INT y,
2159 breakCount,
2160 areaWidth = clientArea->right - clientArea->left,
2161 nErrors = 0, e;
2162 const char *pFirstChar, *pLastChar;
2163 SIZE size;
2164 TEXTMETRICA tm;
2165 struct err
2167 const char *start;
2168 int len;
2169 int GetTextExtentExPointWWidth;
2170 } error[20];
2172 GetTextMetricsA(hdc, &tm);
2173 y = clientArea->top;
2174 do {
2175 breakCount = 0;
2176 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2177 pFirstChar = str;
2179 do {
2180 pLastChar = str;
2182 /* if not at the end of the string, ... */
2183 if (*str == '\0') break;
2184 /* ... add the next word to the current extent */
2185 while (*str != '\0' && *str++ != tm.tmBreakChar);
2186 breakCount++;
2187 SetTextJustification(hdc, 0, 0);
2188 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2189 } while ((int) size.cx < areaWidth);
2191 /* ignore trailing break chars */
2192 breakCount--;
2193 while (*(pLastChar - 1) == tm.tmBreakChar)
2195 pLastChar--;
2196 breakCount--;
2199 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2201 SetTextJustification(hdc, 0, 0);
2202 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2204 /* do not justify the last extent */
2205 if (*str != '\0' && breakCount > 0)
2207 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2208 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2209 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2211 error[nErrors].start = pFirstChar;
2212 error[nErrors].len = pLastChar - pFirstChar;
2213 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2214 nErrors++;
2218 trace( "%u %.*s\n", size.cx, (int)(pLastChar - pFirstChar), pFirstChar);
2220 y += size.cy;
2221 str = pLastChar;
2222 } while (*str && y < clientArea->bottom);
2224 for (e = 0; e < nErrors; e++)
2226 /* The width returned by GetTextExtentPoint32() is exactly the same
2227 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2228 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2229 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2230 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2234 static void test_SetTextJustification(void)
2236 HDC hdc;
2237 RECT clientArea;
2238 LOGFONTA lf;
2239 HFONT hfont;
2240 HWND hwnd;
2241 SIZE size, expect;
2242 int i;
2243 WORD indices[2];
2244 static const char testText[] =
2245 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2246 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2247 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2248 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2249 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2250 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2251 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2253 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2254 GetClientRect( hwnd, &clientArea );
2255 hdc = GetDC( hwnd );
2257 memset(&lf, 0, sizeof lf);
2258 lf.lfCharSet = ANSI_CHARSET;
2259 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2260 lf.lfWeight = FW_DONTCARE;
2261 lf.lfHeight = 20;
2262 lf.lfQuality = DEFAULT_QUALITY;
2263 lstrcpyA(lf.lfFaceName, "Times New Roman");
2264 hfont = create_font("Times New Roman", &lf);
2265 SelectObject(hdc, hfont);
2267 testJustification(hdc, testText, &clientArea);
2269 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2270 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2272 SetTextJustification(hdc, 0, 0);
2273 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2274 GetTextExtentPoint32A(hdc, " ", 3, &size);
2275 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2276 SetTextJustification(hdc, 4, 1);
2277 GetTextExtentPoint32A(hdc, " ", 1, &size);
2278 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2279 SetTextJustification(hdc, 9, 2);
2280 GetTextExtentPoint32A(hdc, " ", 2, &size);
2281 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2282 SetTextJustification(hdc, 7, 3);
2283 GetTextExtentPoint32A(hdc, " ", 3, &size);
2284 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2285 SetTextJustification(hdc, 7, 3);
2286 SetTextCharacterExtra(hdc, 2 );
2287 GetTextExtentPoint32A(hdc, " ", 3, &size);
2288 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2289 SetTextJustification(hdc, 0, 0);
2290 SetTextCharacterExtra(hdc, 0);
2291 size.cx = size.cy = 1234;
2292 GetTextExtentPoint32A(hdc, " ", 0, &size);
2293 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2294 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2295 SetTextJustification(hdc, 5, 1);
2296 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2297 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2298 SetTextJustification(hdc, 0, 0);
2300 SetMapMode( hdc, MM_ANISOTROPIC );
2301 SetWindowExtEx( hdc, 2, 2, NULL );
2302 GetClientRect( hwnd, &clientArea );
2303 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2304 testJustification(hdc, testText, &clientArea);
2306 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2307 for (i = 0; i < 10; i++)
2309 SetTextCharacterExtra(hdc, i);
2310 GetTextExtentPoint32A(hdc, "A", 1, &size);
2311 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2313 SetTextCharacterExtra(hdc, 0);
2314 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2315 for (i = 0; i < 10; i++)
2317 SetTextCharacterExtra(hdc, i);
2318 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2319 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2321 SetTextCharacterExtra(hdc, 0);
2323 SetViewportExtEx( hdc, 3, 3, NULL );
2324 GetClientRect( hwnd, &clientArea );
2325 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2326 testJustification(hdc, testText, &clientArea);
2328 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2329 for (i = 0; i < 10; i++)
2331 SetTextCharacterExtra(hdc, i);
2332 GetTextExtentPoint32A(hdc, "A", 1, &size);
2333 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2336 done:
2337 DeleteObject(hfont);
2338 ReleaseDC(hwnd, hdc);
2339 DestroyWindow(hwnd);
2342 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2344 HDC hdc;
2345 LOGFONTA lf;
2346 HFONT hfont, hfont_old;
2347 CHARSETINFO csi;
2348 FONTSIGNATURE fs;
2349 INT cs;
2350 DWORD i, ret;
2351 char name[64];
2353 assert(count <= 128);
2355 memset(&lf, 0, sizeof(lf));
2357 lf.lfCharSet = charset;
2358 lf.lfHeight = 10;
2359 lstrcpyA(lf.lfFaceName, "Arial");
2360 SetLastError(0xdeadbeef);
2361 hfont = CreateFontIndirectA(&lf);
2362 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2364 hdc = GetDC(0);
2365 hfont_old = SelectObject(hdc, hfont);
2367 cs = GetTextCharsetInfo(hdc, &fs, 0);
2368 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2370 SetLastError(0xdeadbeef);
2371 ret = GetTextFaceA(hdc, sizeof(name), name);
2372 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2374 if (charset == SYMBOL_CHARSET)
2376 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2377 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
2379 else
2381 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2382 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2385 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2387 trace("Can't find codepage for charset %d\n", cs);
2388 ReleaseDC(0, hdc);
2389 return FALSE;
2391 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2393 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2395 skip("Font code page %d, looking for code page %d\n",
2396 pGdiGetCodePage(hdc), code_page);
2397 ReleaseDC(0, hdc);
2398 return FALSE;
2401 if (unicode)
2403 char ansi_buf[128];
2404 WCHAR unicode_buf[128];
2406 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2408 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2410 SetLastError(0xdeadbeef);
2411 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2412 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2413 count, ret, GetLastError());
2415 else
2417 char ansi_buf[128];
2419 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2421 SetLastError(0xdeadbeef);
2422 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2423 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2424 count, ret, GetLastError());
2427 SelectObject(hdc, hfont_old);
2428 DeleteObject(hfont);
2430 ReleaseDC(0, hdc);
2432 return TRUE;
2435 static void test_font_charset(void)
2437 static struct charset_data
2439 INT charset;
2440 UINT code_page;
2441 WORD font_idxA[128], font_idxW[128];
2442 } cd[] =
2444 { ANSI_CHARSET, 1252 },
2445 { RUSSIAN_CHARSET, 1251 },
2446 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2448 int i;
2450 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2452 win_skip("Skipping the font charset test on a Win9x platform\n");
2453 return;
2456 if (!is_font_installed("Arial"))
2458 skip("Arial is not installed\n");
2459 return;
2462 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2464 if (cd[i].charset == SYMBOL_CHARSET)
2466 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2468 skip("Symbol or Wingdings is not installed\n");
2469 break;
2472 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2473 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2474 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2477 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2478 if (i > 2)
2480 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2481 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2483 else
2484 skip("Symbol or Wingdings is not installed\n");
2487 static void test_GdiGetCodePage(void)
2489 static const struct _matching_data
2491 UINT current_codepage;
2492 LPCSTR lfFaceName;
2493 UCHAR lfCharSet;
2494 UINT expected_codepage;
2495 } matching_data[] = {
2496 {1251, "Arial", ANSI_CHARSET, 1252},
2497 {1251, "Tahoma", ANSI_CHARSET, 1252},
2499 {1252, "Arial", ANSI_CHARSET, 1252},
2500 {1252, "Tahoma", ANSI_CHARSET, 1252},
2502 {1253, "Arial", ANSI_CHARSET, 1252},
2503 {1253, "Tahoma", ANSI_CHARSET, 1252},
2505 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2506 { 932, "Tahoma", ANSI_CHARSET, 1252},
2507 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2509 { 936, "Arial", ANSI_CHARSET, 936},
2510 { 936, "Tahoma", ANSI_CHARSET, 936},
2511 { 936, "Simsun", ANSI_CHARSET, 936},
2513 { 949, "Arial", ANSI_CHARSET, 949},
2514 { 949, "Tahoma", ANSI_CHARSET, 949},
2515 { 949, "Gulim", ANSI_CHARSET, 949},
2517 { 950, "Arial", ANSI_CHARSET, 950},
2518 { 950, "Tahoma", ANSI_CHARSET, 950},
2519 { 950, "PMingLiU", ANSI_CHARSET, 950},
2521 HDC hdc;
2522 LOGFONTA lf;
2523 HFONT hfont;
2524 UINT charset, acp;
2525 DWORD codepage;
2526 int i;
2528 if (!pGdiGetCodePage)
2530 skip("GdiGetCodePage not available on this platform\n");
2531 return;
2534 acp = GetACP();
2536 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2538 /* only test data matched current locale codepage */
2539 if (matching_data[i].current_codepage != acp)
2540 continue;
2542 if (!is_font_installed(matching_data[i].lfFaceName))
2544 skip("%s is not installed\n", matching_data[i].lfFaceName);
2545 continue;
2548 hdc = GetDC(0);
2550 memset(&lf, 0, sizeof(lf));
2551 lf.lfHeight = -16;
2552 lf.lfCharSet = matching_data[i].lfCharSet;
2553 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2554 hfont = CreateFontIndirectA(&lf);
2555 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2557 hfont = SelectObject(hdc, hfont);
2558 charset = GetTextCharset(hdc);
2559 codepage = pGdiGetCodePage(hdc);
2560 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2561 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2562 ok(codepage == matching_data[i].expected_codepage,
2563 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2565 hfont = SelectObject(hdc, hfont);
2566 DeleteObject(hfont);
2567 ReleaseDC(NULL, hdc);
2571 static void test_GetFontUnicodeRanges(void)
2573 LOGFONTA lf;
2574 HDC hdc;
2575 HFONT hfont, hfont_old;
2576 DWORD size;
2577 GLYPHSET *gs;
2578 DWORD i;
2580 if (!pGetFontUnicodeRanges)
2582 win_skip("GetFontUnicodeRanges not available before W2K\n");
2583 return;
2586 memset(&lf, 0, sizeof(lf));
2587 lstrcpyA(lf.lfFaceName, "Arial");
2588 hfont = create_font("Arial", &lf);
2590 hdc = GetDC(0);
2591 hfont_old = SelectObject(hdc, hfont);
2593 size = pGetFontUnicodeRanges(NULL, NULL);
2594 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2596 size = pGetFontUnicodeRanges(hdc, NULL);
2597 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2599 gs = HeapAlloc(GetProcessHeap(), 0, size);
2601 size = pGetFontUnicodeRanges(hdc, gs);
2602 ok(size, "GetFontUnicodeRanges failed\n");
2604 if (0) /* Disabled to limit console spam */
2605 for (i = 0; i < gs->cRanges; i++)
2606 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2607 trace("found %u ranges\n", gs->cRanges);
2609 HeapFree(GetProcessHeap(), 0, gs);
2611 SelectObject(hdc, hfont_old);
2612 DeleteObject(hfont);
2613 ReleaseDC(NULL, hdc);
2616 #define MAX_ENUM_FONTS 4096
2618 struct enum_font_data
2620 int total;
2621 LOGFONTA lf[MAX_ENUM_FONTS];
2624 struct enum_fullname_data
2626 int total;
2627 ENUMLOGFONTA elf[MAX_ENUM_FONTS];
2630 struct enum_font_dataW
2632 int total;
2633 LOGFONTW lf[MAX_ENUM_FONTS];
2636 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2638 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2639 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2641 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2642 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2644 if (type != TRUETYPE_FONTTYPE) return 1;
2646 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2648 if (0) /* Disabled to limit console spam */
2649 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2650 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2651 if (efd->total < MAX_ENUM_FONTS)
2652 efd->lf[efd->total++] = *lf;
2653 else
2654 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2656 return 1;
2659 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2661 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2662 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2664 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2665 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2667 if (type != TRUETYPE_FONTTYPE) return 1;
2669 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2671 if (0) /* Disabled to limit console spam */
2672 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2673 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2674 if (efd->total < MAX_ENUM_FONTS)
2675 efd->lf[efd->total++] = *lf;
2676 else
2677 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2679 return 1;
2682 static void get_charset_stats(struct enum_font_data *efd,
2683 int *ansi_charset, int *symbol_charset,
2684 int *russian_charset)
2686 int i;
2688 *ansi_charset = 0;
2689 *symbol_charset = 0;
2690 *russian_charset = 0;
2692 for (i = 0; i < efd->total; i++)
2694 switch (efd->lf[i].lfCharSet)
2696 case ANSI_CHARSET:
2697 (*ansi_charset)++;
2698 break;
2699 case SYMBOL_CHARSET:
2700 (*symbol_charset)++;
2701 break;
2702 case RUSSIAN_CHARSET:
2703 (*russian_charset)++;
2704 break;
2709 static void get_charset_statsW(struct enum_font_dataW *efd,
2710 int *ansi_charset, int *symbol_charset,
2711 int *russian_charset)
2713 int i;
2715 *ansi_charset = 0;
2716 *symbol_charset = 0;
2717 *russian_charset = 0;
2719 for (i = 0; i < efd->total; i++)
2721 switch (efd->lf[i].lfCharSet)
2723 case ANSI_CHARSET:
2724 (*ansi_charset)++;
2725 break;
2726 case SYMBOL_CHARSET:
2727 (*symbol_charset)++;
2728 break;
2729 case RUSSIAN_CHARSET:
2730 (*russian_charset)++;
2731 break;
2736 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2738 struct enum_font_data efd;
2739 struct enum_font_dataW efdw;
2740 LOGFONTA lf;
2741 HDC hdc;
2742 int i, ret, ansi_charset, symbol_charset, russian_charset;
2744 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2746 if (*font_name && !is_truetype_font_installed(font_name))
2748 skip("%s is not installed\n", font_name);
2749 return;
2752 hdc = GetDC(0);
2754 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2755 * while EnumFontFamiliesEx doesn't.
2757 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2760 * Use EnumFontFamiliesW since win98 crashes when the
2761 * second parameter is NULL using EnumFontFamilies
2763 efdw.total = 0;
2764 SetLastError(0xdeadbeef);
2765 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2766 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2767 if(ret)
2769 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2770 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2771 ansi_charset, symbol_charset, russian_charset);
2772 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2773 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2774 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2775 ok(russian_charset > 0 ||
2776 broken(russian_charset == 0), /* NT4 */
2777 "NULL family should enumerate RUSSIAN_CHARSET\n");
2780 efdw.total = 0;
2781 SetLastError(0xdeadbeef);
2782 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2783 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW 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, "NULL family should enumerate RUSSIAN_CHARSET\n");
2796 efd.total = 0;
2797 SetLastError(0xdeadbeef);
2798 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2799 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2800 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2801 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2802 ansi_charset, symbol_charset, russian_charset,
2803 *font_name ? font_name : "<empty>");
2804 if (*font_name)
2805 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2806 else
2807 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2808 for (i = 0; i < efd.total; i++)
2810 /* FIXME: remove completely once Wine is fixed */
2811 if (efd.lf[i].lfCharSet != font_charset)
2813 todo_wine
2814 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2816 else
2817 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2818 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2819 font_name, efd.lf[i].lfFaceName);
2822 memset(&lf, 0, sizeof(lf));
2823 lf.lfCharSet = ANSI_CHARSET;
2824 strcpy(lf.lfFaceName, font_name);
2825 efd.total = 0;
2826 SetLastError(0xdeadbeef);
2827 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2828 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2829 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2830 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2831 ansi_charset, symbol_charset, russian_charset,
2832 *font_name ? font_name : "<empty>");
2833 if (font_charset == SYMBOL_CHARSET)
2835 if (*font_name)
2836 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2837 else
2838 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2840 else
2842 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2843 for (i = 0; i < efd.total; i++)
2845 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2846 if (*font_name)
2847 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2848 font_name, efd.lf[i].lfFaceName);
2852 /* DEFAULT_CHARSET should enumerate all available charsets */
2853 memset(&lf, 0, sizeof(lf));
2854 lf.lfCharSet = DEFAULT_CHARSET;
2855 strcpy(lf.lfFaceName, font_name);
2856 efd.total = 0;
2857 SetLastError(0xdeadbeef);
2858 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2859 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2860 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2861 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2862 ansi_charset, symbol_charset, russian_charset,
2863 *font_name ? font_name : "<empty>");
2864 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2865 for (i = 0; i < efd.total; i++)
2867 if (*font_name)
2868 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2869 font_name, efd.lf[i].lfFaceName);
2871 if (*font_name)
2873 switch (font_charset)
2875 case ANSI_CHARSET:
2876 ok(ansi_charset > 0,
2877 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2878 ok(!symbol_charset,
2879 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2880 ok(russian_charset > 0,
2881 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2882 break;
2883 case SYMBOL_CHARSET:
2884 ok(!ansi_charset,
2885 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2886 ok(symbol_charset,
2887 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2888 ok(!russian_charset,
2889 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2890 break;
2891 case DEFAULT_CHARSET:
2892 ok(ansi_charset > 0,
2893 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2894 ok(symbol_charset > 0,
2895 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2896 ok(russian_charset > 0,
2897 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2898 break;
2901 else
2903 ok(ansi_charset > 0,
2904 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2905 ok(symbol_charset > 0,
2906 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2907 ok(russian_charset > 0,
2908 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2911 memset(&lf, 0, sizeof(lf));
2912 lf.lfCharSet = SYMBOL_CHARSET;
2913 strcpy(lf.lfFaceName, font_name);
2914 efd.total = 0;
2915 SetLastError(0xdeadbeef);
2916 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2917 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2918 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2919 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2920 ansi_charset, symbol_charset, russian_charset,
2921 *font_name ? font_name : "<empty>");
2922 if (*font_name && font_charset == ANSI_CHARSET)
2923 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2924 else
2926 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2927 for (i = 0; i < efd.total; i++)
2929 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2930 if (*font_name)
2931 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2932 font_name, efd.lf[i].lfFaceName);
2935 ok(!ansi_charset,
2936 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2937 ok(symbol_charset > 0,
2938 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2939 ok(!russian_charset,
2940 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2943 ReleaseDC(0, hdc);
2946 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2948 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
2949 LOGFONTA *target = (LOGFONTA *)lParam;
2950 const DWORD valid_bits = 0x003f01ff;
2951 CHARSETINFO csi;
2952 DWORD fs;
2954 if (type != TRUETYPE_FONTTYPE) return TRUE;
2956 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
2957 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
2958 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
2959 *target = *lf;
2960 return FALSE;
2964 return TRUE;
2967 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
2969 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2971 if (type != TRUETYPE_FONTTYPE) return 1;
2973 if (efd->total < MAX_ENUM_FONTS)
2974 efd->lf[efd->total++] = *lf;
2975 else
2976 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2978 return 1;
2981 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
2983 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2985 if (type != TRUETYPE_FONTTYPE) return 1;
2987 if (efnd->total < MAX_ENUM_FONTS)
2988 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
2989 else
2990 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2992 return 1;
2995 static void test_EnumFontFamiliesEx_default_charset(void)
2997 struct enum_font_data efd;
2998 LOGFONTA target, enum_font;
2999 UINT acp;
3000 HDC hdc;
3001 CHARSETINFO csi;
3003 acp = GetACP();
3004 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3005 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3006 return;
3009 hdc = GetDC(0);
3010 memset(&enum_font, 0, sizeof(enum_font));
3011 enum_font.lfCharSet = csi.ciCharset;
3012 target.lfFaceName[0] = '\0';
3013 target.lfCharSet = csi.ciCharset;
3014 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3015 if (target.lfFaceName[0] == '\0') {
3016 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3017 return;
3019 if (acp == 874 || acp == 1255 || acp == 1256) {
3020 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3021 target.lfCharSet = ANSI_CHARSET;
3024 efd.total = 0;
3025 memset(&enum_font, 0, sizeof(enum_font));
3026 strcpy(enum_font.lfFaceName, target.lfFaceName);
3027 enum_font.lfCharSet = DEFAULT_CHARSET;
3028 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3029 ReleaseDC(0, hdc);
3031 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3032 if (efd.total < 2) {
3033 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3034 return;
3037 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3038 "(%s) got charset %d expected %d\n",
3039 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3041 return;
3044 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3046 HFONT hfont, hfont_prev;
3047 DWORD ret;
3048 GLYPHMETRICS gm1, gm2;
3049 LOGFONTA lf2 = *lf;
3050 WORD idx;
3052 if(!pGetGlyphIndicesA)
3053 return;
3055 /* negative widths are handled just as positive ones */
3056 lf2.lfWidth = -lf->lfWidth;
3058 SetLastError(0xdeadbeef);
3059 hfont = CreateFontIndirectA(lf);
3060 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3061 check_font("original", lf, hfont);
3063 hfont_prev = SelectObject(hdc, hfont);
3065 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3066 if (ret == GDI_ERROR || idx == 0xffff)
3068 SelectObject(hdc, hfont_prev);
3069 DeleteObject(hfont);
3070 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3071 return;
3074 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3075 memset(&gm1, 0xab, sizeof(gm1));
3076 SetLastError(0xdeadbeef);
3077 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3078 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3080 SelectObject(hdc, hfont_prev);
3081 DeleteObject(hfont);
3083 SetLastError(0xdeadbeef);
3084 hfont = CreateFontIndirectA(&lf2);
3085 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3086 check_font("negative width", &lf2, hfont);
3088 hfont_prev = SelectObject(hdc, hfont);
3090 memset(&gm2, 0xbb, sizeof(gm2));
3091 SetLastError(0xdeadbeef);
3092 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3093 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3095 SelectObject(hdc, hfont_prev);
3096 DeleteObject(hfont);
3098 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3099 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3100 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3101 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3102 gm1.gmCellIncX == gm2.gmCellIncX &&
3103 gm1.gmCellIncY == gm2.gmCellIncY,
3104 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3105 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3106 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3107 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3108 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3111 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3112 #include "pshpack2.h"
3113 typedef struct
3115 USHORT version;
3116 SHORT xAvgCharWidth;
3117 USHORT usWeightClass;
3118 USHORT usWidthClass;
3119 SHORT fsType;
3120 SHORT ySubscriptXSize;
3121 SHORT ySubscriptYSize;
3122 SHORT ySubscriptXOffset;
3123 SHORT ySubscriptYOffset;
3124 SHORT ySuperscriptXSize;
3125 SHORT ySuperscriptYSize;
3126 SHORT ySuperscriptXOffset;
3127 SHORT ySuperscriptYOffset;
3128 SHORT yStrikeoutSize;
3129 SHORT yStrikeoutPosition;
3130 SHORT sFamilyClass;
3131 PANOSE panose;
3132 ULONG ulUnicodeRange1;
3133 ULONG ulUnicodeRange2;
3134 ULONG ulUnicodeRange3;
3135 ULONG ulUnicodeRange4;
3136 CHAR achVendID[4];
3137 USHORT fsSelection;
3138 USHORT usFirstCharIndex;
3139 USHORT usLastCharIndex;
3140 /* According to the Apple spec, original version didn't have the below fields,
3141 * version numbers were taken from the OpenType spec.
3143 /* version 0 (TrueType 1.5) */
3144 USHORT sTypoAscender;
3145 USHORT sTypoDescender;
3146 USHORT sTypoLineGap;
3147 USHORT usWinAscent;
3148 USHORT usWinDescent;
3149 /* version 1 (TrueType 1.66) */
3150 ULONG ulCodePageRange1;
3151 ULONG ulCodePageRange2;
3152 /* version 2 (OpenType 1.2) */
3153 SHORT sxHeight;
3154 SHORT sCapHeight;
3155 USHORT usDefaultChar;
3156 USHORT usBreakChar;
3157 USHORT usMaxContext;
3158 } TT_OS2_V2;
3159 #include "poppack.h"
3161 typedef struct
3163 USHORT version;
3164 USHORT num_tables;
3165 } cmap_header;
3167 typedef struct
3169 USHORT plat_id;
3170 USHORT enc_id;
3171 ULONG offset;
3172 } cmap_encoding_record;
3174 typedef struct
3176 USHORT format;
3177 USHORT length;
3178 USHORT language;
3180 BYTE glyph_ids[256];
3181 } cmap_format_0;
3183 typedef struct
3185 USHORT format;
3186 USHORT length;
3187 USHORT language;
3189 USHORT seg_countx2;
3190 USHORT search_range;
3191 USHORT entry_selector;
3192 USHORT range_shift;
3194 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3195 /* Then follows:
3196 USHORT pad;
3197 USHORT start_count[seg_countx2 / 2];
3198 USHORT id_delta[seg_countx2 / 2];
3199 USHORT id_range_offset[seg_countx2 / 2];
3200 USHORT glyph_ids[];
3202 } cmap_format_4;
3204 typedef struct
3206 USHORT end_count;
3207 USHORT start_count;
3208 USHORT id_delta;
3209 USHORT id_range_offset;
3210 } cmap_format_4_seg;
3212 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
3214 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3215 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3216 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3217 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3218 os2->panose.bWeight, os2->panose.bProportion);
3221 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3223 int i;
3224 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3226 *first = 256;
3228 for(i = 0; i < 256; i++)
3230 if(cmap->glyph_ids[i] == 0) continue;
3231 *last = i;
3232 if(*first == 256) *first = i;
3234 if(*first == 256) return FALSE;
3235 return TRUE;
3238 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3240 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3241 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3242 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3243 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3244 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3247 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3249 int i;
3250 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3251 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3252 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
3254 *first = 0x10000;
3256 for(i = 0; i < seg_count; i++)
3258 DWORD code, index;
3259 cmap_format_4_seg seg;
3261 get_seg4(cmap, i, &seg);
3262 for(code = seg.start_count; code <= seg.end_count; code++)
3264 if(seg.id_range_offset == 0)
3265 index = (seg.id_delta + code) & 0xffff;
3266 else
3268 index = seg.id_range_offset / 2
3269 + code - seg.start_count
3270 + i - seg_count;
3272 /* some fonts have broken last segment */
3273 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
3274 index = GET_BE_WORD(glyph_ids[index]);
3275 else
3277 trace("segment %04x/%04x index %04x points to nowhere\n",
3278 seg.start_count, seg.end_count, index);
3279 index = 0;
3281 if(index) index += seg.id_delta;
3283 if(*first == 0x10000)
3284 *last = *first = code;
3285 else if(index)
3286 *last = code;
3290 if(*first == 0x10000) return FALSE;
3291 return TRUE;
3294 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3296 USHORT i;
3297 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3299 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3301 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3302 return (BYTE *)header + GET_BE_DWORD(record->offset);
3303 record++;
3305 return NULL;
3308 typedef enum
3310 cmap_none,
3311 cmap_ms_unicode,
3312 cmap_ms_symbol
3313 } cmap_type;
3315 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3317 LONG size, ret;
3318 cmap_header *header;
3319 void *cmap;
3320 BOOL r = FALSE;
3321 WORD format;
3323 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3324 ok(size != GDI_ERROR, "no cmap table found\n");
3325 if(size == GDI_ERROR) return FALSE;
3327 header = HeapAlloc(GetProcessHeap(), 0, size);
3328 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3329 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3330 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3332 cmap = get_cmap(header, 3, 1);
3333 if(cmap)
3334 *cmap_type = cmap_ms_unicode;
3335 else
3337 cmap = get_cmap(header, 3, 0);
3338 if(cmap) *cmap_type = cmap_ms_symbol;
3340 if(!cmap)
3342 *cmap_type = cmap_none;
3343 goto end;
3346 format = GET_BE_WORD(*(WORD *)cmap);
3347 switch(format)
3349 case 0:
3350 r = get_first_last_from_cmap0(cmap, first, last);
3351 break;
3352 case 4:
3353 r = get_first_last_from_cmap4(cmap, first, last, size);
3354 break;
3355 default:
3356 trace("unhandled cmap format %d\n", format);
3357 break;
3360 end:
3361 HeapFree(GetProcessHeap(), 0, header);
3362 return r;
3365 #define TT_PLATFORM_MICROSOFT 3
3366 #define TT_MS_ID_SYMBOL_CS 0
3367 #define TT_MS_ID_UNICODE_CS 1
3368 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3369 #define TT_NAME_ID_FONT_FAMILY 1
3370 #define TT_NAME_ID_FONT_SUBFAMILY 2
3371 #define TT_NAME_ID_UNIQUE_ID 3
3372 #define TT_NAME_ID_FULL_NAME 4
3374 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3376 struct sfnt_name_header
3378 USHORT format;
3379 USHORT number_of_record;
3380 USHORT storage_offset;
3381 } *header;
3382 struct sfnt_name
3384 USHORT platform_id;
3385 USHORT encoding_id;
3386 USHORT language_id;
3387 USHORT name_id;
3388 USHORT length;
3389 USHORT offset;
3390 } *entry;
3391 BOOL r = FALSE;
3392 LONG size, offset, length;
3393 LONG c, ret;
3394 WCHAR *name;
3395 BYTE *data;
3396 USHORT i;
3398 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3399 ok(size != GDI_ERROR, "no name table found\n");
3400 if(size == GDI_ERROR) return FALSE;
3402 data = HeapAlloc(GetProcessHeap(), 0, size);
3403 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3404 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3406 header = (void *)data;
3407 header->format = GET_BE_WORD(header->format);
3408 header->number_of_record = GET_BE_WORD(header->number_of_record);
3409 header->storage_offset = GET_BE_WORD(header->storage_offset);
3410 if (header->format != 0)
3412 trace("got format %u\n", header->format);
3413 goto out;
3415 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3417 trace("number records out of range: %d\n", header->number_of_record);
3418 goto out;
3420 if (header->storage_offset >= size)
3422 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3423 goto out;
3426 entry = (void *)&header[1];
3427 for (i = 0; i < header->number_of_record; i++)
3429 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
3430 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
3431 GET_BE_WORD(entry[i].language_id) != language_id ||
3432 GET_BE_WORD(entry[i].name_id) != name_id)
3434 continue;
3437 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
3438 length = GET_BE_WORD(entry[i].length);
3439 if (offset + length > size)
3441 trace("entry %d is out of range\n", i);
3442 break;
3444 if (length >= out_size)
3446 trace("buffer too small for entry %d\n", i);
3447 break;
3450 name = (WCHAR *)(data + offset);
3451 for (c = 0; c < length / 2; c++)
3452 out_buf[c] = GET_BE_WORD(name[c]);
3453 out_buf[c] = 0;
3455 r = TRUE;
3456 break;
3459 out:
3460 HeapFree(GetProcessHeap(), 0, data);
3461 return r;
3464 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3466 HDC hdc;
3467 HFONT hfont, hfont_old;
3468 TEXTMETRICA tmA;
3469 TT_OS2_V2 tt_os2;
3470 LONG size, ret;
3471 const char *font_name = lf->lfFaceName;
3472 DWORD cmap_first = 0, cmap_last = 0;
3473 UINT ascent, descent, cell_height;
3474 cmap_type cmap_type;
3475 BOOL sys_lang_non_english;
3477 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3478 hdc = GetDC(0);
3480 SetLastError(0xdeadbeef);
3481 hfont = CreateFontIndirectA(lf);
3482 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3484 hfont_old = SelectObject(hdc, hfont);
3486 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3487 if (size == GDI_ERROR)
3489 trace("OS/2 chunk was not found\n");
3490 goto end_of_test;
3492 if (size > sizeof(tt_os2))
3494 trace("got too large OS/2 chunk of size %u\n", size);
3495 size = sizeof(tt_os2);
3498 memset(&tt_os2, 0, sizeof(tt_os2));
3499 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3500 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3502 SetLastError(0xdeadbeef);
3503 ret = GetTextMetricsA(hdc, &tmA);
3504 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3506 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3508 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3510 else
3512 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3513 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3514 UINT os2_first_char, os2_last_char, default_char, break_char;
3515 USHORT version;
3516 TEXTMETRICW tmW;
3518 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3519 descent = GET_BE_WORD(tt_os2.usWinDescent);
3520 cell_height = ascent + descent;
3521 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3522 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3524 version = GET_BE_WORD(tt_os2.version);
3526 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3527 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3528 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3529 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3531 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3532 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3533 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3535 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3537 expect_first_W = 0;
3538 switch(GetACP())
3540 case 1257: /* Baltic */
3541 expect_last_W = 0xf8fd;
3542 break;
3543 default:
3544 expect_last_W = 0xf0ff;
3546 expect_break_W = 0x20;
3547 expect_default_W = expect_break_W - 1;
3548 expect_first_A = 0x1e;
3549 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3551 else
3553 expect_first_W = cmap_first;
3554 expect_last_W = min(cmap_last, os2_last_char);
3555 if(os2_first_char <= 1)
3556 expect_break_W = os2_first_char + 2;
3557 else if(os2_first_char > 0xff)
3558 expect_break_W = 0x20;
3559 else
3560 expect_break_W = os2_first_char;
3561 expect_default_W = expect_break_W - 1;
3562 expect_first_A = expect_default_W - 1;
3563 expect_last_A = min(expect_last_W, 0xff);
3565 expect_break_A = expect_break_W;
3566 expect_default_A = expect_default_W;
3568 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3569 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3570 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3571 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3572 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3573 else
3574 ok(tmA.tmFirstChar == expect_first_A ||
3575 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3576 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3577 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3578 ok(tmA.tmLastChar == expect_last_A ||
3579 tmA.tmLastChar == 0xff /* win9x */,
3580 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3581 else
3582 skip("tmLastChar is DBCS lead byte\n");
3583 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3584 font_name, tmA.tmBreakChar, expect_break_A);
3585 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3586 "A: tmDefaultChar for %s got %02x expected %02x\n",
3587 font_name, tmA.tmDefaultChar, expect_default_A);
3590 SetLastError(0xdeadbeef);
3591 ret = GetTextMetricsW(hdc, &tmW);
3592 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3593 "GetTextMetricsW error %u\n", GetLastError());
3594 if (ret)
3596 /* Wine uses the os2 first char */
3597 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3598 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3599 font_name, tmW.tmFirstChar, expect_first_W);
3600 else
3601 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3602 font_name, tmW.tmFirstChar, expect_first_W);
3604 /* Wine uses the os2 last char */
3605 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3606 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3607 font_name, tmW.tmLastChar, expect_last_W);
3608 else
3609 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3610 font_name, tmW.tmLastChar, expect_last_W);
3611 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3612 font_name, tmW.tmBreakChar, expect_break_W);
3613 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3614 "W: tmDefaultChar for %s got %02x expected %02x\n",
3615 font_name, tmW.tmDefaultChar, expect_default_W);
3617 /* Test the aspect ratio while we have tmW */
3618 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3619 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3620 tmW.tmDigitizedAspectX, ret);
3621 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3622 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3623 tmW.tmDigitizedAspectX, ret);
3627 /* test FF_ values */
3628 switch(tt_os2.panose.bFamilyType)
3630 case PAN_ANY:
3631 case PAN_NO_FIT:
3632 case PAN_FAMILY_TEXT_DISPLAY:
3633 case PAN_FAMILY_PICTORIAL:
3634 default:
3635 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3636 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3638 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3639 break;
3641 switch(tt_os2.panose.bSerifStyle)
3643 case PAN_ANY:
3644 case PAN_NO_FIT:
3645 default:
3646 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3647 break;
3649 case PAN_SERIF_COVE:
3650 case PAN_SERIF_OBTUSE_COVE:
3651 case PAN_SERIF_SQUARE_COVE:
3652 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3653 case PAN_SERIF_SQUARE:
3654 case PAN_SERIF_THIN:
3655 case PAN_SERIF_BONE:
3656 case PAN_SERIF_EXAGGERATED:
3657 case PAN_SERIF_TRIANGLE:
3658 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3659 break;
3661 case PAN_SERIF_NORMAL_SANS:
3662 case PAN_SERIF_OBTUSE_SANS:
3663 case PAN_SERIF_PERP_SANS:
3664 case PAN_SERIF_FLARED:
3665 case PAN_SERIF_ROUNDED:
3666 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3667 break;
3669 break;
3671 case PAN_FAMILY_SCRIPT:
3672 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3673 break;
3675 case PAN_FAMILY_DECORATIVE:
3676 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3677 break;
3680 test_negative_width(hdc, lf);
3682 end_of_test:
3683 SelectObject(hdc, hfont_old);
3684 DeleteObject(hfont);
3686 ReleaseDC(0, hdc);
3689 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3691 INT *enumed = (INT *)lParam;
3693 if (type == TRUETYPE_FONTTYPE)
3695 (*enumed)++;
3696 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
3698 return 1;
3701 static void test_GetTextMetrics(void)
3703 LOGFONTA lf;
3704 HDC hdc;
3705 INT enumed;
3707 /* Report only once */
3708 if(!pGetGlyphIndicesA)
3709 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3711 hdc = GetDC(0);
3713 memset(&lf, 0, sizeof(lf));
3714 lf.lfCharSet = DEFAULT_CHARSET;
3715 enumed = 0;
3716 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3717 trace("Tested metrics of %d truetype fonts\n", enumed);
3719 ReleaseDC(0, hdc);
3722 static void test_nonexistent_font(void)
3724 static const struct
3726 const char *name;
3727 int charset;
3728 } font_subst[] =
3730 { "Times New Roman Baltic", 186 },
3731 { "Times New Roman CE", 238 },
3732 { "Times New Roman CYR", 204 },
3733 { "Times New Roman Greek", 161 },
3734 { "Times New Roman TUR", 162 }
3736 LOGFONTA lf;
3737 HDC hdc;
3738 HFONT hfont;
3739 CHARSETINFO csi;
3740 INT cs, expected_cs, i;
3741 char buf[LF_FACESIZE];
3743 if (!is_truetype_font_installed("Arial") ||
3744 !is_truetype_font_installed("Times New Roman"))
3746 skip("Arial or Times New Roman not installed\n");
3747 return;
3750 expected_cs = GetACP();
3751 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3753 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3754 return;
3756 expected_cs = csi.ciCharset;
3757 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3759 hdc = GetDC(0);
3761 memset(&lf, 0, sizeof(lf));
3762 lf.lfHeight = 100;
3763 lf.lfWeight = FW_REGULAR;
3764 lf.lfCharSet = ANSI_CHARSET;
3765 lf.lfPitchAndFamily = FF_SWISS;
3766 strcpy(lf.lfFaceName, "Nonexistent font");
3767 hfont = CreateFontIndirectA(&lf);
3768 hfont = SelectObject(hdc, hfont);
3769 GetTextFaceA(hdc, sizeof(buf), buf);
3770 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3771 cs = GetTextCharset(hdc);
3772 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3773 DeleteObject(SelectObject(hdc, hfont));
3775 memset(&lf, 0, sizeof(lf));
3776 lf.lfHeight = -13;
3777 lf.lfWeight = FW_DONTCARE;
3778 strcpy(lf.lfFaceName, "Nonexistent font");
3779 hfont = CreateFontIndirectA(&lf);
3780 hfont = SelectObject(hdc, hfont);
3781 GetTextFaceA(hdc, sizeof(buf), buf);
3782 todo_wine /* Wine uses Arial for all substitutions */
3783 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3784 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3785 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3786 "Got %s\n", buf);
3787 cs = GetTextCharset(hdc);
3788 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3789 DeleteObject(SelectObject(hdc, hfont));
3791 memset(&lf, 0, sizeof(lf));
3792 lf.lfHeight = -13;
3793 lf.lfWeight = FW_REGULAR;
3794 strcpy(lf.lfFaceName, "Nonexistent font");
3795 hfont = CreateFontIndirectA(&lf);
3796 hfont = SelectObject(hdc, hfont);
3797 GetTextFaceA(hdc, sizeof(buf), buf);
3798 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3799 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3800 cs = GetTextCharset(hdc);
3801 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3802 DeleteObject(SelectObject(hdc, hfont));
3804 memset(&lf, 0, sizeof(lf));
3805 lf.lfHeight = -13;
3806 lf.lfWeight = FW_DONTCARE;
3807 strcpy(lf.lfFaceName, "Times New Roman");
3808 hfont = CreateFontIndirectA(&lf);
3809 hfont = SelectObject(hdc, hfont);
3810 GetTextFaceA(hdc, sizeof(buf), buf);
3811 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3812 cs = GetTextCharset(hdc);
3813 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3814 DeleteObject(SelectObject(hdc, hfont));
3816 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3818 memset(&lf, 0, sizeof(lf));
3819 lf.lfHeight = -13;
3820 lf.lfWeight = FW_REGULAR;
3821 strcpy(lf.lfFaceName, font_subst[i].name);
3822 hfont = CreateFontIndirectA(&lf);
3823 hfont = SelectObject(hdc, hfont);
3824 cs = GetTextCharset(hdc);
3825 if (font_subst[i].charset == expected_cs)
3827 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3828 GetTextFaceA(hdc, sizeof(buf), buf);
3829 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3831 else
3833 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3834 GetTextFaceA(hdc, sizeof(buf), buf);
3835 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3836 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3838 DeleteObject(SelectObject(hdc, hfont));
3840 memset(&lf, 0, sizeof(lf));
3841 lf.lfHeight = -13;
3842 lf.lfWeight = FW_DONTCARE;
3843 strcpy(lf.lfFaceName, font_subst[i].name);
3844 hfont = CreateFontIndirectA(&lf);
3845 hfont = SelectObject(hdc, hfont);
3846 GetTextFaceA(hdc, sizeof(buf), buf);
3847 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3848 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3849 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3850 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3851 "got %s for font %s\n", buf, font_subst[i].name);
3852 cs = GetTextCharset(hdc);
3853 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3854 DeleteObject(SelectObject(hdc, hfont));
3857 ReleaseDC(0, hdc);
3860 static void test_GdiRealizationInfo(void)
3862 HDC hdc;
3863 DWORD info[4];
3864 BOOL r;
3865 HFONT hfont, hfont_old;
3866 LOGFONTA lf;
3868 if(!pGdiRealizationInfo)
3870 win_skip("GdiRealizationInfo not available\n");
3871 return;
3874 hdc = GetDC(0);
3876 memset(info, 0xcc, sizeof(info));
3877 r = pGdiRealizationInfo(hdc, info);
3878 ok(r != 0, "ret 0\n");
3879 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3880 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3882 if (!is_truetype_font_installed("Arial"))
3884 skip("skipping GdiRealizationInfo with truetype font\n");
3885 goto end;
3888 memset(&lf, 0, sizeof(lf));
3889 strcpy(lf.lfFaceName, "Arial");
3890 lf.lfHeight = 20;
3891 lf.lfWeight = FW_NORMAL;
3892 hfont = CreateFontIndirectA(&lf);
3893 hfont_old = SelectObject(hdc, hfont);
3895 memset(info, 0xcc, sizeof(info));
3896 r = pGdiRealizationInfo(hdc, info);
3897 ok(r != 0, "ret 0\n");
3898 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3899 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3901 DeleteObject(SelectObject(hdc, hfont_old));
3903 end:
3904 ReleaseDC(0, hdc);
3907 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3908 the nul in the count of characters copied when the face name buffer is not
3909 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3910 always includes it. */
3911 static void test_GetTextFace(void)
3913 static const char faceA[] = "Tahoma";
3914 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3915 LOGFONTA fA = {0};
3916 LOGFONTW fW = {0};
3917 char bufA[LF_FACESIZE];
3918 WCHAR bufW[LF_FACESIZE];
3919 HFONT f, g;
3920 HDC dc;
3921 int n;
3923 if(!is_font_installed("Tahoma"))
3925 skip("Tahoma is not installed so skipping this test\n");
3926 return;
3929 /* 'A' case. */
3930 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3931 f = CreateFontIndirectA(&fA);
3932 ok(f != NULL, "CreateFontIndirectA failed\n");
3934 dc = GetDC(NULL);
3935 g = SelectObject(dc, f);
3936 n = GetTextFaceA(dc, sizeof bufA, bufA);
3937 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3938 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3940 /* Play with the count arg. */
3941 bufA[0] = 'x';
3942 n = GetTextFaceA(dc, 0, bufA);
3943 ok(n == 0, "GetTextFaceA returned %d\n", n);
3944 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3946 bufA[0] = 'x';
3947 n = GetTextFaceA(dc, 1, bufA);
3948 ok(n == 0, "GetTextFaceA returned %d\n", n);
3949 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3951 bufA[0] = 'x'; bufA[1] = 'y';
3952 n = GetTextFaceA(dc, 2, bufA);
3953 ok(n == 1, "GetTextFaceA returned %d\n", n);
3954 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3956 n = GetTextFaceA(dc, 0, NULL);
3957 ok(n == sizeof faceA ||
3958 broken(n == 0), /* win98, winMe */
3959 "GetTextFaceA returned %d\n", n);
3961 DeleteObject(SelectObject(dc, g));
3962 ReleaseDC(NULL, dc);
3964 /* 'W' case. */
3965 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3966 SetLastError(0xdeadbeef);
3967 f = CreateFontIndirectW(&fW);
3968 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3970 win_skip("CreateFontIndirectW is not implemented\n");
3971 return;
3973 ok(f != NULL, "CreateFontIndirectW failed\n");
3975 dc = GetDC(NULL);
3976 g = SelectObject(dc, f);
3977 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3978 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3979 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3981 /* Play with the count arg. */
3982 bufW[0] = 'x';
3983 n = GetTextFaceW(dc, 0, bufW);
3984 ok(n == 0, "GetTextFaceW returned %d\n", n);
3985 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3987 bufW[0] = 'x';
3988 n = GetTextFaceW(dc, 1, bufW);
3989 ok(n == 1, "GetTextFaceW returned %d\n", n);
3990 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3992 bufW[0] = 'x'; bufW[1] = 'y';
3993 n = GetTextFaceW(dc, 2, bufW);
3994 ok(n == 2, "GetTextFaceW returned %d\n", n);
3995 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3997 n = GetTextFaceW(dc, 0, NULL);
3998 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4000 DeleteObject(SelectObject(dc, g));
4001 ReleaseDC(NULL, dc);
4004 static void test_orientation(void)
4006 static const char test_str[11] = "Test String";
4007 HDC hdc;
4008 LOGFONTA lf;
4009 HFONT hfont, old_hfont;
4010 SIZE size;
4012 if (!is_truetype_font_installed("Arial"))
4014 skip("Arial is not installed\n");
4015 return;
4018 hdc = CreateCompatibleDC(0);
4019 memset(&lf, 0, sizeof(lf));
4020 lstrcpyA(lf.lfFaceName, "Arial");
4021 lf.lfHeight = 72;
4022 lf.lfOrientation = lf.lfEscapement = 900;
4023 hfont = create_font("orientation", &lf);
4024 old_hfont = SelectObject(hdc, hfont);
4025 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4026 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4027 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4028 SelectObject(hdc, old_hfont);
4029 DeleteObject(hfont);
4030 DeleteDC(hdc);
4033 static void test_oemcharset(void)
4035 HDC hdc;
4036 LOGFONTA lf, clf;
4037 HFONT hfont, old_hfont;
4038 int charset;
4040 hdc = CreateCompatibleDC(0);
4041 ZeroMemory(&lf, sizeof(lf));
4042 lf.lfHeight = 12;
4043 lf.lfCharSet = OEM_CHARSET;
4044 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4045 lstrcpyA(lf.lfFaceName, "Terminal");
4046 hfont = CreateFontIndirectA(&lf);
4047 old_hfont = SelectObject(hdc, hfont);
4048 charset = GetTextCharset(hdc);
4049 todo_wine
4050 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4051 hfont = SelectObject(hdc, old_hfont);
4052 GetObjectA(hfont, sizeof(clf), &clf);
4053 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4054 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4055 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4056 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4057 DeleteObject(hfont);
4058 DeleteDC(hdc);
4061 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4062 const TEXTMETRICA *lpntme,
4063 DWORD FontType, LPARAM lParam)
4065 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4066 CHARSETINFO csi;
4067 LOGFONTA lf = *lpelfe;
4068 HFONT hfont;
4069 DWORD found_subset;
4071 /* skip bitmap, proportional or vertical font */
4072 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4073 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4074 lf.lfFaceName[0] == '@')
4075 return 1;
4077 /* skip linked font */
4078 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4079 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4080 return 1;
4082 /* skip linked font, like SimSun-ExtB */
4083 switch (lpelfe->lfCharSet) {
4084 case SHIFTJIS_CHARSET:
4085 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4086 break;
4087 case GB2312_CHARSET:
4088 case CHINESEBIG5_CHARSET:
4089 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4090 break;
4091 case HANGEUL_CHARSET:
4092 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4093 break;
4094 default:
4095 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4096 break;
4098 if (!found_subset)
4099 return 1;
4101 /* test with an odd height */
4102 lf.lfHeight = -19;
4103 lf.lfWidth = 0;
4104 hfont = CreateFontIndirectA(&lf);
4105 if (hfont)
4107 *(HFONT *)lParam = hfont;
4108 return 0;
4110 return 1;
4113 static void test_GetGlyphOutline(void)
4115 HDC hdc;
4116 GLYPHMETRICS gm, gm2;
4117 LOGFONTA lf;
4118 HFONT hfont, old_hfont;
4119 INT ret, ret2;
4120 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4121 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4122 static const struct
4124 UINT cs;
4125 UINT a;
4126 UINT w;
4127 } c[] =
4129 {ANSI_CHARSET, 0x30, 0x30},
4130 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4131 {HANGEUL_CHARSET, 0x8141, 0xac02},
4132 {GB2312_CHARSET, 0x8141, 0x4e04},
4133 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4135 UINT i;
4137 if (!is_truetype_font_installed("Tahoma"))
4139 skip("Tahoma is not installed\n");
4140 return;
4143 hdc = CreateCompatibleDC(0);
4144 memset(&lf, 0, sizeof(lf));
4145 lf.lfHeight = 72;
4146 lstrcpyA(lf.lfFaceName, "Tahoma");
4147 SetLastError(0xdeadbeef);
4148 hfont = CreateFontIndirectA(&lf);
4149 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4150 old_hfont = SelectObject(hdc, hfont);
4152 memset(&gm, 0, sizeof(gm));
4153 SetLastError(0xdeadbeef);
4154 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4155 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4157 memset(&gm, 0, sizeof(gm));
4158 SetLastError(0xdeadbeef);
4159 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4160 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4161 ok(GetLastError() == 0xdeadbeef ||
4162 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4163 "expected 0xdeadbeef, got %u\n", GetLastError());
4165 memset(&gm, 0, sizeof(gm));
4166 SetLastError(0xdeadbeef);
4167 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4168 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4169 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4171 memset(&gm, 0, sizeof(gm));
4172 SetLastError(0xdeadbeef);
4173 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4174 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4176 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4177 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4180 /* test for needed buffer size request on space char */
4181 memset(&gm, 0, sizeof(gm));
4182 SetLastError(0xdeadbeef);
4183 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4184 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4185 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4187 /* requesting buffer size for space char + error */
4188 memset(&gm, 0, sizeof(gm));
4189 SetLastError(0xdeadbeef);
4190 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4191 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4193 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4194 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4197 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4199 DWORD dummy;
4201 memset(&gm, 0xab, sizeof(gm));
4202 SetLastError(0xdeadbeef);
4203 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4204 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4206 if (fmt[i] == GGO_METRICS)
4207 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4208 else
4209 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4210 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4211 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4214 memset(&gm, 0xab, sizeof(gm));
4215 SetLastError(0xdeadbeef);
4216 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4217 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4219 if (fmt[i] == GGO_METRICS)
4220 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4221 else
4222 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4223 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4224 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4227 memset(&gm, 0xab, sizeof(gm));
4228 SetLastError(0xdeadbeef);
4229 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4230 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4232 if (fmt[i] == GGO_METRICS)
4233 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4234 else
4235 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4236 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4237 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4240 memset(&gm, 0xab, sizeof(gm));
4241 SetLastError(0xdeadbeef);
4242 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4243 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4245 if (fmt[i] == GGO_METRICS) {
4246 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4247 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4248 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4250 else
4252 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4253 memset(&gm2, 0xab, sizeof(gm2));
4254 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4255 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4260 SelectObject(hdc, old_hfont);
4261 DeleteObject(hfont);
4263 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4265 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4266 TEXTMETRICA tm;
4268 lf.lfFaceName[0] = '\0';
4269 lf.lfCharSet = c[i].cs;
4270 lf.lfPitchAndFamily = 0;
4271 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4273 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4274 continue;
4277 old_hfont = SelectObject(hdc, hfont);
4279 /* expected to ignore superfluous bytes (sigle-byte character) */
4280 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4281 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4282 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4284 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4285 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4286 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4288 /* expected to ignore superfluous bytes (double-byte character) */
4289 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4290 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4291 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4292 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4294 /* expected to match wide-char version results */
4295 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4296 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4298 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4300 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4301 continue;
4303 DeleteObject(SelectObject(hdc, hfont));
4304 if (c[i].a <= 0xff)
4306 DeleteObject(SelectObject(hdc, old_hfont));
4307 continue;
4310 ret = GetObjectA(hfont, sizeof lf, &lf);
4311 ok(ret > 0, "GetObject error %u\n", GetLastError());
4313 ret = GetTextMetricsA(hdc, &tm);
4314 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4315 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4316 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4317 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4318 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4319 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4320 "expected %d, got %d (%s:%d)\n",
4321 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4323 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4324 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4325 ok(gm2.gmCellIncY == -lf.lfHeight,
4326 "expected %d, got %d (%s:%d)\n",
4327 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4329 lf.lfItalic = TRUE;
4330 hfont = CreateFontIndirectA(&lf);
4331 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4332 DeleteObject(SelectObject(hdc, hfont));
4333 ret = GetTextMetricsA(hdc, &tm);
4334 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4335 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4336 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4337 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4338 "expected %d, got %d (%s:%d)\n",
4339 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4341 lf.lfItalic = FALSE;
4342 lf.lfEscapement = lf.lfOrientation = 2700;
4343 hfont = CreateFontIndirectA(&lf);
4344 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4345 DeleteObject(SelectObject(hdc, hfont));
4346 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4347 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4348 ok(gm2.gmCellIncY == -lf.lfHeight,
4349 "expected %d, got %d (%s:%d)\n",
4350 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4352 hfont = SelectObject(hdc, old_hfont);
4353 DeleteObject(hfont);
4356 DeleteDC(hdc);
4359 /* bug #9995: there is a limit to the character width that can be specified */
4360 static void test_GetTextMetrics2(const char *fontname, int font_height)
4362 HFONT of, hf;
4363 HDC hdc;
4364 TEXTMETRICA tm;
4365 BOOL ret;
4366 int ave_width, height, width, ratio, scale;
4368 if (!is_truetype_font_installed( fontname)) {
4369 skip("%s is not installed\n", fontname);
4370 return;
4372 hdc = CreateCompatibleDC(0);
4373 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4374 /* select width = 0 */
4375 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4376 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4377 DEFAULT_QUALITY, VARIABLE_PITCH,
4378 fontname);
4379 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4380 of = SelectObject( hdc, hf);
4381 ret = GetTextMetricsA( hdc, &tm);
4382 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4383 height = tm.tmHeight;
4384 ave_width = tm.tmAveCharWidth;
4385 SelectObject( hdc, of);
4386 DeleteObject( hf);
4388 trace("height %d, ave width %d\n", height, ave_width);
4390 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4392 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4393 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4394 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4395 ok(hf != 0, "CreateFont failed\n");
4396 of = SelectObject(hdc, hf);
4397 ret = GetTextMetricsA(hdc, &tm);
4398 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4399 SelectObject(hdc, of);
4400 DeleteObject(hf);
4402 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4403 break;
4406 DeleteDC(hdc);
4408 ratio = width / height;
4409 scale = width / ave_width;
4411 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4412 width, height, ratio, width, ave_width, scale);
4414 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4417 static void test_CreateFontIndirect(void)
4419 LOGFONTA lf, getobj_lf;
4420 int ret, i;
4421 HFONT hfont;
4422 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4424 memset(&lf, 0, sizeof(lf));
4425 lf.lfCharSet = ANSI_CHARSET;
4426 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4427 lf.lfHeight = 16;
4428 lf.lfWidth = 16;
4429 lf.lfQuality = DEFAULT_QUALITY;
4430 lf.lfItalic = FALSE;
4431 lf.lfWeight = FW_DONTCARE;
4433 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4435 lstrcpyA(lf.lfFaceName, TestName[i]);
4436 hfont = CreateFontIndirectA(&lf);
4437 ok(hfont != 0, "CreateFontIndirectA failed\n");
4438 SetLastError(0xdeadbeef);
4439 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4440 ok(ret, "GetObject failed: %d\n", GetLastError());
4441 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4442 ok(lf.lfWeight == getobj_lf.lfWeight ||
4443 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4444 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4445 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4446 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4447 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4448 DeleteObject(hfont);
4452 static void test_CreateFontIndirectEx(void)
4454 ENUMLOGFONTEXDVA lfex;
4455 HFONT hfont;
4457 if (!pCreateFontIndirectExA)
4459 win_skip("CreateFontIndirectExA is not available\n");
4460 return;
4463 if (!is_truetype_font_installed("Arial"))
4465 skip("Arial is not installed\n");
4466 return;
4469 SetLastError(0xdeadbeef);
4470 hfont = pCreateFontIndirectExA(NULL);
4471 ok(hfont == NULL, "got %p\n", hfont);
4472 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4474 memset(&lfex, 0, sizeof(lfex));
4475 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
4476 hfont = pCreateFontIndirectExA(&lfex);
4477 ok(hfont != 0, "CreateFontIndirectEx failed\n");
4478 if (hfont)
4479 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
4480 DeleteObject(hfont);
4483 static void free_font(void *font)
4485 UnmapViewOfFile(font);
4488 static void *load_font(const char *font_name, DWORD *font_size)
4490 char file_name[MAX_PATH];
4491 HANDLE file, mapping;
4492 void *font;
4494 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
4495 strcat(file_name, "\\fonts\\");
4496 strcat(file_name, font_name);
4498 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4499 if (file == INVALID_HANDLE_VALUE) return NULL;
4501 *font_size = GetFileSize(file, NULL);
4503 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4504 if (!mapping)
4506 CloseHandle(file);
4507 return NULL;
4510 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4512 CloseHandle(file);
4513 CloseHandle(mapping);
4514 return font;
4517 static void test_AddFontMemResource(void)
4519 void *font;
4520 DWORD font_size, num_fonts;
4521 HANDLE ret;
4522 BOOL bRet;
4524 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4526 win_skip("AddFontMemResourceEx is not available on this platform\n");
4527 return;
4530 font = load_font("sserife.fon", &font_size);
4531 if (!font)
4533 skip("Unable to locate and load font sserife.fon\n");
4534 return;
4537 SetLastError(0xdeadbeef);
4538 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4539 ok(!ret, "AddFontMemResourceEx should fail\n");
4540 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4541 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4542 GetLastError());
4544 SetLastError(0xdeadbeef);
4545 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4546 ok(!ret, "AddFontMemResourceEx should fail\n");
4547 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4548 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4549 GetLastError());
4551 SetLastError(0xdeadbeef);
4552 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4553 ok(!ret, "AddFontMemResourceEx should fail\n");
4554 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4555 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4556 GetLastError());
4558 SetLastError(0xdeadbeef);
4559 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4560 ok(!ret, "AddFontMemResourceEx should fail\n");
4561 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4562 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4563 GetLastError());
4565 SetLastError(0xdeadbeef);
4566 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4567 ok(!ret, "AddFontMemResourceEx should fail\n");
4568 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4569 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4570 GetLastError());
4572 SetLastError(0xdeadbeef);
4573 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4574 ok(!ret, "AddFontMemResourceEx should fail\n");
4575 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4576 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4577 GetLastError());
4579 num_fonts = 0xdeadbeef;
4580 SetLastError(0xdeadbeef);
4581 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4582 ok(!ret, "AddFontMemResourceEx should fail\n");
4583 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4584 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4585 GetLastError());
4586 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4588 if (0) /* hangs under windows 2000 */
4590 num_fonts = 0xdeadbeef;
4591 SetLastError(0xdeadbeef);
4592 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4593 ok(!ret, "AddFontMemResourceEx should fail\n");
4594 ok(GetLastError() == 0xdeadbeef,
4595 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4596 GetLastError());
4597 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4600 num_fonts = 0xdeadbeef;
4601 SetLastError(0xdeadbeef);
4602 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4603 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4604 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4605 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4607 free_font(font);
4609 SetLastError(0xdeadbeef);
4610 bRet = pRemoveFontMemResourceEx(ret);
4611 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4613 /* test invalid pointer to number of loaded fonts */
4614 font = load_font("sserife.fon", &font_size);
4615 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4617 SetLastError(0xdeadbeef);
4618 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4619 ok(!ret, "AddFontMemResourceEx should fail\n");
4620 ok(GetLastError() == 0xdeadbeef,
4621 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4622 GetLastError());
4624 SetLastError(0xdeadbeef);
4625 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4626 ok(!ret, "AddFontMemResourceEx should fail\n");
4627 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4628 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4629 GetLastError());
4631 free_font(font);
4634 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4636 LOGFONTA *lf;
4638 if (type != TRUETYPE_FONTTYPE) return 1;
4640 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4642 lf = (LOGFONTA *)lparam;
4643 *lf = *elf;
4644 return 0;
4647 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4649 int ret;
4650 LOGFONTA *lf;
4652 if (type != TRUETYPE_FONTTYPE) return 1;
4654 lf = (LOGFONTA *)lparam;
4655 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
4656 if(ret == 0)
4658 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4659 *lf = *elf;
4660 return 0;
4662 return 1;
4665 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4667 return lparam;
4670 static void test_EnumFonts(void)
4672 int ret;
4673 LOGFONTA lf;
4674 HDC hdc;
4676 if (!is_truetype_font_installed("Arial"))
4678 skip("Arial is not installed\n");
4679 return;
4682 /* Windows uses localized font face names, so Arial Bold won't be found */
4683 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4685 skip("User locale is not English, skipping the test\n");
4686 return;
4689 hdc = CreateCompatibleDC(0);
4691 /* check that the enumproc's retval is returned */
4692 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4693 ok(ret == 0xcafe, "got %08x\n", ret);
4695 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4696 ok(!ret, "font Arial is not enumerated\n");
4697 ret = strcmp(lf.lfFaceName, "Arial");
4698 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4699 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4701 strcpy(lf.lfFaceName, "Arial");
4702 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4703 ok(!ret, "font Arial is not enumerated\n");
4704 ret = strcmp(lf.lfFaceName, "Arial");
4705 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4706 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4708 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4709 ok(!ret, "font Arial Bold is not enumerated\n");
4710 ret = strcmp(lf.lfFaceName, "Arial");
4711 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4712 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4714 strcpy(lf.lfFaceName, "Arial Bold");
4715 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4716 ok(ret, "font Arial Bold should not be enumerated\n");
4718 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4719 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4720 ret = strcmp(lf.lfFaceName, "Arial");
4721 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4722 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4724 strcpy(lf.lfFaceName, "Arial Bold Italic");
4725 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4726 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4728 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4729 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4731 strcpy(lf.lfFaceName, "Arial Italic Bold");
4732 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4733 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4735 DeleteDC(hdc);
4738 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4740 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
4741 const char *fullname = (const char *)lParam;
4743 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4745 return 1;
4748 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4750 HDC hdc = GetDC(0);
4751 BOOL ret = FALSE;
4753 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4754 ret = TRUE;
4756 ReleaseDC(0, hdc);
4757 return ret;
4760 static void test_fullname(void)
4762 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4763 WCHAR bufW[LF_FULLFACESIZE];
4764 char bufA[LF_FULLFACESIZE];
4765 HFONT hfont, of;
4766 LOGFONTA lf;
4767 HDC hdc;
4768 int i;
4769 DWORD ret;
4771 hdc = CreateCompatibleDC(0);
4772 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4774 memset(&lf, 0, sizeof(lf));
4775 lf.lfCharSet = ANSI_CHARSET;
4776 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4777 lf.lfHeight = 16;
4778 lf.lfWidth = 16;
4779 lf.lfQuality = DEFAULT_QUALITY;
4780 lf.lfItalic = FALSE;
4781 lf.lfWeight = FW_DONTCARE;
4783 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4785 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4787 skip("%s is not installed\n", TestName[i]);
4788 continue;
4791 lstrcpyA(lf.lfFaceName, TestName[i]);
4792 hfont = CreateFontIndirectA(&lf);
4793 ok(hfont != 0, "CreateFontIndirectA failed\n");
4795 of = SelectObject(hdc, hfont);
4796 bufW[0] = 0;
4797 bufA[0] = 0;
4798 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4799 ok(ret, "face full name could not be read\n");
4800 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4801 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4802 SelectObject(hdc, of);
4803 DeleteObject(hfont);
4805 DeleteDC(hdc);
4808 static WCHAR *prepend_at(WCHAR *family)
4810 if (!family)
4811 return NULL;
4813 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4814 family[0] = '@';
4815 return family;
4818 static void test_fullname2_helper(const char *Family)
4820 char *FamilyName, *FaceName, *StyleName, *otmStr;
4821 struct enum_fullname_data efnd;
4822 WCHAR *bufW;
4823 char *bufA;
4824 HFONT hfont, of;
4825 LOGFONTA lf;
4826 HDC hdc;
4827 int i;
4828 DWORD otm_size, ret, buf_size;
4829 OUTLINETEXTMETRICA *otm;
4830 BOOL want_vertical, get_vertical;
4831 want_vertical = ( Family[0] == '@' );
4833 hdc = CreateCompatibleDC(0);
4834 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4836 memset(&lf, 0, sizeof(lf));
4837 lf.lfCharSet = DEFAULT_CHARSET;
4838 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4839 lf.lfHeight = 16;
4840 lf.lfWidth = 16;
4841 lf.lfQuality = DEFAULT_QUALITY;
4842 lf.lfItalic = FALSE;
4843 lf.lfWeight = FW_DONTCARE;
4844 strcpy(lf.lfFaceName, Family);
4845 efnd.total = 0;
4846 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4847 if (efnd.total == 0)
4848 skip("%s is not installed\n", lf.lfFaceName);
4850 for (i = 0; i < efnd.total; i++)
4852 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4853 FaceName = (char *)efnd.elf[i].elfFullName;
4854 StyleName = (char *)efnd.elf[i].elfStyle;
4856 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4858 get_vertical = ( FamilyName[0] == '@' );
4859 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4861 lstrcpyA(lf.lfFaceName, FaceName);
4862 hfont = CreateFontIndirectA(&lf);
4863 ok(hfont != 0, "CreateFontIndirectA failed\n");
4865 of = SelectObject(hdc, hfont);
4866 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4867 ok(buf_size != GDI_ERROR, "no name table found\n");
4868 if (buf_size == GDI_ERROR) continue;
4870 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4871 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4873 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4874 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4875 memset(otm, 0, otm_size);
4876 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
4877 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4878 if (ret == 0) continue;
4880 bufW[0] = 0;
4881 bufA[0] = 0;
4882 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4883 if (!ret)
4885 trace("no localized FONT_FAMILY found.\n");
4886 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4888 ok(ret, "FAMILY (family name) could not be read\n");
4889 if (want_vertical) bufW = prepend_at(bufW);
4890 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4891 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4892 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4893 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4895 bufW[0] = 0;
4896 bufA[0] = 0;
4897 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4898 if (!ret)
4900 trace("no localized FULL_NAME found.\n");
4901 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4903 ok(ret, "FULL_NAME (face name) could not be read\n");
4904 if (want_vertical) bufW = prepend_at(bufW);
4905 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4906 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4907 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4908 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4910 bufW[0] = 0;
4911 bufA[0] = 0;
4912 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4913 if (!ret)
4915 trace("no localized FONT_SUBFAMILY found.\n");
4916 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4918 ok(ret, "SUBFAMILY (style name) could not be read\n");
4919 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4920 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4921 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4922 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4924 bufW[0] = 0;
4925 bufA[0] = 0;
4926 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4927 if (!ret)
4929 trace("no localized UNIQUE_ID found.\n");
4930 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4932 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4933 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4934 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4935 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4937 SelectObject(hdc, of);
4938 DeleteObject(hfont);
4940 HeapFree(GetProcessHeap(), 0, otm);
4941 HeapFree(GetProcessHeap(), 0, bufW);
4942 HeapFree(GetProcessHeap(), 0, bufA);
4944 DeleteDC(hdc);
4947 static void test_fullname2(void)
4949 test_fullname2_helper("Arial");
4950 test_fullname2_helper("DejaVu Sans");
4951 test_fullname2_helper("Lucida Sans");
4952 test_fullname2_helper("Tahoma");
4953 test_fullname2_helper("Webdings");
4954 test_fullname2_helper("Wingdings");
4955 test_fullname2_helper("SimSun");
4956 test_fullname2_helper("NSimSun");
4957 test_fullname2_helper("MingLiu");
4958 test_fullname2_helper("PMingLiu");
4959 test_fullname2_helper("WenQuanYi Micro Hei");
4960 test_fullname2_helper("MS UI Gothic");
4961 test_fullname2_helper("Ume UI Gothic");
4962 test_fullname2_helper("MS Gothic");
4963 test_fullname2_helper("Ume Gothic");
4964 test_fullname2_helper("MS PGothic");
4965 test_fullname2_helper("Ume P Gothic");
4966 test_fullname2_helper("Gulim");
4967 test_fullname2_helper("Batang");
4968 test_fullname2_helper("UnBatang");
4969 test_fullname2_helper("UnDotum");
4970 test_fullname2_helper("@SimSun");
4971 test_fullname2_helper("@NSimSun");
4972 test_fullname2_helper("@MingLiu");
4973 test_fullname2_helper("@PMingLiu");
4974 test_fullname2_helper("@WenQuanYi Micro Hei");
4975 test_fullname2_helper("@MS UI Gothic");
4976 test_fullname2_helper("@Ume UI Gothic");
4977 test_fullname2_helper("@MS Gothic");
4978 test_fullname2_helper("@Ume Gothic");
4979 test_fullname2_helper("@MS PGothic");
4980 test_fullname2_helper("@Ume P Gothic");
4981 test_fullname2_helper("@Gulim");
4982 test_fullname2_helper("@Batang");
4983 test_fullname2_helper("@UnBatang");
4984 test_fullname2_helper("@UnDotum");
4988 static void test_GetGlyphOutline_empty_contour(void)
4990 HDC hdc;
4991 LOGFONTA lf;
4992 HFONT hfont, hfont_prev;
4993 TTPOLYGONHEADER *header;
4994 GLYPHMETRICS gm;
4995 char buf[1024];
4996 DWORD ret;
4998 memset(&lf, 0, sizeof(lf));
4999 lf.lfHeight = 72;
5000 lstrcpyA(lf.lfFaceName, "wine_test");
5002 hfont = CreateFontIndirectA(&lf);
5003 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5005 hdc = GetDC(NULL);
5007 hfont_prev = SelectObject(hdc, hfont);
5008 ok(hfont_prev != NULL, "SelectObject failed\n");
5010 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5011 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5013 header = (TTPOLYGONHEADER*)buf;
5014 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5015 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5016 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5017 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5018 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5019 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5020 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5021 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5023 SelectObject(hdc, hfont_prev);
5024 DeleteObject(hfont);
5025 ReleaseDC(NULL, hdc);
5028 static void test_GetGlyphOutline_metric_clipping(void)
5030 HDC hdc;
5031 LOGFONTA lf;
5032 HFONT hfont, hfont_prev;
5033 GLYPHMETRICS gm;
5034 TEXTMETRICA tm;
5035 DWORD ret;
5037 memset(&lf, 0, sizeof(lf));
5038 lf.lfHeight = 72;
5039 lstrcpyA(lf.lfFaceName, "wine_test");
5041 SetLastError(0xdeadbeef);
5042 hfont = CreateFontIndirectA(&lf);
5043 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5045 hdc = GetDC(NULL);
5047 hfont_prev = SelectObject(hdc, hfont);
5048 ok(hfont_prev != NULL, "SelectObject failed\n");
5050 SetLastError(0xdeadbeef);
5051 ret = GetTextMetricsA(hdc, &tm);
5052 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5054 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5055 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5056 "Glyph top(%d) exceeds ascent(%d)\n",
5057 gm.gmptGlyphOrigin.y, tm.tmAscent);
5058 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5059 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5060 "Glyph bottom(%d) exceeds descent(%d)\n",
5061 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5063 SelectObject(hdc, hfont_prev);
5064 DeleteObject(hfont);
5065 ReleaseDC(NULL, hdc);
5068 static void test_CreateScalableFontResource(void)
5070 char ttf_name[MAX_PATH];
5071 char tmp_path[MAX_PATH];
5072 char fot_name[MAX_PATH];
5073 char *file_part;
5074 DWORD ret;
5075 int i;
5077 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5079 win_skip("AddFontResourceExA is not available on this platform\n");
5080 return;
5083 if (!write_ttf_file("wine_test.ttf", ttf_name))
5085 skip("Failed to create ttf file for testing\n");
5086 return;
5089 trace("created %s\n", ttf_name);
5091 ret = is_truetype_font_installed("wine_test");
5092 ok(!ret, "font wine_test should not be enumerated\n");
5094 ret = GetTempPathA(MAX_PATH, tmp_path);
5095 ok(ret, "GetTempPath() error %d\n", GetLastError());
5096 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5097 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5099 ret = GetFileAttributesA(fot_name);
5100 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5102 SetLastError(0xdeadbeef);
5103 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5104 ok(!ret, "CreateScalableFontResource() should fail\n");
5105 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5107 SetLastError(0xdeadbeef);
5108 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5109 ok(!ret, "CreateScalableFontResource() should fail\n");
5110 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5112 file_part = strrchr(ttf_name, '\\');
5113 SetLastError(0xdeadbeef);
5114 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5115 ok(!ret, "CreateScalableFontResource() should fail\n");
5116 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5118 SetLastError(0xdeadbeef);
5119 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5120 ok(!ret, "CreateScalableFontResource() should fail\n");
5121 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5123 SetLastError(0xdeadbeef);
5124 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5125 ok(!ret, "CreateScalableFontResource() should fail\n");
5126 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5128 ret = DeleteFileA(fot_name);
5129 ok(ret, "DeleteFile() error %d\n", GetLastError());
5131 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5132 ok(!ret, "RemoveFontResourceEx() should fail\n");
5134 /* test public font resource */
5135 SetLastError(0xdeadbeef);
5136 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5137 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5139 ret = is_truetype_font_installed("wine_test");
5140 ok(!ret, "font wine_test should not be enumerated\n");
5142 SetLastError(0xdeadbeef);
5143 ret = pAddFontResourceExA(fot_name, 0, 0);
5144 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5146 ret = is_truetype_font_installed("wine_test");
5147 ok(ret, "font wine_test should be enumerated\n");
5149 test_GetGlyphOutline_empty_contour();
5150 test_GetGlyphOutline_metric_clipping();
5152 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5153 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5155 SetLastError(0xdeadbeef);
5156 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5157 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5159 ret = is_truetype_font_installed("wine_test");
5160 ok(!ret, "font wine_test should not be enumerated\n");
5162 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5163 ok(!ret, "RemoveFontResourceEx() should fail\n");
5165 /* test refcounting */
5166 for (i = 0; i < 5; i++)
5168 SetLastError(0xdeadbeef);
5169 ret = pAddFontResourceExA(fot_name, 0, 0);
5170 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5172 for (i = 0; i < 5; i++)
5174 SetLastError(0xdeadbeef);
5175 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5176 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5178 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5179 ok(!ret, "RemoveFontResourceEx() should fail\n");
5181 DeleteFileA(fot_name);
5183 /* test hidden font resource */
5184 SetLastError(0xdeadbeef);
5185 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5186 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5188 ret = is_truetype_font_installed("wine_test");
5189 ok(!ret, "font wine_test should not be enumerated\n");
5191 SetLastError(0xdeadbeef);
5192 ret = pAddFontResourceExA(fot_name, 0, 0);
5193 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5195 ret = is_truetype_font_installed("wine_test");
5196 todo_wine
5197 ok(!ret, "font wine_test should not be enumerated\n");
5199 /* XP allows removing a private font added with 0 flags */
5200 SetLastError(0xdeadbeef);
5201 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5202 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5204 ret = is_truetype_font_installed("wine_test");
5205 ok(!ret, "font wine_test should not be enumerated\n");
5207 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5208 ok(!ret, "RemoveFontResourceEx() should fail\n");
5210 DeleteFileA(fot_name);
5211 DeleteFileA(ttf_name);
5214 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5216 LOGFONTA lf;
5217 HFONT hfont, hfont_prev;
5218 HDC hdc;
5219 char facename[100];
5220 DWORD ret;
5221 static const WCHAR str[] = { 0x2025 };
5223 *installed = is_truetype_font_installed(name);
5225 lf.lfHeight = -18;
5226 lf.lfWidth = 0;
5227 lf.lfEscapement = 0;
5228 lf.lfOrientation = 0;
5229 lf.lfWeight = FW_DONTCARE;
5230 lf.lfItalic = 0;
5231 lf.lfUnderline = 0;
5232 lf.lfStrikeOut = 0;
5233 lf.lfCharSet = DEFAULT_CHARSET;
5234 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5235 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5236 lf.lfQuality = DEFAULT_QUALITY;
5237 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5238 strcpy(lf.lfFaceName, name);
5240 hfont = CreateFontIndirectA(&lf);
5241 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5243 hdc = GetDC(NULL);
5245 hfont_prev = SelectObject(hdc, hfont);
5246 ok(hfont_prev != NULL, "SelectObject failed\n");
5248 ret = GetTextFaceA(hdc, sizeof facename, facename);
5249 ok(ret, "GetTextFaceA failed\n");
5250 *selected = !strcmp(facename, name);
5252 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5253 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5254 if (!*selected)
5255 memset(gm, 0, sizeof *gm);
5257 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5258 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5260 SelectObject(hdc, hfont_prev);
5261 DeleteObject(hfont);
5262 ReleaseDC(NULL, hdc);
5265 static void check_vertical_metrics(const char *face)
5267 LOGFONTA lf;
5268 HFONT hfont, hfont_prev;
5269 HDC hdc;
5270 DWORD ret;
5271 GLYPHMETRICS rgm, vgm;
5272 const UINT code = 0x5EAD, height = 1000;
5273 WORD idx;
5274 ABC abc;
5275 OUTLINETEXTMETRICA otm;
5276 USHORT numOfLongVerMetrics;
5278 hdc = GetDC(NULL);
5280 memset(&lf, 0, sizeof(lf));
5281 strcpy(lf.lfFaceName, face);
5282 lf.lfHeight = -height;
5283 lf.lfCharSet = DEFAULT_CHARSET;
5284 lf.lfEscapement = lf.lfOrientation = 900;
5285 hfont = CreateFontIndirectA(&lf);
5286 hfont_prev = SelectObject(hdc, hfont);
5287 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5288 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5289 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5290 ok(ret, "GetCharABCWidthsW failed\n");
5291 DeleteObject(SelectObject(hdc, hfont_prev));
5293 memset(&lf, 0, sizeof(lf));
5294 strcpy(lf.lfFaceName, "@");
5295 strcat(lf.lfFaceName, face);
5296 lf.lfHeight = -height;
5297 lf.lfCharSet = DEFAULT_CHARSET;
5298 hfont = CreateFontIndirectA(&lf);
5299 hfont_prev = SelectObject(hdc, hfont);
5300 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5301 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5303 memset(&otm, 0, sizeof(otm));
5304 otm.otmSize = sizeof(otm);
5305 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5306 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5308 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5309 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5310 int offset;
5311 SHORT topSideBearing;
5313 if (!pGetGlyphIndicesW) {
5314 win_skip("GetGlyphIndices is not available on this platform\n");
5316 else {
5317 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5318 ok(ret != 0, "GetGlyphIndicesW failed\n");
5319 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5320 if (numOfLongVerMetrics > idx)
5321 offset = idx * 2 + 1;
5322 else
5323 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5324 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5325 &topSideBearing, sizeof(SHORT));
5326 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5327 topSideBearing = GET_BE_WORD(topSideBearing);
5328 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5329 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5330 "expected %d, got %d\n",
5331 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5334 else
5336 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5337 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5338 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5341 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
5342 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
5343 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5344 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
5346 DeleteObject(SelectObject(hdc, hfont_prev));
5347 ReleaseDC(NULL, hdc);
5350 static void test_vertical_font(void)
5352 char ttf_name[MAX_PATH];
5353 int num, i;
5354 BOOL ret, installed, selected;
5355 GLYPHMETRICS gm;
5356 WORD hgi, vgi;
5357 const char* face_list[] = {
5358 "@WineTestVertical", /* has vmtx table */
5359 "@Ume Gothic", /* doesn't have vmtx table */
5360 "@MS UI Gothic", /* has vmtx table, available on native */
5363 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
5365 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5366 return;
5369 if (!write_ttf_file("vertical.ttf", ttf_name))
5371 skip("Failed to create ttf file for testing\n");
5372 return;
5375 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
5376 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5378 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
5379 ok(installed, "WineTestVertical is not installed\n");
5380 ok(selected, "WineTestVertical is not selected\n");
5381 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5382 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5383 gm.gmBlackBoxX, gm.gmBlackBoxY);
5385 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
5386 ok(installed, "@WineTestVertical is not installed\n");
5387 ok(selected, "@WineTestVertical is not selected\n");
5388 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5389 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5390 gm.gmBlackBoxX, gm.gmBlackBoxY);
5392 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
5394 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
5395 const char* face = face_list[i];
5396 if (!is_truetype_font_installed(face)) {
5397 skip("%s is not installed\n", face);
5398 continue;
5400 trace("Testing %s...\n", face);
5401 check_vertical_metrics(&face[1]);
5404 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
5405 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5407 DeleteFileA(ttf_name);
5410 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
5411 DWORD type, LPARAM lParam)
5413 if (lf->lfFaceName[0] == '@') {
5414 return 0;
5416 return 1;
5419 static void test_east_asian_font_selection(void)
5421 HDC hdc;
5422 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
5423 GB2312_CHARSET, CHINESEBIG5_CHARSET };
5424 size_t i;
5426 hdc = GetDC(NULL);
5428 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
5430 LOGFONTA lf;
5431 HFONT hfont;
5432 char face_name[LF_FACESIZE];
5433 int ret;
5435 memset(&lf, 0, sizeof lf);
5436 lf.lfFaceName[0] = '\0';
5437 lf.lfCharSet = charset[i];
5439 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
5441 skip("Vertical font for charset %u is not installed\n", charset[i]);
5442 continue;
5445 hfont = CreateFontIndirectA(&lf);
5446 hfont = SelectObject(hdc, hfont);
5447 memset(face_name, 0, sizeof face_name);
5448 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5449 ok(ret && face_name[0] != '@',
5450 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
5451 DeleteObject(SelectObject(hdc, hfont));
5453 memset(&lf, 0, sizeof lf);
5454 strcpy(lf.lfFaceName, "@");
5455 lf.lfCharSet = charset[i];
5456 hfont = CreateFontIndirectA(&lf);
5457 hfont = SelectObject(hdc, hfont);
5458 memset(face_name, 0, sizeof face_name);
5459 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5460 ok(ret && face_name[0] == '@',
5461 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
5462 DeleteObject(SelectObject(hdc, hfont));
5464 ReleaseDC(NULL, hdc);
5467 static int get_font_dpi(const LOGFONTA *lf, int *height)
5469 HDC hdc = CreateCompatibleDC(0);
5470 HFONT hfont;
5471 TEXTMETRICA tm;
5472 int ret;
5474 hfont = CreateFontIndirectA(lf);
5475 ok(hfont != 0, "CreateFontIndirect failed\n");
5477 SelectObject(hdc, hfont);
5478 ret = GetTextMetricsA(hdc, &tm);
5479 ok(ret, "GetTextMetrics failed\n");
5480 ret = tm.tmDigitizedAspectX;
5481 if (height) *height = tm.tmHeight;
5483 DeleteDC(hdc);
5484 DeleteObject(hfont);
5486 return ret;
5489 static void test_stock_fonts(void)
5491 static const int font[] =
5493 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
5494 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5496 static const struct test_data
5498 int charset, weight, height, height_pixels, dpi;
5499 const char face_name[LF_FACESIZE];
5500 } td[][11] =
5502 { /* ANSI_FIXED_FONT */
5503 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
5504 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
5505 { 0 }
5507 { /* ANSI_VAR_FONT */
5508 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
5509 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
5510 { 0 }
5512 { /* SYSTEM_FONT */
5513 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5514 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5515 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5516 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5517 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5518 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5519 { 0 }
5521 { /* DEVICE_DEFAULT_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 { /* DEFAULT_GUI_FONT */
5531 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
5532 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
5533 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
5534 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
5535 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
5536 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
5537 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
5538 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
5539 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5540 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
5541 { 0 }
5544 int i, j;
5546 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
5548 HFONT hfont;
5549 LOGFONTA lf;
5550 int ret, height;
5552 hfont = GetStockObject(font[i]);
5553 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
5555 ret = GetObjectA(hfont, sizeof(lf), &lf);
5556 if (ret != sizeof(lf))
5558 /* NT4 */
5559 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
5560 continue;
5563 for (j = 0; td[i][j].face_name[0] != 0; j++)
5565 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
5567 continue;
5570 ret = get_font_dpi(&lf, &height);
5571 if (ret != td[i][j].dpi)
5573 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5574 i, j, lf.lfFaceName, ret, td[i][j].dpi);
5575 continue;
5578 /* FIXME: Remove once Wine is fixed */
5579 if (td[i][j].dpi != 96 &&
5580 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5581 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
5582 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5583 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
5584 todo_wine
5585 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5586 else
5587 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5589 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
5590 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
5591 if (td[i][j].face_name[0] == '?')
5593 /* Wine doesn't have this font, skip this case for now.
5594 Actually, the face name is localized on Windows and varies
5595 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5596 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
5598 else
5600 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);
5602 break;
5607 static void test_max_height(void)
5609 HDC hdc;
5610 LOGFONTA lf;
5611 HFONT hfont, hfont_old;
5612 TEXTMETRICA tm1, tm;
5613 BOOL r;
5614 LONG invalid_height[] = { -65536, -123456, 123456 };
5615 size_t i;
5617 memset(&tm1, 0, sizeof(tm1));
5618 memset(&lf, 0, sizeof(lf));
5619 strcpy(lf.lfFaceName, "Tahoma");
5620 lf.lfHeight = -1;
5622 hdc = GetDC(NULL);
5624 /* get 1 ppem value */
5625 hfont = CreateFontIndirectA(&lf);
5626 hfont_old = SelectObject(hdc, hfont);
5627 r = GetTextMetricsA(hdc, &tm1);
5628 ok(r, "GetTextMetrics failed\n");
5629 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5630 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5631 DeleteObject(SelectObject(hdc, hfont_old));
5633 /* test the largest value */
5634 lf.lfHeight = -((1 << 16) - 1);
5635 hfont = CreateFontIndirectA(&lf);
5636 hfont_old = SelectObject(hdc, hfont);
5637 memset(&tm, 0, sizeof(tm));
5638 r = GetTextMetricsA(hdc, &tm);
5639 ok(r, "GetTextMetrics failed\n");
5640 ok(tm.tmHeight > tm1.tmHeight,
5641 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5642 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
5643 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5644 DeleteObject(SelectObject(hdc, hfont_old));
5646 /* test an invalid value */
5647 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
5648 lf.lfHeight = invalid_height[i];
5649 hfont = CreateFontIndirectA(&lf);
5650 hfont_old = SelectObject(hdc, hfont);
5651 memset(&tm, 0, sizeof(tm));
5652 r = GetTextMetricsA(hdc, &tm);
5653 ok(r, "GetTextMetrics failed\n");
5654 ok(tm.tmHeight == tm1.tmHeight,
5655 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5656 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
5657 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5658 DeleteObject(SelectObject(hdc, hfont_old));
5661 ReleaseDC(NULL, hdc);
5662 return;
5665 static void test_vertical_order(void)
5667 struct enum_font_data efd;
5668 LOGFONTA lf;
5669 HDC hdc;
5670 int i, j;
5672 hdc = CreateCompatibleDC(0);
5673 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5675 memset(&lf, 0, sizeof(lf));
5676 lf.lfCharSet = DEFAULT_CHARSET;
5677 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5678 lf.lfHeight = 16;
5679 lf.lfWidth = 16;
5680 lf.lfQuality = DEFAULT_QUALITY;
5681 lf.lfItalic = FALSE;
5682 lf.lfWeight = FW_DONTCARE;
5683 efd.total = 0;
5684 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
5685 for (i = 0; i < efd.total; i++)
5687 if (efd.lf[i].lfFaceName[0] != '@') continue;
5688 for (j = 0; j < efd.total; j++)
5690 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
5692 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
5693 break;
5697 DeleteDC( hdc );
5700 static void test_GetCharWidth32(void)
5702 BOOL ret;
5703 HDC hdc;
5704 LOGFONTA lf;
5705 HFONT hfont;
5706 INT bufferA;
5707 INT bufferW;
5708 HWND hwnd;
5710 if (!pGetCharWidth32A || !pGetCharWidth32W)
5712 win_skip("GetCharWidth32A/W not available on this platform\n");
5713 return;
5716 memset(&lf, 0, sizeof(lf));
5717 strcpy(lf.lfFaceName, "System");
5718 lf.lfHeight = 20;
5720 hfont = CreateFontIndirectA(&lf);
5721 hdc = GetDC(0);
5722 hfont = SelectObject(hdc, hfont);
5724 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5725 ok(ret, "GetCharWidth32W should have succeeded\n");
5726 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
5727 ok(ret, "GetCharWidth32A should have succeeded\n");
5728 ok (bufferA == bufferW, "Widths should be the same\n");
5729 ok (bufferA > 0," Width should be greater than zero\n");
5731 hfont = SelectObject(hdc, hfont);
5732 DeleteObject(hfont);
5733 ReleaseDC(NULL, hdc);
5735 memset(&lf, 0, sizeof(lf));
5736 strcpy(lf.lfFaceName, "Tahoma");
5737 lf.lfHeight = 20;
5739 hfont = CreateFontIndirectA(&lf);
5740 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
5741 0, 0, 0, NULL);
5742 hdc = GetDC(hwnd);
5743 SetMapMode( hdc, MM_ANISOTROPIC );
5744 SelectObject(hdc, hfont);
5746 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5747 ok(ret, "GetCharWidth32W should have succeeded\n");
5748 ok (bufferW > 0," Width should be greater than zero\n");
5749 SetWindowExtEx(hdc, -1,-1,NULL);
5750 SetGraphicsMode(hdc, GM_COMPATIBLE);
5751 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5752 ok(ret, "GetCharWidth32W should have succeeded\n");
5753 ok (bufferW > 0," Width should be greater than zero\n");
5754 SetGraphicsMode(hdc, GM_ADVANCED);
5755 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5756 ok(ret, "GetCharWidth32W should have succeeded\n");
5757 todo_wine 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 ok (bufferW > 0," Width should be greater than zero\n");
5768 ReleaseDC(hwnd, hdc);
5769 DestroyWindow(hwnd);
5771 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
5772 0, 0, 0, NULL);
5773 hdc = GetDC(hwnd);
5774 SetMapMode( hdc, MM_ANISOTROPIC );
5775 SelectObject(hdc, hfont);
5777 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5778 ok(ret, "GetCharWidth32W should have succeeded\n");
5779 ok (bufferW > 0," Width should be greater than zero\n");
5780 SetWindowExtEx(hdc, -1,-1,NULL);
5781 SetGraphicsMode(hdc, GM_COMPATIBLE);
5782 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5783 ok(ret, "GetCharWidth32W should have succeeded\n");
5784 ok (bufferW > 0," Width should be greater than zero\n");
5785 SetGraphicsMode(hdc, GM_ADVANCED);
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 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
5799 ReleaseDC(hwnd, hdc);
5800 DestroyWindow(hwnd);
5801 DeleteObject(hfont);
5804 static void test_fake_bold_font(void)
5806 HDC hdc;
5807 HFONT hfont, hfont_old;
5808 LOGFONTA lf;
5809 BOOL ret;
5810 TEXTMETRICA tm[2];
5811 ABC abc[2];
5812 INT w[2];
5814 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
5815 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
5816 return;
5819 /* Test outline font */
5820 memset(&lf, 0, sizeof(lf));
5821 strcpy(lf.lfFaceName, "Wingdings");
5822 lf.lfWeight = FW_NORMAL;
5823 lf.lfCharSet = SYMBOL_CHARSET;
5824 hfont = CreateFontIndirectA(&lf);
5826 hdc = GetDC(NULL);
5827 hfont_old = SelectObject(hdc, hfont);
5829 /* base metrics */
5830 ret = GetTextMetricsA(hdc, &tm[0]);
5831 ok(ret, "got %d\n", ret);
5832 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[0]);
5833 ok(ret, "got %d\n", ret);
5835 lf.lfWeight = FW_BOLD;
5836 hfont = CreateFontIndirectA(&lf);
5837 DeleteObject(SelectObject(hdc, hfont));
5839 /* bold metrics */
5840 ret = GetTextMetricsA(hdc, &tm[1]);
5841 ok(ret, "got %d\n", ret);
5842 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[1]);
5843 ok(ret, "got %d\n", ret);
5845 DeleteObject(SelectObject(hdc, hfont_old));
5846 ReleaseDC(NULL, hdc);
5848 /* compare results (outline) */
5849 ok(tm[0].tmHeight == tm[1].tmHeight, "expected %d, got %d\n", tm[0].tmHeight, tm[1].tmHeight);
5850 ok(tm[0].tmAscent == tm[1].tmAscent, "expected %d, got %d\n", tm[0].tmAscent, tm[1].tmAscent);
5851 ok(tm[0].tmDescent == tm[1].tmDescent, "expected %d, got %d\n", tm[0].tmDescent, tm[1].tmDescent);
5852 ok((tm[0].tmAveCharWidth + 1) == tm[1].tmAveCharWidth,
5853 "expected %d, got %d\n", tm[0].tmAveCharWidth + 1, tm[1].tmAveCharWidth);
5854 ok((tm[0].tmMaxCharWidth + 1) == tm[1].tmMaxCharWidth,
5855 "expected %d, got %d\n", tm[0].tmMaxCharWidth + 1, tm[1].tmMaxCharWidth);
5856 ok(tm[0].tmOverhang == tm[1].tmOverhang, "expected %d, got %d\n", tm[0].tmOverhang, tm[1].tmOverhang);
5857 w[0] = abc[0].abcA + abc[0].abcB + abc[0].abcC;
5858 w[1] = abc[1].abcA + abc[1].abcB + abc[1].abcC;
5859 ok((w[0] + 1) == w[1], "expected %d, got %d\n", w[0] + 1, w[1]);
5863 static void test_bitmap_font_glyph_index(void)
5865 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
5866 const struct {
5867 LPCSTR face;
5868 BYTE charset;
5869 } bitmap_font_list[] = {
5870 { "Courier", ANSI_CHARSET },
5871 { "Small Fonts", ANSI_CHARSET },
5872 { "Fixedsys", DEFAULT_CHARSET },
5873 { "System", DEFAULT_CHARSET }
5875 HDC hdc;
5876 LOGFONTA lf;
5877 HFONT hFont;
5878 CHAR facename[LF_FACESIZE];
5879 BITMAPINFO bmi;
5880 HBITMAP hBmp[2];
5881 void *pixels[2];
5882 int i, j;
5883 DWORD ret;
5884 BITMAP bmp;
5885 TEXTMETRICA tm;
5886 CHARSETINFO ci;
5887 BYTE chr = '\xA9';
5889 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
5890 win_skip("GetGlyphIndices is unavailable\n");
5891 return;
5894 hdc = CreateCompatibleDC(0);
5895 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5897 memset(&bmi, 0, sizeof(bmi));
5898 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
5899 bmi.bmiHeader.biBitCount = 32;
5900 bmi.bmiHeader.biPlanes = 1;
5901 bmi.bmiHeader.biWidth = 128;
5902 bmi.bmiHeader.biHeight = 32;
5903 bmi.bmiHeader.biCompression = BI_RGB;
5905 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
5906 memset(&lf, 0, sizeof(lf));
5907 lf.lfCharSet = bitmap_font_list[i].charset;
5908 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
5909 hFont = CreateFontIndirectA(&lf);
5910 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
5911 hFont = SelectObject(hdc, hFont);
5912 ret = GetTextMetricsA(hdc, &tm);
5913 ok(ret, "GetTextMetric failed\n");
5914 ret = GetTextFaceA(hdc, sizeof(facename), facename);
5915 ok(ret, "GetTextFace failed\n");
5916 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
5917 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
5918 continue;
5920 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
5921 skip("expected %s, got %s\n", lf.lfFaceName, facename);
5922 continue;
5925 for (j = 0; j < 2; j++) {
5926 HBITMAP hBmpPrev;
5927 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
5928 ok(hBmp[j] != NULL, "Can't create DIB\n");
5929 hBmpPrev = SelectObject(hdc, hBmp[j]);
5930 switch (j) {
5931 case 0:
5932 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
5933 break;
5934 case 1:
5936 int len = lstrlenW(text);
5937 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
5938 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
5939 ok(ret, "GetGlyphIndices failed\n");
5940 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
5941 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
5942 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
5943 HeapFree(GetProcessHeap(), 0, indices);
5944 break;
5947 ok(ret, "ExtTextOutW failed\n");
5948 SelectObject(hdc, hBmpPrev);
5951 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
5952 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
5953 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5955 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
5956 if (!ret) {
5957 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5958 goto next;
5960 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
5961 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
5962 goto next;
5965 for (j = 0; j < 2; j++) {
5966 HBITMAP hBmpPrev;
5967 WORD code;
5968 hBmpPrev = SelectObject(hdc, hBmp[j]);
5969 switch (j) {
5970 case 0:
5971 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
5972 break;
5973 case 1:
5974 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
5975 ok(ret, "GetGlyphIndices failed\n");
5976 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
5977 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
5978 break;
5980 ok(ret, "ExtTextOutA failed\n");
5981 SelectObject(hdc, hBmpPrev);
5984 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
5985 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5986 next:
5987 for (j = 0; j < 2; j++)
5988 DeleteObject(hBmp[j]);
5989 hFont = SelectObject(hdc, hFont);
5990 DeleteObject(hFont);
5993 DeleteDC(hdc);
5996 START_TEST(font)
5998 init();
6000 test_stock_fonts();
6001 test_logfont();
6002 test_bitmap_font();
6003 test_outline_font();
6004 test_bitmap_font_metrics();
6005 test_GdiGetCharDimensions();
6006 test_GetCharABCWidths();
6007 test_text_extents();
6008 test_GetGlyphIndices();
6009 test_GetKerningPairs();
6010 test_GetOutlineTextMetrics();
6011 test_SetTextJustification();
6012 test_font_charset();
6013 test_GdiGetCodePage();
6014 test_GetFontUnicodeRanges();
6015 test_nonexistent_font();
6016 test_orientation();
6017 test_height_selection();
6018 test_AddFontMemResource();
6019 test_EnumFonts();
6021 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6022 * I'd like to avoid them in this test.
6024 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6025 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6026 if (is_truetype_font_installed("Arial Black") &&
6027 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6029 test_EnumFontFamilies("", ANSI_CHARSET);
6030 test_EnumFontFamilies("", SYMBOL_CHARSET);
6031 test_EnumFontFamilies("", DEFAULT_CHARSET);
6033 else
6034 skip("Arial Black or Symbol/Wingdings is not installed\n");
6035 test_EnumFontFamiliesEx_default_charset();
6036 test_GetTextMetrics();
6037 test_GdiRealizationInfo();
6038 test_GetTextFace();
6039 test_GetGlyphOutline();
6040 test_GetTextMetrics2("Tahoma", -11);
6041 test_GetTextMetrics2("Tahoma", -55);
6042 test_GetTextMetrics2("Tahoma", -110);
6043 test_GetTextMetrics2("Arial", -11);
6044 test_GetTextMetrics2("Arial", -55);
6045 test_GetTextMetrics2("Arial", -110);
6046 test_CreateFontIndirect();
6047 test_CreateFontIndirectEx();
6048 test_oemcharset();
6049 test_fullname();
6050 test_fullname2();
6051 test_east_asian_font_selection();
6052 test_max_height();
6053 test_vertical_order();
6054 test_GetCharWidth32();
6055 test_fake_bold_font();
6056 test_bitmap_font_glyph_index();
6058 /* These tests should be last test until RemoveFontResource
6059 * is properly implemented.
6061 test_vertical_font();
6062 test_CreateScalableFontResource();