gdi32/tests: GetCharABCWidthsA is broken for johab charset on windows.
[wine/multimedia.git] / dlls / gdi32 / tests / font.c
blob259f4a02f8a3b888259f65600bef59ceaa266726
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 {JOHAB_CHARSET, 0x8446, 0x3135},
4133 {GB2312_CHARSET, 0x8141, 0x4e04},
4134 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4136 UINT i;
4138 if (!is_truetype_font_installed("Tahoma"))
4140 skip("Tahoma is not installed\n");
4141 return;
4144 hdc = CreateCompatibleDC(0);
4145 memset(&lf, 0, sizeof(lf));
4146 lf.lfHeight = 72;
4147 lstrcpyA(lf.lfFaceName, "Tahoma");
4148 SetLastError(0xdeadbeef);
4149 hfont = CreateFontIndirectA(&lf);
4150 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4151 old_hfont = SelectObject(hdc, hfont);
4153 memset(&gm, 0, sizeof(gm));
4154 SetLastError(0xdeadbeef);
4155 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4156 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4158 memset(&gm, 0, sizeof(gm));
4159 SetLastError(0xdeadbeef);
4160 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4161 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4162 ok(GetLastError() == 0xdeadbeef ||
4163 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4164 "expected 0xdeadbeef, got %u\n", GetLastError());
4166 memset(&gm, 0, sizeof(gm));
4167 SetLastError(0xdeadbeef);
4168 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4169 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4170 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4172 memset(&gm, 0, sizeof(gm));
4173 SetLastError(0xdeadbeef);
4174 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4175 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4177 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4178 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4181 /* test for needed buffer size request on space char */
4182 memset(&gm, 0, sizeof(gm));
4183 SetLastError(0xdeadbeef);
4184 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4185 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4186 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4188 /* requesting buffer size for space char + error */
4189 memset(&gm, 0, sizeof(gm));
4190 SetLastError(0xdeadbeef);
4191 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4192 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4194 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4195 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4198 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4200 DWORD dummy;
4202 memset(&gm, 0xab, sizeof(gm));
4203 SetLastError(0xdeadbeef);
4204 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4205 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4207 if (fmt[i] == GGO_METRICS)
4208 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4209 else
4210 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4211 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4212 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4215 memset(&gm, 0xab, sizeof(gm));
4216 SetLastError(0xdeadbeef);
4217 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4218 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4220 if (fmt[i] == GGO_METRICS)
4221 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4222 else
4223 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4224 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4225 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4228 memset(&gm, 0xab, sizeof(gm));
4229 SetLastError(0xdeadbeef);
4230 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4231 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4233 if (fmt[i] == GGO_METRICS)
4234 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4235 else
4236 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4237 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4238 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4241 memset(&gm, 0xab, sizeof(gm));
4242 SetLastError(0xdeadbeef);
4243 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4244 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4246 if (fmt[i] == GGO_METRICS) {
4247 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4248 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4249 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4251 else
4253 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4254 memset(&gm2, 0xab, sizeof(gm2));
4255 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4256 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4261 SelectObject(hdc, old_hfont);
4262 DeleteObject(hfont);
4264 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4266 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4267 TEXTMETRICA tm;
4269 lf.lfFaceName[0] = '\0';
4270 lf.lfCharSet = c[i].cs;
4271 lf.lfPitchAndFamily = 0;
4272 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4274 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4275 continue;
4278 old_hfont = SelectObject(hdc, hfont);
4280 /* expected to ignore superfluous bytes (sigle-byte character) */
4281 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4282 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4283 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4285 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4286 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4287 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4289 /* expected to ignore superfluous bytes (double-byte character) */
4290 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4291 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4292 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4293 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4295 /* expected to match wide-char version results */
4296 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4297 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4299 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4301 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4302 continue;
4304 DeleteObject(SelectObject(hdc, hfont));
4305 if (c[i].a <= 0xff)
4307 DeleteObject(SelectObject(hdc, old_hfont));
4308 continue;
4311 ret = GetObjectA(hfont, sizeof lf, &lf);
4312 ok(ret > 0, "GetObject error %u\n", GetLastError());
4314 ret = GetTextMetricsA(hdc, &tm);
4315 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4316 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4317 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4318 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4319 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4320 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4321 "expected %d, got %d (%s:%d)\n",
4322 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4324 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4325 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4326 ok(gm2.gmCellIncY == -lf.lfHeight,
4327 "expected %d, got %d (%s:%d)\n",
4328 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4330 lf.lfItalic = TRUE;
4331 hfont = CreateFontIndirectA(&lf);
4332 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4333 DeleteObject(SelectObject(hdc, hfont));
4334 ret = GetTextMetricsA(hdc, &tm);
4335 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4336 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4337 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4338 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4339 "expected %d, got %d (%s:%d)\n",
4340 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4342 lf.lfItalic = FALSE;
4343 lf.lfEscapement = lf.lfOrientation = 2700;
4344 hfont = CreateFontIndirectA(&lf);
4345 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4346 DeleteObject(SelectObject(hdc, hfont));
4347 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4348 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4349 ok(gm2.gmCellIncY == -lf.lfHeight,
4350 "expected %d, got %d (%s:%d)\n",
4351 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4353 hfont = SelectObject(hdc, old_hfont);
4354 DeleteObject(hfont);
4357 DeleteDC(hdc);
4360 /* bug #9995: there is a limit to the character width that can be specified */
4361 static void test_GetTextMetrics2(const char *fontname, int font_height)
4363 HFONT of, hf;
4364 HDC hdc;
4365 TEXTMETRICA tm;
4366 BOOL ret;
4367 int ave_width, height, width, ratio, scale;
4369 if (!is_truetype_font_installed( fontname)) {
4370 skip("%s is not installed\n", fontname);
4371 return;
4373 hdc = CreateCompatibleDC(0);
4374 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4375 /* select width = 0 */
4376 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4377 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4378 DEFAULT_QUALITY, VARIABLE_PITCH,
4379 fontname);
4380 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4381 of = SelectObject( hdc, hf);
4382 ret = GetTextMetricsA( hdc, &tm);
4383 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4384 height = tm.tmHeight;
4385 ave_width = tm.tmAveCharWidth;
4386 SelectObject( hdc, of);
4387 DeleteObject( hf);
4389 trace("height %d, ave width %d\n", height, ave_width);
4391 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4393 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4394 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4395 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4396 ok(hf != 0, "CreateFont failed\n");
4397 of = SelectObject(hdc, hf);
4398 ret = GetTextMetricsA(hdc, &tm);
4399 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4400 SelectObject(hdc, of);
4401 DeleteObject(hf);
4403 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4404 break;
4407 DeleteDC(hdc);
4409 ratio = width / height;
4410 scale = width / ave_width;
4412 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4413 width, height, ratio, width, ave_width, scale);
4415 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4418 static void test_CreateFontIndirect(void)
4420 LOGFONTA lf, getobj_lf;
4421 int ret, i;
4422 HFONT hfont;
4423 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4425 memset(&lf, 0, sizeof(lf));
4426 lf.lfCharSet = ANSI_CHARSET;
4427 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4428 lf.lfHeight = 16;
4429 lf.lfWidth = 16;
4430 lf.lfQuality = DEFAULT_QUALITY;
4431 lf.lfItalic = FALSE;
4432 lf.lfWeight = FW_DONTCARE;
4434 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4436 lstrcpyA(lf.lfFaceName, TestName[i]);
4437 hfont = CreateFontIndirectA(&lf);
4438 ok(hfont != 0, "CreateFontIndirectA failed\n");
4439 SetLastError(0xdeadbeef);
4440 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4441 ok(ret, "GetObject failed: %d\n", GetLastError());
4442 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4443 ok(lf.lfWeight == getobj_lf.lfWeight ||
4444 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4445 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4446 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4447 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4448 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4449 DeleteObject(hfont);
4453 static void test_CreateFontIndirectEx(void)
4455 ENUMLOGFONTEXDVA lfex;
4456 HFONT hfont;
4458 if (!pCreateFontIndirectExA)
4460 win_skip("CreateFontIndirectExA is not available\n");
4461 return;
4464 if (!is_truetype_font_installed("Arial"))
4466 skip("Arial is not installed\n");
4467 return;
4470 SetLastError(0xdeadbeef);
4471 hfont = pCreateFontIndirectExA(NULL);
4472 ok(hfont == NULL, "got %p\n", hfont);
4473 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4475 memset(&lfex, 0, sizeof(lfex));
4476 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
4477 hfont = pCreateFontIndirectExA(&lfex);
4478 ok(hfont != 0, "CreateFontIndirectEx failed\n");
4479 if (hfont)
4480 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
4481 DeleteObject(hfont);
4484 static void free_font(void *font)
4486 UnmapViewOfFile(font);
4489 static void *load_font(const char *font_name, DWORD *font_size)
4491 char file_name[MAX_PATH];
4492 HANDLE file, mapping;
4493 void *font;
4495 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
4496 strcat(file_name, "\\fonts\\");
4497 strcat(file_name, font_name);
4499 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4500 if (file == INVALID_HANDLE_VALUE) return NULL;
4502 *font_size = GetFileSize(file, NULL);
4504 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4505 if (!mapping)
4507 CloseHandle(file);
4508 return NULL;
4511 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4513 CloseHandle(file);
4514 CloseHandle(mapping);
4515 return font;
4518 static void test_AddFontMemResource(void)
4520 void *font;
4521 DWORD font_size, num_fonts;
4522 HANDLE ret;
4523 BOOL bRet;
4525 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4527 win_skip("AddFontMemResourceEx is not available on this platform\n");
4528 return;
4531 font = load_font("sserife.fon", &font_size);
4532 if (!font)
4534 skip("Unable to locate and load font sserife.fon\n");
4535 return;
4538 SetLastError(0xdeadbeef);
4539 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4540 ok(!ret, "AddFontMemResourceEx should fail\n");
4541 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4542 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4543 GetLastError());
4545 SetLastError(0xdeadbeef);
4546 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4547 ok(!ret, "AddFontMemResourceEx should fail\n");
4548 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4549 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4550 GetLastError());
4552 SetLastError(0xdeadbeef);
4553 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4554 ok(!ret, "AddFontMemResourceEx should fail\n");
4555 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4556 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4557 GetLastError());
4559 SetLastError(0xdeadbeef);
4560 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4561 ok(!ret, "AddFontMemResourceEx should fail\n");
4562 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4563 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4564 GetLastError());
4566 SetLastError(0xdeadbeef);
4567 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4568 ok(!ret, "AddFontMemResourceEx should fail\n");
4569 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4570 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4571 GetLastError());
4573 SetLastError(0xdeadbeef);
4574 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4575 ok(!ret, "AddFontMemResourceEx should fail\n");
4576 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4577 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4578 GetLastError());
4580 num_fonts = 0xdeadbeef;
4581 SetLastError(0xdeadbeef);
4582 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4583 ok(!ret, "AddFontMemResourceEx should fail\n");
4584 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4585 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4586 GetLastError());
4587 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4589 if (0) /* hangs under windows 2000 */
4591 num_fonts = 0xdeadbeef;
4592 SetLastError(0xdeadbeef);
4593 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4594 ok(!ret, "AddFontMemResourceEx should fail\n");
4595 ok(GetLastError() == 0xdeadbeef,
4596 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4597 GetLastError());
4598 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4601 num_fonts = 0xdeadbeef;
4602 SetLastError(0xdeadbeef);
4603 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4604 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4605 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4606 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4608 free_font(font);
4610 SetLastError(0xdeadbeef);
4611 bRet = pRemoveFontMemResourceEx(ret);
4612 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4614 /* test invalid pointer to number of loaded fonts */
4615 font = load_font("sserife.fon", &font_size);
4616 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4618 SetLastError(0xdeadbeef);
4619 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4620 ok(!ret, "AddFontMemResourceEx should fail\n");
4621 ok(GetLastError() == 0xdeadbeef,
4622 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4623 GetLastError());
4625 SetLastError(0xdeadbeef);
4626 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4627 ok(!ret, "AddFontMemResourceEx should fail\n");
4628 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4629 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4630 GetLastError());
4632 free_font(font);
4635 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4637 LOGFONTA *lf;
4639 if (type != TRUETYPE_FONTTYPE) return 1;
4641 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4643 lf = (LOGFONTA *)lparam;
4644 *lf = *elf;
4645 return 0;
4648 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4650 int ret;
4651 LOGFONTA *lf;
4653 if (type != TRUETYPE_FONTTYPE) return 1;
4655 lf = (LOGFONTA *)lparam;
4656 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
4657 if(ret == 0)
4659 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4660 *lf = *elf;
4661 return 0;
4663 return 1;
4666 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
4668 return lparam;
4671 static void test_EnumFonts(void)
4673 int ret;
4674 LOGFONTA lf;
4675 HDC hdc;
4677 if (!is_truetype_font_installed("Arial"))
4679 skip("Arial is not installed\n");
4680 return;
4683 /* Windows uses localized font face names, so Arial Bold won't be found */
4684 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4686 skip("User locale is not English, skipping the test\n");
4687 return;
4690 hdc = CreateCompatibleDC(0);
4692 /* check that the enumproc's retval is returned */
4693 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4694 ok(ret == 0xcafe, "got %08x\n", ret);
4696 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4697 ok(!ret, "font Arial is not enumerated\n");
4698 ret = strcmp(lf.lfFaceName, "Arial");
4699 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4700 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4702 strcpy(lf.lfFaceName, "Arial");
4703 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4704 ok(!ret, "font Arial is not enumerated\n");
4705 ret = strcmp(lf.lfFaceName, "Arial");
4706 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4707 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4709 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4710 ok(!ret, "font Arial Bold is not enumerated\n");
4711 ret = strcmp(lf.lfFaceName, "Arial");
4712 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4713 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4715 strcpy(lf.lfFaceName, "Arial Bold");
4716 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4717 ok(ret, "font Arial Bold should not be enumerated\n");
4719 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4720 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4721 ret = strcmp(lf.lfFaceName, "Arial");
4722 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4723 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4725 strcpy(lf.lfFaceName, "Arial Bold Italic");
4726 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4727 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4729 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4730 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4732 strcpy(lf.lfFaceName, "Arial Italic Bold");
4733 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4734 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4736 DeleteDC(hdc);
4739 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4741 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
4742 const char *fullname = (const char *)lParam;
4744 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4746 return 1;
4749 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4751 HDC hdc = GetDC(0);
4752 BOOL ret = FALSE;
4754 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4755 ret = TRUE;
4757 ReleaseDC(0, hdc);
4758 return ret;
4761 static void test_fullname(void)
4763 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4764 WCHAR bufW[LF_FULLFACESIZE];
4765 char bufA[LF_FULLFACESIZE];
4766 HFONT hfont, of;
4767 LOGFONTA lf;
4768 HDC hdc;
4769 int i;
4770 DWORD ret;
4772 hdc = CreateCompatibleDC(0);
4773 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4775 memset(&lf, 0, sizeof(lf));
4776 lf.lfCharSet = ANSI_CHARSET;
4777 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4778 lf.lfHeight = 16;
4779 lf.lfWidth = 16;
4780 lf.lfQuality = DEFAULT_QUALITY;
4781 lf.lfItalic = FALSE;
4782 lf.lfWeight = FW_DONTCARE;
4784 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4786 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4788 skip("%s is not installed\n", TestName[i]);
4789 continue;
4792 lstrcpyA(lf.lfFaceName, TestName[i]);
4793 hfont = CreateFontIndirectA(&lf);
4794 ok(hfont != 0, "CreateFontIndirectA failed\n");
4796 of = SelectObject(hdc, hfont);
4797 bufW[0] = 0;
4798 bufA[0] = 0;
4799 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4800 ok(ret, "face full name could not be read\n");
4801 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4802 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4803 SelectObject(hdc, of);
4804 DeleteObject(hfont);
4806 DeleteDC(hdc);
4809 static WCHAR *prepend_at(WCHAR *family)
4811 if (!family)
4812 return NULL;
4814 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4815 family[0] = '@';
4816 return family;
4819 static void test_fullname2_helper(const char *Family)
4821 char *FamilyName, *FaceName, *StyleName, *otmStr;
4822 struct enum_fullname_data efnd;
4823 WCHAR *bufW;
4824 char *bufA;
4825 HFONT hfont, of;
4826 LOGFONTA lf;
4827 HDC hdc;
4828 int i;
4829 DWORD otm_size, ret, buf_size;
4830 OUTLINETEXTMETRICA *otm;
4831 BOOL want_vertical, get_vertical;
4832 want_vertical = ( Family[0] == '@' );
4834 hdc = CreateCompatibleDC(0);
4835 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4837 memset(&lf, 0, sizeof(lf));
4838 lf.lfCharSet = DEFAULT_CHARSET;
4839 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4840 lf.lfHeight = 16;
4841 lf.lfWidth = 16;
4842 lf.lfQuality = DEFAULT_QUALITY;
4843 lf.lfItalic = FALSE;
4844 lf.lfWeight = FW_DONTCARE;
4845 strcpy(lf.lfFaceName, Family);
4846 efnd.total = 0;
4847 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4848 if (efnd.total == 0)
4849 skip("%s is not installed\n", lf.lfFaceName);
4851 for (i = 0; i < efnd.total; i++)
4853 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4854 FaceName = (char *)efnd.elf[i].elfFullName;
4855 StyleName = (char *)efnd.elf[i].elfStyle;
4857 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4859 get_vertical = ( FamilyName[0] == '@' );
4860 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4862 lstrcpyA(lf.lfFaceName, FaceName);
4863 hfont = CreateFontIndirectA(&lf);
4864 ok(hfont != 0, "CreateFontIndirectA failed\n");
4866 of = SelectObject(hdc, hfont);
4867 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4868 ok(buf_size != GDI_ERROR, "no name table found\n");
4869 if (buf_size == GDI_ERROR) continue;
4871 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4872 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4874 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4875 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4876 memset(otm, 0, otm_size);
4877 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
4878 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4879 if (ret == 0) continue;
4881 bufW[0] = 0;
4882 bufA[0] = 0;
4883 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4884 if (!ret)
4886 trace("no localized FONT_FAMILY found.\n");
4887 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4889 ok(ret, "FAMILY (family name) could not be read\n");
4890 if (want_vertical) bufW = prepend_at(bufW);
4891 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4892 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4893 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4894 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4896 bufW[0] = 0;
4897 bufA[0] = 0;
4898 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4899 if (!ret)
4901 trace("no localized FULL_NAME found.\n");
4902 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4904 ok(ret, "FULL_NAME (face name) could not be read\n");
4905 if (want_vertical) bufW = prepend_at(bufW);
4906 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4907 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4908 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4909 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4911 bufW[0] = 0;
4912 bufA[0] = 0;
4913 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4914 if (!ret)
4916 trace("no localized FONT_SUBFAMILY found.\n");
4917 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4919 ok(ret, "SUBFAMILY (style name) could not be read\n");
4920 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4921 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4922 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4923 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4925 bufW[0] = 0;
4926 bufA[0] = 0;
4927 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4928 if (!ret)
4930 trace("no localized UNIQUE_ID found.\n");
4931 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4933 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4934 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4935 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4936 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4938 SelectObject(hdc, of);
4939 DeleteObject(hfont);
4941 HeapFree(GetProcessHeap(), 0, otm);
4942 HeapFree(GetProcessHeap(), 0, bufW);
4943 HeapFree(GetProcessHeap(), 0, bufA);
4945 DeleteDC(hdc);
4948 static void test_fullname2(void)
4950 test_fullname2_helper("Arial");
4951 test_fullname2_helper("DejaVu Sans");
4952 test_fullname2_helper("Lucida Sans");
4953 test_fullname2_helper("Tahoma");
4954 test_fullname2_helper("Webdings");
4955 test_fullname2_helper("Wingdings");
4956 test_fullname2_helper("SimSun");
4957 test_fullname2_helper("NSimSun");
4958 test_fullname2_helper("MingLiu");
4959 test_fullname2_helper("PMingLiu");
4960 test_fullname2_helper("WenQuanYi Micro Hei");
4961 test_fullname2_helper("MS UI Gothic");
4962 test_fullname2_helper("Ume UI Gothic");
4963 test_fullname2_helper("MS Gothic");
4964 test_fullname2_helper("Ume Gothic");
4965 test_fullname2_helper("MS PGothic");
4966 test_fullname2_helper("Ume P Gothic");
4967 test_fullname2_helper("Gulim");
4968 test_fullname2_helper("Batang");
4969 test_fullname2_helper("UnBatang");
4970 test_fullname2_helper("UnDotum");
4971 test_fullname2_helper("@SimSun");
4972 test_fullname2_helper("@NSimSun");
4973 test_fullname2_helper("@MingLiu");
4974 test_fullname2_helper("@PMingLiu");
4975 test_fullname2_helper("@WenQuanYi Micro Hei");
4976 test_fullname2_helper("@MS UI Gothic");
4977 test_fullname2_helper("@Ume UI Gothic");
4978 test_fullname2_helper("@MS Gothic");
4979 test_fullname2_helper("@Ume Gothic");
4980 test_fullname2_helper("@MS PGothic");
4981 test_fullname2_helper("@Ume P Gothic");
4982 test_fullname2_helper("@Gulim");
4983 test_fullname2_helper("@Batang");
4984 test_fullname2_helper("@UnBatang");
4985 test_fullname2_helper("@UnDotum");
4989 static void test_GetGlyphOutline_empty_contour(void)
4991 HDC hdc;
4992 LOGFONTA lf;
4993 HFONT hfont, hfont_prev;
4994 TTPOLYGONHEADER *header;
4995 GLYPHMETRICS gm;
4996 char buf[1024];
4997 DWORD ret;
4999 memset(&lf, 0, sizeof(lf));
5000 lf.lfHeight = 72;
5001 lstrcpyA(lf.lfFaceName, "wine_test");
5003 hfont = CreateFontIndirectA(&lf);
5004 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5006 hdc = GetDC(NULL);
5008 hfont_prev = SelectObject(hdc, hfont);
5009 ok(hfont_prev != NULL, "SelectObject failed\n");
5011 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5012 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5014 header = (TTPOLYGONHEADER*)buf;
5015 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5016 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5017 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5018 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5019 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5020 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5021 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5022 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5024 SelectObject(hdc, hfont_prev);
5025 DeleteObject(hfont);
5026 ReleaseDC(NULL, hdc);
5029 static void test_GetGlyphOutline_metric_clipping(void)
5031 HDC hdc;
5032 LOGFONTA lf;
5033 HFONT hfont, hfont_prev;
5034 GLYPHMETRICS gm;
5035 TEXTMETRICA tm;
5036 DWORD ret;
5038 memset(&lf, 0, sizeof(lf));
5039 lf.lfHeight = 72;
5040 lstrcpyA(lf.lfFaceName, "wine_test");
5042 SetLastError(0xdeadbeef);
5043 hfont = CreateFontIndirectA(&lf);
5044 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5046 hdc = GetDC(NULL);
5048 hfont_prev = SelectObject(hdc, hfont);
5049 ok(hfont_prev != NULL, "SelectObject failed\n");
5051 SetLastError(0xdeadbeef);
5052 ret = GetTextMetricsA(hdc, &tm);
5053 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5055 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5056 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5057 "Glyph top(%d) exceeds ascent(%d)\n",
5058 gm.gmptGlyphOrigin.y, tm.tmAscent);
5059 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5060 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5061 "Glyph bottom(%d) exceeds descent(%d)\n",
5062 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5064 SelectObject(hdc, hfont_prev);
5065 DeleteObject(hfont);
5066 ReleaseDC(NULL, hdc);
5069 static void test_CreateScalableFontResource(void)
5071 char ttf_name[MAX_PATH];
5072 char tmp_path[MAX_PATH];
5073 char fot_name[MAX_PATH];
5074 char *file_part;
5075 DWORD ret;
5076 int i;
5078 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5080 win_skip("AddFontResourceExA is not available on this platform\n");
5081 return;
5084 if (!write_ttf_file("wine_test.ttf", ttf_name))
5086 skip("Failed to create ttf file for testing\n");
5087 return;
5090 trace("created %s\n", ttf_name);
5092 ret = is_truetype_font_installed("wine_test");
5093 ok(!ret, "font wine_test should not be enumerated\n");
5095 ret = GetTempPathA(MAX_PATH, tmp_path);
5096 ok(ret, "GetTempPath() error %d\n", GetLastError());
5097 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5098 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5100 ret = GetFileAttributesA(fot_name);
5101 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5103 SetLastError(0xdeadbeef);
5104 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5105 ok(!ret, "CreateScalableFontResource() should fail\n");
5106 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5108 SetLastError(0xdeadbeef);
5109 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5110 ok(!ret, "CreateScalableFontResource() should fail\n");
5111 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5113 file_part = strrchr(ttf_name, '\\');
5114 SetLastError(0xdeadbeef);
5115 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5116 ok(!ret, "CreateScalableFontResource() should fail\n");
5117 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5119 SetLastError(0xdeadbeef);
5120 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5121 ok(!ret, "CreateScalableFontResource() should fail\n");
5122 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5124 SetLastError(0xdeadbeef);
5125 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5126 ok(!ret, "CreateScalableFontResource() should fail\n");
5127 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5129 ret = DeleteFileA(fot_name);
5130 ok(ret, "DeleteFile() error %d\n", GetLastError());
5132 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5133 ok(!ret, "RemoveFontResourceEx() should fail\n");
5135 /* test public font resource */
5136 SetLastError(0xdeadbeef);
5137 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5138 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5140 ret = is_truetype_font_installed("wine_test");
5141 ok(!ret, "font wine_test should not be enumerated\n");
5143 SetLastError(0xdeadbeef);
5144 ret = pAddFontResourceExA(fot_name, 0, 0);
5145 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5147 ret = is_truetype_font_installed("wine_test");
5148 ok(ret, "font wine_test should be enumerated\n");
5150 test_GetGlyphOutline_empty_contour();
5151 test_GetGlyphOutline_metric_clipping();
5153 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5154 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5156 SetLastError(0xdeadbeef);
5157 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5158 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5160 ret = is_truetype_font_installed("wine_test");
5161 ok(!ret, "font wine_test should not be enumerated\n");
5163 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5164 ok(!ret, "RemoveFontResourceEx() should fail\n");
5166 /* test refcounting */
5167 for (i = 0; i < 5; i++)
5169 SetLastError(0xdeadbeef);
5170 ret = pAddFontResourceExA(fot_name, 0, 0);
5171 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5173 for (i = 0; i < 5; i++)
5175 SetLastError(0xdeadbeef);
5176 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5177 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5179 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5180 ok(!ret, "RemoveFontResourceEx() should fail\n");
5182 DeleteFileA(fot_name);
5184 /* test hidden font resource */
5185 SetLastError(0xdeadbeef);
5186 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5187 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5189 ret = is_truetype_font_installed("wine_test");
5190 ok(!ret, "font wine_test should not be enumerated\n");
5192 SetLastError(0xdeadbeef);
5193 ret = pAddFontResourceExA(fot_name, 0, 0);
5194 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5196 ret = is_truetype_font_installed("wine_test");
5197 todo_wine
5198 ok(!ret, "font wine_test should not be enumerated\n");
5200 /* XP allows removing a private font added with 0 flags */
5201 SetLastError(0xdeadbeef);
5202 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5203 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5205 ret = is_truetype_font_installed("wine_test");
5206 ok(!ret, "font wine_test should not be enumerated\n");
5208 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5209 ok(!ret, "RemoveFontResourceEx() should fail\n");
5211 DeleteFileA(fot_name);
5212 DeleteFileA(ttf_name);
5215 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5217 LOGFONTA lf;
5218 HFONT hfont, hfont_prev;
5219 HDC hdc;
5220 char facename[100];
5221 DWORD ret;
5222 static const WCHAR str[] = { 0x2025 };
5224 *installed = is_truetype_font_installed(name);
5226 lf.lfHeight = -18;
5227 lf.lfWidth = 0;
5228 lf.lfEscapement = 0;
5229 lf.lfOrientation = 0;
5230 lf.lfWeight = FW_DONTCARE;
5231 lf.lfItalic = 0;
5232 lf.lfUnderline = 0;
5233 lf.lfStrikeOut = 0;
5234 lf.lfCharSet = DEFAULT_CHARSET;
5235 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5236 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5237 lf.lfQuality = DEFAULT_QUALITY;
5238 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5239 strcpy(lf.lfFaceName, name);
5241 hfont = CreateFontIndirectA(&lf);
5242 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5244 hdc = GetDC(NULL);
5246 hfont_prev = SelectObject(hdc, hfont);
5247 ok(hfont_prev != NULL, "SelectObject failed\n");
5249 ret = GetTextFaceA(hdc, sizeof facename, facename);
5250 ok(ret, "GetTextFaceA failed\n");
5251 *selected = !strcmp(facename, name);
5253 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5254 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5255 if (!*selected)
5256 memset(gm, 0, sizeof *gm);
5258 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5259 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5261 SelectObject(hdc, hfont_prev);
5262 DeleteObject(hfont);
5263 ReleaseDC(NULL, hdc);
5266 static void check_vertical_metrics(const char *face)
5268 LOGFONTA lf;
5269 HFONT hfont, hfont_prev;
5270 HDC hdc;
5271 DWORD ret;
5272 GLYPHMETRICS rgm, vgm;
5273 const UINT code = 0x5EAD, height = 1000;
5274 WORD idx;
5275 ABC abc;
5276 OUTLINETEXTMETRICA otm;
5277 USHORT numOfLongVerMetrics;
5279 hdc = GetDC(NULL);
5281 memset(&lf, 0, sizeof(lf));
5282 strcpy(lf.lfFaceName, face);
5283 lf.lfHeight = -height;
5284 lf.lfCharSet = DEFAULT_CHARSET;
5285 lf.lfEscapement = lf.lfOrientation = 900;
5286 hfont = CreateFontIndirectA(&lf);
5287 hfont_prev = SelectObject(hdc, hfont);
5288 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5289 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5290 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5291 ok(ret, "GetCharABCWidthsW failed\n");
5292 DeleteObject(SelectObject(hdc, hfont_prev));
5294 memset(&lf, 0, sizeof(lf));
5295 strcpy(lf.lfFaceName, "@");
5296 strcat(lf.lfFaceName, face);
5297 lf.lfHeight = -height;
5298 lf.lfCharSet = DEFAULT_CHARSET;
5299 hfont = CreateFontIndirectA(&lf);
5300 hfont_prev = SelectObject(hdc, hfont);
5301 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5302 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5304 memset(&otm, 0, sizeof(otm));
5305 otm.otmSize = sizeof(otm);
5306 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5307 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5309 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5310 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5311 int offset;
5312 SHORT topSideBearing;
5314 if (!pGetGlyphIndicesW) {
5315 win_skip("GetGlyphIndices is not available on this platform\n");
5317 else {
5318 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5319 ok(ret != 0, "GetGlyphIndicesW failed\n");
5320 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5321 if (numOfLongVerMetrics > idx)
5322 offset = idx * 2 + 1;
5323 else
5324 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5325 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5326 &topSideBearing, sizeof(SHORT));
5327 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5328 topSideBearing = GET_BE_WORD(topSideBearing);
5329 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5330 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5331 "expected %d, got %d\n",
5332 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5335 else
5337 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5338 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5339 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5342 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
5343 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
5344 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5345 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
5347 DeleteObject(SelectObject(hdc, hfont_prev));
5348 ReleaseDC(NULL, hdc);
5351 static void test_vertical_font(void)
5353 char ttf_name[MAX_PATH];
5354 int num, i;
5355 BOOL ret, installed, selected;
5356 GLYPHMETRICS gm;
5357 WORD hgi, vgi;
5358 const char* face_list[] = {
5359 "@WineTestVertical", /* has vmtx table */
5360 "@Ume Gothic", /* doesn't have vmtx table */
5361 "@MS UI Gothic", /* has vmtx table, available on native */
5364 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
5366 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5367 return;
5370 if (!write_ttf_file("vertical.ttf", ttf_name))
5372 skip("Failed to create ttf file for testing\n");
5373 return;
5376 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
5377 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5379 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
5380 ok(installed, "WineTestVertical is not installed\n");
5381 ok(selected, "WineTestVertical is not selected\n");
5382 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5383 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5384 gm.gmBlackBoxX, gm.gmBlackBoxY);
5386 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
5387 ok(installed, "@WineTestVertical is not installed\n");
5388 ok(selected, "@WineTestVertical is not selected\n");
5389 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5390 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5391 gm.gmBlackBoxX, gm.gmBlackBoxY);
5393 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
5395 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
5396 const char* face = face_list[i];
5397 if (!is_truetype_font_installed(face)) {
5398 skip("%s is not installed\n", face);
5399 continue;
5401 trace("Testing %s...\n", face);
5402 check_vertical_metrics(&face[1]);
5405 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
5406 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5408 DeleteFileA(ttf_name);
5411 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
5412 DWORD type, LPARAM lParam)
5414 if (lf->lfFaceName[0] == '@') {
5415 return 0;
5417 return 1;
5420 static void test_east_asian_font_selection(void)
5422 HDC hdc;
5423 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
5424 GB2312_CHARSET, CHINESEBIG5_CHARSET };
5425 size_t i;
5427 hdc = GetDC(NULL);
5429 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
5431 LOGFONTA lf;
5432 HFONT hfont;
5433 char face_name[LF_FACESIZE];
5434 int ret;
5436 memset(&lf, 0, sizeof lf);
5437 lf.lfFaceName[0] = '\0';
5438 lf.lfCharSet = charset[i];
5440 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
5442 skip("Vertical font for charset %u is not installed\n", charset[i]);
5443 continue;
5446 hfont = CreateFontIndirectA(&lf);
5447 hfont = SelectObject(hdc, hfont);
5448 memset(face_name, 0, sizeof face_name);
5449 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5450 ok(ret && face_name[0] != '@',
5451 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
5452 DeleteObject(SelectObject(hdc, hfont));
5454 memset(&lf, 0, sizeof lf);
5455 strcpy(lf.lfFaceName, "@");
5456 lf.lfCharSet = charset[i];
5457 hfont = CreateFontIndirectA(&lf);
5458 hfont = SelectObject(hdc, hfont);
5459 memset(face_name, 0, sizeof face_name);
5460 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5461 ok(ret && face_name[0] == '@',
5462 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
5463 DeleteObject(SelectObject(hdc, hfont));
5465 ReleaseDC(NULL, hdc);
5468 static int get_font_dpi(const LOGFONTA *lf, int *height)
5470 HDC hdc = CreateCompatibleDC(0);
5471 HFONT hfont;
5472 TEXTMETRICA tm;
5473 int ret;
5475 hfont = CreateFontIndirectA(lf);
5476 ok(hfont != 0, "CreateFontIndirect failed\n");
5478 SelectObject(hdc, hfont);
5479 ret = GetTextMetricsA(hdc, &tm);
5480 ok(ret, "GetTextMetrics failed\n");
5481 ret = tm.tmDigitizedAspectX;
5482 if (height) *height = tm.tmHeight;
5484 DeleteDC(hdc);
5485 DeleteObject(hfont);
5487 return ret;
5490 static void test_stock_fonts(void)
5492 static const int font[] =
5494 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
5495 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5497 static const struct test_data
5499 int charset, weight, height, height_pixels, dpi;
5500 const char face_name[LF_FACESIZE];
5501 } td[][11] =
5503 { /* ANSI_FIXED_FONT */
5504 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
5505 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
5506 { 0 }
5508 { /* ANSI_VAR_FONT */
5509 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
5510 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
5511 { 0 }
5513 { /* SYSTEM_FONT */
5514 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5515 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5516 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5517 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5518 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5519 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5520 { 0 }
5522 { /* DEVICE_DEFAULT_FONT */
5523 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5524 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5525 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5526 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5527 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5528 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5529 { 0 }
5531 { /* DEFAULT_GUI_FONT */
5532 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
5533 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
5534 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
5535 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
5536 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
5537 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
5538 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
5539 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
5540 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5541 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
5542 { 0 }
5545 int i, j;
5547 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
5549 HFONT hfont;
5550 LOGFONTA lf;
5551 int ret, height;
5553 hfont = GetStockObject(font[i]);
5554 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
5556 ret = GetObjectA(hfont, sizeof(lf), &lf);
5557 if (ret != sizeof(lf))
5559 /* NT4 */
5560 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
5561 continue;
5564 for (j = 0; td[i][j].face_name[0] != 0; j++)
5566 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
5568 continue;
5571 ret = get_font_dpi(&lf, &height);
5572 if (ret != td[i][j].dpi)
5574 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5575 i, j, lf.lfFaceName, ret, td[i][j].dpi);
5576 continue;
5579 /* FIXME: Remove once Wine is fixed */
5580 if (td[i][j].dpi != 96 &&
5581 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5582 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
5583 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5584 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
5585 todo_wine
5586 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5587 else
5588 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
5590 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
5591 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
5592 if (td[i][j].face_name[0] == '?')
5594 /* Wine doesn't have this font, skip this case for now.
5595 Actually, the face name is localized on Windows and varies
5596 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5597 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
5599 else
5601 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);
5603 break;
5608 static void test_max_height(void)
5610 HDC hdc;
5611 LOGFONTA lf;
5612 HFONT hfont, hfont_old;
5613 TEXTMETRICA tm1, tm;
5614 BOOL r;
5615 LONG invalid_height[] = { -65536, -123456, 123456 };
5616 size_t i;
5618 memset(&tm1, 0, sizeof(tm1));
5619 memset(&lf, 0, sizeof(lf));
5620 strcpy(lf.lfFaceName, "Tahoma");
5621 lf.lfHeight = -1;
5623 hdc = GetDC(NULL);
5625 /* get 1 ppem value */
5626 hfont = CreateFontIndirectA(&lf);
5627 hfont_old = SelectObject(hdc, hfont);
5628 r = GetTextMetricsA(hdc, &tm1);
5629 ok(r, "GetTextMetrics failed\n");
5630 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5631 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
5632 DeleteObject(SelectObject(hdc, hfont_old));
5634 /* test the largest value */
5635 lf.lfHeight = -((1 << 16) - 1);
5636 hfont = CreateFontIndirectA(&lf);
5637 hfont_old = SelectObject(hdc, hfont);
5638 memset(&tm, 0, sizeof(tm));
5639 r = GetTextMetricsA(hdc, &tm);
5640 ok(r, "GetTextMetrics failed\n");
5641 ok(tm.tmHeight > tm1.tmHeight,
5642 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5643 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
5644 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5645 DeleteObject(SelectObject(hdc, hfont_old));
5647 /* test an invalid value */
5648 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
5649 lf.lfHeight = invalid_height[i];
5650 hfont = CreateFontIndirectA(&lf);
5651 hfont_old = SelectObject(hdc, hfont);
5652 memset(&tm, 0, sizeof(tm));
5653 r = GetTextMetricsA(hdc, &tm);
5654 ok(r, "GetTextMetrics failed\n");
5655 ok(tm.tmHeight == tm1.tmHeight,
5656 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
5657 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
5658 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
5659 DeleteObject(SelectObject(hdc, hfont_old));
5662 ReleaseDC(NULL, hdc);
5663 return;
5666 static void test_vertical_order(void)
5668 struct enum_font_data efd;
5669 LOGFONTA lf;
5670 HDC hdc;
5671 int i, j;
5673 hdc = CreateCompatibleDC(0);
5674 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5676 memset(&lf, 0, sizeof(lf));
5677 lf.lfCharSet = DEFAULT_CHARSET;
5678 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5679 lf.lfHeight = 16;
5680 lf.lfWidth = 16;
5681 lf.lfQuality = DEFAULT_QUALITY;
5682 lf.lfItalic = FALSE;
5683 lf.lfWeight = FW_DONTCARE;
5684 efd.total = 0;
5685 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
5686 for (i = 0; i < efd.total; i++)
5688 if (efd.lf[i].lfFaceName[0] != '@') continue;
5689 for (j = 0; j < efd.total; j++)
5691 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
5693 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
5694 break;
5698 DeleteDC( hdc );
5701 static void test_GetCharWidth32(void)
5703 BOOL ret;
5704 HDC hdc;
5705 LOGFONTA lf;
5706 HFONT hfont;
5707 INT bufferA;
5708 INT bufferW;
5709 HWND hwnd;
5711 if (!pGetCharWidth32A || !pGetCharWidth32W)
5713 win_skip("GetCharWidth32A/W not available on this platform\n");
5714 return;
5717 memset(&lf, 0, sizeof(lf));
5718 strcpy(lf.lfFaceName, "System");
5719 lf.lfHeight = 20;
5721 hfont = CreateFontIndirectA(&lf);
5722 hdc = GetDC(0);
5723 hfont = SelectObject(hdc, hfont);
5725 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5726 ok(ret, "GetCharWidth32W should have succeeded\n");
5727 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
5728 ok(ret, "GetCharWidth32A should have succeeded\n");
5729 ok (bufferA == bufferW, "Widths should be the same\n");
5730 ok (bufferA > 0," Width should be greater than zero\n");
5732 hfont = SelectObject(hdc, hfont);
5733 DeleteObject(hfont);
5734 ReleaseDC(NULL, hdc);
5736 memset(&lf, 0, sizeof(lf));
5737 strcpy(lf.lfFaceName, "Tahoma");
5738 lf.lfHeight = 20;
5740 hfont = CreateFontIndirectA(&lf);
5741 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
5742 0, 0, 0, NULL);
5743 hdc = GetDC(hwnd);
5744 SetMapMode( hdc, MM_ANISOTROPIC );
5745 SelectObject(hdc, hfont);
5747 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5748 ok(ret, "GetCharWidth32W should have succeeded\n");
5749 ok (bufferW > 0," Width should be greater than zero\n");
5750 SetWindowExtEx(hdc, -1,-1,NULL);
5751 SetGraphicsMode(hdc, GM_COMPATIBLE);
5752 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5753 ok(ret, "GetCharWidth32W should have succeeded\n");
5754 ok (bufferW > 0," Width should be greater than zero\n");
5755 SetGraphicsMode(hdc, GM_ADVANCED);
5756 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5757 ok(ret, "GetCharWidth32W should have succeeded\n");
5758 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
5759 SetWindowExtEx(hdc, 1,1,NULL);
5760 SetGraphicsMode(hdc, GM_COMPATIBLE);
5761 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5762 ok(ret, "GetCharWidth32W should have succeeded\n");
5763 ok (bufferW > 0," Width should be greater than zero\n");
5764 SetGraphicsMode(hdc, GM_ADVANCED);
5765 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5766 ok(ret, "GetCharWidth32W should have succeeded\n");
5767 ok (bufferW > 0," Width should be greater than zero\n");
5769 ReleaseDC(hwnd, hdc);
5770 DestroyWindow(hwnd);
5772 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
5773 0, 0, 0, NULL);
5774 hdc = GetDC(hwnd);
5775 SetMapMode( hdc, MM_ANISOTROPIC );
5776 SelectObject(hdc, hfont);
5778 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5779 ok(ret, "GetCharWidth32W should have succeeded\n");
5780 ok (bufferW > 0," Width should be greater than zero\n");
5781 SetWindowExtEx(hdc, -1,-1,NULL);
5782 SetGraphicsMode(hdc, GM_COMPATIBLE);
5783 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5784 ok(ret, "GetCharWidth32W should have succeeded\n");
5785 ok (bufferW > 0," Width should be greater than zero\n");
5786 SetGraphicsMode(hdc, GM_ADVANCED);
5787 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5788 ok(ret, "GetCharWidth32W should have succeeded\n");
5789 ok (bufferW > 0," Width should be greater than zero\n");
5790 SetWindowExtEx(hdc, 1,1,NULL);
5791 SetGraphicsMode(hdc, GM_COMPATIBLE);
5792 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5793 ok(ret, "GetCharWidth32W should have succeeded\n");
5794 ok (bufferW > 0," Width should be greater than zero\n");
5795 SetGraphicsMode(hdc, GM_ADVANCED);
5796 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
5797 ok(ret, "GetCharWidth32W should have succeeded\n");
5798 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
5800 ReleaseDC(hwnd, hdc);
5801 DestroyWindow(hwnd);
5802 DeleteObject(hfont);
5805 static void test_fake_bold_font(void)
5807 HDC hdc;
5808 HFONT hfont, hfont_old;
5809 LOGFONTA lf;
5810 BOOL ret;
5811 TEXTMETRICA tm[2];
5812 ABC abc[2];
5813 INT w[2];
5815 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
5816 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
5817 return;
5820 /* Test outline font */
5821 memset(&lf, 0, sizeof(lf));
5822 strcpy(lf.lfFaceName, "Wingdings");
5823 lf.lfWeight = FW_NORMAL;
5824 lf.lfCharSet = SYMBOL_CHARSET;
5825 hfont = CreateFontIndirectA(&lf);
5827 hdc = GetDC(NULL);
5828 hfont_old = SelectObject(hdc, hfont);
5830 /* base metrics */
5831 ret = GetTextMetricsA(hdc, &tm[0]);
5832 ok(ret, "got %d\n", ret);
5833 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[0]);
5834 ok(ret, "got %d\n", ret);
5836 lf.lfWeight = FW_BOLD;
5837 hfont = CreateFontIndirectA(&lf);
5838 DeleteObject(SelectObject(hdc, hfont));
5840 /* bold metrics */
5841 ret = GetTextMetricsA(hdc, &tm[1]);
5842 ok(ret, "got %d\n", ret);
5843 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[1]);
5844 ok(ret, "got %d\n", ret);
5846 DeleteObject(SelectObject(hdc, hfont_old));
5847 ReleaseDC(NULL, hdc);
5849 /* compare results (outline) */
5850 ok(tm[0].tmHeight == tm[1].tmHeight, "expected %d, got %d\n", tm[0].tmHeight, tm[1].tmHeight);
5851 ok(tm[0].tmAscent == tm[1].tmAscent, "expected %d, got %d\n", tm[0].tmAscent, tm[1].tmAscent);
5852 ok(tm[0].tmDescent == tm[1].tmDescent, "expected %d, got %d\n", tm[0].tmDescent, tm[1].tmDescent);
5853 ok((tm[0].tmAveCharWidth + 1) == tm[1].tmAveCharWidth,
5854 "expected %d, got %d\n", tm[0].tmAveCharWidth + 1, tm[1].tmAveCharWidth);
5855 ok((tm[0].tmMaxCharWidth + 1) == tm[1].tmMaxCharWidth,
5856 "expected %d, got %d\n", tm[0].tmMaxCharWidth + 1, tm[1].tmMaxCharWidth);
5857 ok(tm[0].tmOverhang == tm[1].tmOverhang, "expected %d, got %d\n", tm[0].tmOverhang, tm[1].tmOverhang);
5858 w[0] = abc[0].abcA + abc[0].abcB + abc[0].abcC;
5859 w[1] = abc[1].abcA + abc[1].abcB + abc[1].abcC;
5860 ok((w[0] + 1) == w[1], "expected %d, got %d\n", w[0] + 1, w[1]);
5864 static void test_bitmap_font_glyph_index(void)
5866 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
5867 const struct {
5868 LPCSTR face;
5869 BYTE charset;
5870 } bitmap_font_list[] = {
5871 { "Courier", ANSI_CHARSET },
5872 { "Small Fonts", ANSI_CHARSET },
5873 { "Fixedsys", DEFAULT_CHARSET },
5874 { "System", DEFAULT_CHARSET }
5876 HDC hdc;
5877 LOGFONTA lf;
5878 HFONT hFont;
5879 CHAR facename[LF_FACESIZE];
5880 BITMAPINFO bmi;
5881 HBITMAP hBmp[2];
5882 void *pixels[2];
5883 int i, j;
5884 DWORD ret;
5885 BITMAP bmp;
5886 TEXTMETRICA tm;
5887 CHARSETINFO ci;
5888 BYTE chr = '\xA9';
5890 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
5891 win_skip("GetGlyphIndices is unavailable\n");
5892 return;
5895 hdc = CreateCompatibleDC(0);
5896 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5898 memset(&bmi, 0, sizeof(bmi));
5899 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
5900 bmi.bmiHeader.biBitCount = 32;
5901 bmi.bmiHeader.biPlanes = 1;
5902 bmi.bmiHeader.biWidth = 128;
5903 bmi.bmiHeader.biHeight = 32;
5904 bmi.bmiHeader.biCompression = BI_RGB;
5906 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
5907 memset(&lf, 0, sizeof(lf));
5908 lf.lfCharSet = bitmap_font_list[i].charset;
5909 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
5910 hFont = CreateFontIndirectA(&lf);
5911 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
5912 hFont = SelectObject(hdc, hFont);
5913 ret = GetTextMetricsA(hdc, &tm);
5914 ok(ret, "GetTextMetric failed\n");
5915 ret = GetTextFaceA(hdc, sizeof(facename), facename);
5916 ok(ret, "GetTextFace failed\n");
5917 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
5918 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
5919 continue;
5921 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
5922 skip("expected %s, got %s\n", lf.lfFaceName, facename);
5923 continue;
5926 for (j = 0; j < 2; j++) {
5927 HBITMAP hBmpPrev;
5928 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
5929 ok(hBmp[j] != NULL, "Can't create DIB\n");
5930 hBmpPrev = SelectObject(hdc, hBmp[j]);
5931 switch (j) {
5932 case 0:
5933 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
5934 break;
5935 case 1:
5937 int len = lstrlenW(text);
5938 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
5939 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
5940 ok(ret, "GetGlyphIndices failed\n");
5941 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
5942 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
5943 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
5944 HeapFree(GetProcessHeap(), 0, indices);
5945 break;
5948 ok(ret, "ExtTextOutW failed\n");
5949 SelectObject(hdc, hBmpPrev);
5952 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
5953 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
5954 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5956 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
5957 if (!ret) {
5958 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5959 goto next;
5961 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
5962 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
5963 goto next;
5966 for (j = 0; j < 2; j++) {
5967 HBITMAP hBmpPrev;
5968 WORD code;
5969 hBmpPrev = SelectObject(hdc, hBmp[j]);
5970 switch (j) {
5971 case 0:
5972 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
5973 break;
5974 case 1:
5975 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
5976 ok(ret, "GetGlyphIndices failed\n");
5977 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
5978 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
5979 break;
5981 ok(ret, "ExtTextOutA failed\n");
5982 SelectObject(hdc, hBmpPrev);
5985 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
5986 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
5987 next:
5988 for (j = 0; j < 2; j++)
5989 DeleteObject(hBmp[j]);
5990 hFont = SelectObject(hdc, hFont);
5991 DeleteObject(hFont);
5994 DeleteDC(hdc);
5997 START_TEST(font)
5999 init();
6001 test_stock_fonts();
6002 test_logfont();
6003 test_bitmap_font();
6004 test_outline_font();
6005 test_bitmap_font_metrics();
6006 test_GdiGetCharDimensions();
6007 test_GetCharABCWidths();
6008 test_text_extents();
6009 test_GetGlyphIndices();
6010 test_GetKerningPairs();
6011 test_GetOutlineTextMetrics();
6012 test_SetTextJustification();
6013 test_font_charset();
6014 test_GdiGetCodePage();
6015 test_GetFontUnicodeRanges();
6016 test_nonexistent_font();
6017 test_orientation();
6018 test_height_selection();
6019 test_AddFontMemResource();
6020 test_EnumFonts();
6022 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6023 * I'd like to avoid them in this test.
6025 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6026 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6027 if (is_truetype_font_installed("Arial Black") &&
6028 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6030 test_EnumFontFamilies("", ANSI_CHARSET);
6031 test_EnumFontFamilies("", SYMBOL_CHARSET);
6032 test_EnumFontFamilies("", DEFAULT_CHARSET);
6034 else
6035 skip("Arial Black or Symbol/Wingdings is not installed\n");
6036 test_EnumFontFamiliesEx_default_charset();
6037 test_GetTextMetrics();
6038 test_GdiRealizationInfo();
6039 test_GetTextFace();
6040 test_GetGlyphOutline();
6041 test_GetTextMetrics2("Tahoma", -11);
6042 test_GetTextMetrics2("Tahoma", -55);
6043 test_GetTextMetrics2("Tahoma", -110);
6044 test_GetTextMetrics2("Arial", -11);
6045 test_GetTextMetrics2("Arial", -55);
6046 test_GetTextMetrics2("Arial", -110);
6047 test_CreateFontIndirect();
6048 test_CreateFontIndirectEx();
6049 test_oemcharset();
6050 test_fullname();
6051 test_fullname2();
6052 test_east_asian_font_selection();
6053 test_max_height();
6054 test_vertical_order();
6055 test_GetCharWidth32();
6056 test_fake_bold_font();
6057 test_bitmap_font_glyph_index();
6059 /* These tests should be last test until RemoveFontResource
6060 * is properly implemented.
6062 test_vertical_font();
6063 test_CreateScalableFontResource();