gdi32: Added GetFontRealizationInfo() export.
[wine.git] / dlls / gdi32 / tests / font.c
blob3757a8d319a02c0c6c1b93ce8222fd3f461a6e19
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);
58 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
59 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *);
60 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
62 static HMODULE hgdi32 = 0;
63 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
64 static WORD system_lang_id;
66 #ifdef WORDS_BIGENDIAN
67 #define GET_BE_WORD(x) (x)
68 #define GET_BE_DWORD(x) (x)
69 #else
70 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
71 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
72 #endif
74 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
75 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
76 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
77 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
78 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
79 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
81 static void init(void)
83 hgdi32 = GetModuleHandleA("gdi32.dll");
85 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
86 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
87 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
88 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
89 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
90 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
91 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
92 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
93 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
94 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
95 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
96 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
97 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
98 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
99 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
100 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
101 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
102 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
103 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
104 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
105 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
107 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
110 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
112 if (type != TRUETYPE_FONTTYPE) return 1;
114 return 0;
117 static BOOL is_truetype_font_installed(const char *name)
119 HDC hdc = GetDC(0);
120 BOOL ret = FALSE;
122 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
123 ret = TRUE;
125 ReleaseDC(0, hdc);
126 return ret;
129 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
131 return 0;
134 static BOOL is_font_installed(const char *name)
136 HDC hdc = GetDC(0);
137 BOOL ret = FALSE;
139 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
140 ret = TRUE;
142 ReleaseDC(0, hdc);
143 return ret;
146 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
148 HRSRC rsrc;
149 void *rsrc_data;
151 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
152 if (!rsrc) return NULL;
154 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
155 if (!rsrc_data) return NULL;
157 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
158 if (!*rsrc_size) return NULL;
160 return rsrc_data;
163 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
165 char tmp_path[MAX_PATH];
166 HANDLE hfile;
167 BOOL ret;
169 GetTempPathA(MAX_PATH, tmp_path);
170 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
172 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
173 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
175 ret = WriteFile(hfile, data, *size, size, NULL);
177 CloseHandle(hfile);
178 return ret;
181 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
183 void *rsrc_data;
184 DWORD rsrc_size;
186 rsrc_data = get_res_data( fontname, &rsrc_size );
187 if (!rsrc_data) return FALSE;
189 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
192 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
194 LOGFONTA getobj_lf;
195 int ret, minlen = 0;
197 if (!hfont)
198 return;
200 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
201 /* NT4 tries to be clever and only returns the minimum length */
202 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
203 minlen++;
204 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
205 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
206 ok(lf->lfHeight == getobj_lf.lfHeight ||
207 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
208 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
209 ok(lf->lfWidth == getobj_lf.lfWidth ||
210 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
211 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
212 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
213 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
214 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
215 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
216 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
217 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
218 ok(lf->lfWeight == getobj_lf.lfWeight ||
219 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
220 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
221 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
222 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
223 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
224 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
225 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
226 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
227 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
228 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
229 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
230 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
231 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
234 static HFONT create_font(const char* test, const LOGFONTA* lf)
236 HFONT hfont = CreateFontIndirectA(lf);
237 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
238 if (hfont)
239 check_font(test, lf, hfont);
240 return hfont;
243 static void test_logfont(void)
245 LOGFONTA lf;
246 HFONT hfont;
248 memset(&lf, 0, sizeof lf);
250 lf.lfCharSet = ANSI_CHARSET;
251 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
252 lf.lfWeight = FW_DONTCARE;
253 lf.lfHeight = 16;
254 lf.lfWidth = 16;
255 lf.lfQuality = DEFAULT_QUALITY;
257 lstrcpyA(lf.lfFaceName, "Arial");
258 hfont = create_font("Arial", &lf);
259 DeleteObject(hfont);
261 memset(&lf, 'A', sizeof(lf));
262 hfont = CreateFontIndirectA(&lf);
263 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
265 lf.lfFaceName[LF_FACESIZE - 1] = 0;
266 check_font("AAA...", &lf, hfont);
267 DeleteObject(hfont);
270 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
272 if (type & RASTER_FONTTYPE)
274 LOGFONTA *lf = (LOGFONTA *)lParam;
275 *lf = *elf;
276 return 0; /* stop enumeration */
279 return 1; /* continue enumeration */
282 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
284 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
285 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
286 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
287 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
288 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
289 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
290 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
291 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
292 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
293 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
294 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
295 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
296 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
297 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
298 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
299 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
300 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
301 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
302 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
303 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
306 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
307 LONG lfWidth, const char *test_str,
308 INT test_str_len, const TEXTMETRICA *tm_orig,
309 const SIZE *size_orig, INT width_of_A_orig,
310 INT scale_x, INT scale_y)
312 LOGFONTA lf;
313 OUTLINETEXTMETRICA otm;
314 TEXTMETRICA tm;
315 SIZE size;
316 INT width_of_A, cx, cy;
317 UINT ret;
319 if (!hfont)
320 return;
322 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
324 GetObjectA(hfont, sizeof(lf), &lf);
326 if (GetOutlineTextMetricsA(hdc, 0, NULL))
328 otm.otmSize = sizeof(otm) / 2;
329 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
330 ok(ret == sizeof(otm)/2 /* XP */ ||
331 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
333 memset(&otm, 0x1, sizeof(otm));
334 otm.otmSize = sizeof(otm);
335 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
336 ok(ret == sizeof(otm) /* XP */ ||
337 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
339 memset(&tm, 0x2, sizeof(tm));
340 ret = GetTextMetricsA(hdc, &tm);
341 ok(ret, "GetTextMetricsA failed\n");
342 /* the structure size is aligned */
343 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
345 ok(0, "tm != otm\n");
346 compare_tm(&tm, &otm.otmTextMetrics);
349 tm = otm.otmTextMetrics;
350 if (0) /* these metrics are scaled too, but with rounding errors */
352 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
353 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
355 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
356 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
357 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
358 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
359 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
360 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
362 else
364 ret = GetTextMetricsA(hdc, &tm);
365 ok(ret, "GetTextMetricsA failed\n");
368 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
369 cy = tm.tmHeight / tm_orig->tmHeight;
370 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
371 lfHeight, scale_x, scale_y, cx, cy);
372 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
373 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
374 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
375 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
376 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
378 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
379 if (lf.lfHeight)
381 if (lf.lfWidth)
382 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
384 else
385 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
387 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
389 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
390 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
392 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
394 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);
397 /* Test how GDI scales bitmap font metrics */
398 static void test_bitmap_font(void)
400 static const char test_str[11] = "Test String";
401 HDC hdc;
402 LOGFONTA bitmap_lf;
403 HFONT hfont, old_hfont;
404 TEXTMETRICA tm_orig;
405 SIZE size_orig;
406 INT ret, i, width_orig, height_orig, scale, lfWidth;
408 hdc = CreateCompatibleDC(0);
410 /* "System" has only 1 pixel size defined, otherwise the test breaks */
411 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
412 if (ret)
414 ReleaseDC(0, hdc);
415 trace("no bitmap fonts were found, skipping the test\n");
416 return;
419 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
421 height_orig = bitmap_lf.lfHeight;
422 lfWidth = bitmap_lf.lfWidth;
424 hfont = create_font("bitmap", &bitmap_lf);
425 old_hfont = SelectObject(hdc, hfont);
426 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
427 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
428 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
429 SelectObject(hdc, old_hfont);
430 DeleteObject(hfont);
432 bitmap_lf.lfHeight = 0;
433 bitmap_lf.lfWidth = 4;
434 hfont = create_font("bitmap", &bitmap_lf);
435 old_hfont = SelectObject(hdc, hfont);
436 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
437 SelectObject(hdc, old_hfont);
438 DeleteObject(hfont);
440 bitmap_lf.lfHeight = height_orig;
441 bitmap_lf.lfWidth = lfWidth;
443 /* test fractional scaling */
444 for (i = 1; i <= height_orig * 6; i++)
446 INT nearest_height;
448 bitmap_lf.lfHeight = i;
449 hfont = create_font("fractional", &bitmap_lf);
450 scale = (i + height_orig - 1) / height_orig;
451 nearest_height = scale * height_orig;
452 /* Only jump to the next height if the difference <= 25% original height */
453 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
454 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
455 so we'll not test this particular height. */
456 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
457 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
458 old_hfont = SelectObject(hdc, hfont);
459 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
460 SelectObject(hdc, old_hfont);
461 DeleteObject(hfont);
464 /* test integer scaling 3x2 */
465 bitmap_lf.lfHeight = height_orig * 2;
466 bitmap_lf.lfWidth *= 3;
467 hfont = create_font("3x2", &bitmap_lf);
468 old_hfont = SelectObject(hdc, hfont);
469 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
470 SelectObject(hdc, old_hfont);
471 DeleteObject(hfont);
473 /* test integer scaling 3x3 */
474 bitmap_lf.lfHeight = height_orig * 3;
475 bitmap_lf.lfWidth = 0;
476 hfont = create_font("3x3", &bitmap_lf);
477 old_hfont = SelectObject(hdc, hfont);
478 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
479 SelectObject(hdc, old_hfont);
480 DeleteObject(hfont);
482 DeleteDC(hdc);
485 /* Test how GDI scales outline font metrics */
486 static void test_outline_font(void)
488 static const char test_str[11] = "Test String";
489 HDC hdc, hdc_2;
490 LOGFONTA lf;
491 HFONT hfont, old_hfont, old_hfont_2;
492 OUTLINETEXTMETRICA otm;
493 SIZE size_orig;
494 INT width_orig, height_orig, lfWidth;
495 XFORM xform;
496 GLYPHMETRICS gm;
497 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
498 POINT pt;
499 INT ret;
501 if (!is_truetype_font_installed("Arial"))
503 skip("Arial is not installed\n");
504 return;
507 hdc = CreateCompatibleDC(0);
509 memset(&lf, 0, sizeof(lf));
510 strcpy(lf.lfFaceName, "Arial");
511 lf.lfHeight = 72;
512 hfont = create_font("outline", &lf);
513 old_hfont = SelectObject(hdc, hfont);
514 otm.otmSize = sizeof(otm);
515 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
516 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
517 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
519 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
520 SelectObject(hdc, old_hfont);
521 DeleteObject(hfont);
523 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
524 lf.lfHeight = otm.otmEMSquare;
525 lf.lfHeight = -lf.lfHeight;
526 hfont = create_font("outline", &lf);
527 old_hfont = SelectObject(hdc, hfont);
528 otm.otmSize = sizeof(otm);
529 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
530 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
531 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
532 SelectObject(hdc, old_hfont);
533 DeleteObject(hfont);
535 height_orig = otm.otmTextMetrics.tmHeight;
536 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
538 /* test integer scaling 3x2 */
539 lf.lfHeight = height_orig * 2;
540 lf.lfWidth = lfWidth * 3;
541 hfont = create_font("3x2", &lf);
542 old_hfont = SelectObject(hdc, hfont);
543 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
544 SelectObject(hdc, old_hfont);
545 DeleteObject(hfont);
547 /* test integer scaling 3x3 */
548 lf.lfHeight = height_orig * 3;
549 lf.lfWidth = lfWidth * 3;
550 hfont = create_font("3x3", &lf);
551 old_hfont = SelectObject(hdc, hfont);
552 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
553 SelectObject(hdc, old_hfont);
554 DeleteObject(hfont);
556 /* test integer scaling 1x1 */
557 lf.lfHeight = height_orig * 1;
558 lf.lfWidth = lfWidth * 1;
559 hfont = create_font("1x1", &lf);
560 old_hfont = SelectObject(hdc, hfont);
561 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
562 SelectObject(hdc, old_hfont);
563 DeleteObject(hfont);
565 /* test integer scaling 1x1 */
566 lf.lfHeight = height_orig;
567 lf.lfWidth = 0;
568 hfont = create_font("1x1", &lf);
569 old_hfont = SelectObject(hdc, hfont);
570 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
572 /* with an identity matrix */
573 memset(&gm, 0, sizeof(gm));
574 SetLastError(0xdeadbeef);
575 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
576 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
577 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
578 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
579 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
580 /* with a custom matrix */
581 memset(&gm, 0, sizeof(gm));
582 SetLastError(0xdeadbeef);
583 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
584 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
585 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
586 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
587 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
589 /* Test that changing the DC transformation affects only the font
590 * selected on this DC and doesn't affect the same font selected on
591 * another DC.
593 hdc_2 = CreateCompatibleDC(0);
594 old_hfont_2 = SelectObject(hdc_2, hfont);
595 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
597 SetMapMode(hdc, MM_ANISOTROPIC);
599 /* font metrics on another DC should be unchanged */
600 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
602 /* test restrictions of compatibility mode GM_COMPATIBLE */
603 /* part 1: rescaling only X should not change font scaling on screen.
604 So compressing the X axis by 2 is not done, and this
605 appears as X scaling of 2 that no one requested. */
606 SetWindowExtEx(hdc, 100, 100, NULL);
607 SetViewportExtEx(hdc, 50, 100, NULL);
608 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
609 /* font metrics on another DC should be unchanged */
610 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
612 /* part 2: rescaling only Y should change font scaling.
613 As also X is scaled by a factor of 2, but this is not
614 requested by the DC transformation, we get a scaling factor
615 of 2 in the X coordinate. */
616 SetViewportExtEx(hdc, 100, 200, NULL);
617 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 /* restore scaling */
622 SetMapMode(hdc, MM_TEXT);
624 /* font metrics on another DC should be unchanged */
625 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
627 SelectObject(hdc_2, old_hfont_2);
628 DeleteDC(hdc_2);
630 if (!SetGraphicsMode(hdc, GM_ADVANCED))
632 SelectObject(hdc, old_hfont);
633 DeleteObject(hfont);
634 DeleteDC(hdc);
635 skip("GM_ADVANCED is not supported on this platform\n");
636 return;
639 xform.eM11 = 20.0f;
640 xform.eM12 = 0.0f;
641 xform.eM21 = 0.0f;
642 xform.eM22 = 20.0f;
643 xform.eDx = 0.0f;
644 xform.eDy = 0.0f;
646 SetLastError(0xdeadbeef);
647 ret = SetWorldTransform(hdc, &xform);
648 ok(ret, "SetWorldTransform error %u\n", GetLastError());
650 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
652 /* with an identity matrix */
653 memset(&gm, 0, sizeof(gm));
654 SetLastError(0xdeadbeef);
655 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
656 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
657 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
658 pt.x = width_orig; pt.y = 0;
659 LPtoDP(hdc, &pt, 1);
660 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
661 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
662 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
663 /* with a custom matrix */
664 memset(&gm, 0, sizeof(gm));
665 SetLastError(0xdeadbeef);
666 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
667 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
668 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
669 pt.x = width_orig; pt.y = 0;
670 LPtoDP(hdc, &pt, 1);
671 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
672 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
673 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
675 SetLastError(0xdeadbeef);
676 ret = SetMapMode(hdc, MM_LOMETRIC);
677 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
679 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
681 /* with an identity matrix */
682 memset(&gm, 0, sizeof(gm));
683 SetLastError(0xdeadbeef);
684 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
685 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
686 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
687 pt.x = width_orig; pt.y = 0;
688 LPtoDP(hdc, &pt, 1);
689 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
690 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
691 /* with a custom matrix */
692 memset(&gm, 0, sizeof(gm));
693 SetLastError(0xdeadbeef);
694 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
695 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
696 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
697 pt.x = width_orig; pt.y = 0;
698 LPtoDP(hdc, &pt, 1);
699 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
700 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
702 SetLastError(0xdeadbeef);
703 ret = SetMapMode(hdc, MM_TEXT);
704 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
706 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
708 /* with an identity matrix */
709 memset(&gm, 0, sizeof(gm));
710 SetLastError(0xdeadbeef);
711 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
712 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
713 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
714 pt.x = width_orig; pt.y = 0;
715 LPtoDP(hdc, &pt, 1);
716 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
717 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
718 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
719 /* with a custom matrix */
720 memset(&gm, 0, sizeof(gm));
721 SetLastError(0xdeadbeef);
722 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
723 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
724 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
725 pt.x = width_orig; pt.y = 0;
726 LPtoDP(hdc, &pt, 1);
727 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
728 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
729 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
731 SelectObject(hdc, old_hfont);
732 DeleteObject(hfont);
733 DeleteDC(hdc);
736 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
738 LOGFONTA *lf = (LOGFONTA *)lParam;
740 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
742 *lf = *elf;
743 return 0; /* stop enumeration */
745 return 1; /* continue enumeration */
748 static BOOL is_CJK(void)
750 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
753 #define FH_SCALE 0x80000000
754 static void test_bitmap_font_metrics(void)
756 static const struct font_data
758 const char face_name[LF_FACESIZE];
759 int weight, height, ascent, descent, int_leading, ext_leading;
760 int ave_char_width, max_char_width, dpi;
761 BYTE first_char, last_char, def_char, break_char;
762 DWORD ansi_bitfield;
763 WORD skip_lang_id;
764 int scaled_height;
765 } fd[] =
767 { "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 },
768 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
769 { "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 },
770 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
771 { "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 },
772 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
773 { "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 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
775 { "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 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
778 { "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 },
779 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
780 { "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 },
781 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
782 { "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 },
783 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
784 { "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 },
785 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
786 { "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 },
787 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
789 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
790 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
791 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
792 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
793 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
794 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
795 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
796 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
797 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
798 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
799 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
800 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
801 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
802 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
803 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
804 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
806 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
807 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
808 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
809 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
812 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
813 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
814 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
815 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
816 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
817 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
819 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
820 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
821 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
822 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
823 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
824 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
825 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
826 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
827 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
828 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
829 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
830 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
831 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
832 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
833 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
834 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
835 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
837 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
838 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
839 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
840 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
841 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
842 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
843 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
844 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
845 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
846 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
847 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
849 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
850 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
851 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
853 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
854 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
855 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
857 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
858 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
859 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
861 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
862 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
864 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
865 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
866 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
867 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
868 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
869 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
870 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
871 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
872 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
873 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
874 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
875 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
876 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
877 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
878 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
879 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
880 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
881 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
882 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
883 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
884 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
886 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
887 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
888 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
889 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
890 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
891 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
892 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
893 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
894 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
895 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
896 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
897 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
899 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
900 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
901 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
903 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
905 /* FIXME: add "Terminal" */
907 static const int font_log_pixels[] = { 96, 120 };
908 HDC hdc;
909 LOGFONTA lf;
910 HFONT hfont, old_hfont;
911 TEXTMETRICA tm;
912 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
913 char face_name[LF_FACESIZE];
914 CHARSETINFO csi;
916 trace("system language id %04x\n", system_lang_id);
918 expected_cs = GetACP();
919 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
921 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
922 return;
924 expected_cs = csi.ciCharset;
925 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
927 hdc = CreateCompatibleDC(0);
928 assert(hdc);
930 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
931 GetDeviceCaps(hdc, LOGPIXELSY));
933 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
934 diff = 32768;
935 font_res = 0;
936 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
938 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
939 if (new_diff < diff)
941 diff = new_diff;
942 font_res = font_log_pixels[i];
945 trace("best font resolution is %d\n", font_res);
947 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
949 int bit, height;
951 memset(&lf, 0, sizeof(lf));
953 height = fd[i].height & ~FH_SCALE;
954 lf.lfHeight = height;
955 strcpy(lf.lfFaceName, fd[i].face_name);
957 for(bit = 0; bit < 32; bit++)
959 GLYPHMETRICS gm;
960 DWORD fs[2];
961 BOOL bRet;
963 fs[0] = 1L << bit;
964 fs[1] = 0;
965 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
966 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
968 lf.lfCharSet = csi.ciCharset;
969 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
970 if (fd[i].height & FH_SCALE)
971 ok(ret, "scaled font height %d should not be enumerated\n", height);
972 else
974 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
976 if (ret) /* FIXME: Remove once Wine is fixed */
977 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
978 else
979 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
982 if (ret && !(fd[i].height & FH_SCALE))
983 continue;
985 hfont = create_font(lf.lfFaceName, &lf);
986 old_hfont = SelectObject(hdc, hfont);
988 SetLastError(0xdeadbeef);
989 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
990 ok(ret, "GetTextFace error %u\n", GetLastError());
992 if (strcmp(face_name, fd[i].face_name) != 0)
994 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
995 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
996 SelectObject(hdc, old_hfont);
997 DeleteObject(hfont);
998 continue;
1001 memset(&gm, 0, sizeof(gm));
1002 SetLastError(0xdeadbeef);
1003 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1004 todo_wine {
1005 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1006 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1009 bRet = GetTextMetricsA(hdc, &tm);
1010 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1012 SetLastError(0xdeadbeef);
1013 ret = GetTextCharset(hdc);
1014 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1015 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1016 else
1017 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1019 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1020 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1022 if(fd[i].dpi == tm.tmDigitizedAspectX)
1024 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1025 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
1027 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1028 if (fd[i].height & FH_SCALE)
1029 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);
1030 else
1031 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);
1032 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1033 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1034 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);
1035 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);
1036 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);
1037 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1038 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1039 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1040 make default char test fail */
1041 if (tm.tmCharSet == lf.lfCharSet)
1042 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1043 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1044 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);
1046 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1047 that make the max width bigger */
1048 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1049 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);
1051 else
1052 skip("Skipping font metrics test for system langid 0x%x\n",
1053 system_lang_id);
1055 SelectObject(hdc, old_hfont);
1056 DeleteObject(hfont);
1060 DeleteDC(hdc);
1063 static void test_GdiGetCharDimensions(void)
1065 HDC hdc;
1066 TEXTMETRICW tm;
1067 LONG ret;
1068 SIZE size;
1069 LONG avgwidth, height;
1070 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1072 if (!pGdiGetCharDimensions)
1074 win_skip("GdiGetCharDimensions not available on this platform\n");
1075 return;
1078 hdc = CreateCompatibleDC(NULL);
1080 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1081 avgwidth = ((size.cx / 26) + 1) / 2;
1083 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1084 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1085 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1087 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1088 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1090 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1091 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1093 height = 0;
1094 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1095 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1096 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1098 DeleteDC(hdc);
1101 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1102 const TEXTMETRICA *lpntme,
1103 DWORD FontType, LPARAM lParam)
1105 if (FontType & TRUETYPE_FONTTYPE)
1107 HFONT hfont;
1109 hfont = CreateFontIndirectA(lpelfe);
1110 if (hfont)
1112 *(HFONT *)lParam = hfont;
1113 return 0;
1117 return 1;
1120 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1122 ABC abc[1];
1123 ABCFLOAT abcf[1];
1124 BOOL ret = FALSE;
1126 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1127 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1128 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1129 if (todo) todo_wine ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1130 else ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1131 if (todo) todo_wine ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1132 else ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1134 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1135 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1136 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1137 if (todo) todo_wine ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1138 else ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1139 if (todo) todo_wine ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1140 else ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's should be unchanged\n", description);
1142 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1143 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1144 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1145 if (todo) todo_wine ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1146 else ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's should be unchanged\n", description);
1147 if (todo) todo_wine ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1148 else ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1151 static void test_GetCharABCWidths(void)
1153 static const WCHAR str[] = {'i',0};
1154 BOOL ret;
1155 HDC hdc;
1156 LOGFONTA lf;
1157 HFONT hfont;
1158 ABC abc[1];
1159 ABC abcw[1];
1160 ABCFLOAT abcf[1];
1161 WORD glyphs[1];
1162 DWORD nb;
1163 HWND hwnd;
1164 static const struct
1166 UINT first;
1167 UINT last;
1168 } range[] =
1170 {0xff, 0xff},
1171 {0x100, 0x100},
1172 {0xff, 0x100},
1173 {0x1ff, 0xff00},
1174 {0xffff, 0xffff},
1175 {0x10000, 0x10000},
1176 {0xffff, 0x10000},
1177 {0xffffff, 0xffffff},
1178 {0x1000000, 0x1000000},
1179 {0xffffff, 0x1000000},
1180 {0xffffffff, 0xffffffff},
1181 {0x00, 0xff}
1183 static const struct
1185 UINT cs;
1186 UINT a;
1187 UINT w;
1188 BOOL r[sizeof range / sizeof range[0]];
1189 } c[] =
1191 {ANSI_CHARSET, 0x30, 0x30,
1192 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1193 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1194 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1195 {HANGEUL_CHARSET, 0x8141, 0xac02,
1196 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1197 {GB2312_CHARSET, 0x8141, 0x4e04,
1198 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1199 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1200 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1202 UINT i;
1204 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1206 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1207 return;
1210 memset(&lf, 0, sizeof(lf));
1211 strcpy(lf.lfFaceName, "System");
1212 lf.lfHeight = 20;
1214 hfont = CreateFontIndirectA(&lf);
1215 hdc = GetDC(0);
1216 hfont = SelectObject(hdc, hfont);
1218 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1219 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1221 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1222 ok(!ret, "GetCharABCWidthsI should have failed\n");
1224 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1225 ok(!ret, "GetCharABCWidthsI should have failed\n");
1227 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1228 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1230 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1231 ok(!ret, "GetCharABCWidthsW should have failed\n");
1233 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1234 ok(!ret, "GetCharABCWidthsW should have failed\n");
1236 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1237 ok(!ret, "GetCharABCWidthsW should have failed\n");
1239 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1240 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1242 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1243 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1245 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1246 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1248 hfont = SelectObject(hdc, hfont);
1249 DeleteObject(hfont);
1251 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1253 ABC a[2], w[2];
1254 ABC full[256];
1255 UINT code = 0x41, j;
1257 lf.lfFaceName[0] = '\0';
1258 lf.lfCharSet = c[i].cs;
1259 lf.lfPitchAndFamily = 0;
1260 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1262 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1263 continue;
1266 memset(a, 0, sizeof a);
1267 memset(w, 0, sizeof w);
1268 hfont = SelectObject(hdc, hfont);
1269 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1270 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1271 memcmp(a, w, sizeof a) == 0,
1272 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1274 memset(a, 0xbb, sizeof a);
1275 ret = pGetCharABCWidthsA(hdc, code, code, a);
1276 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1277 memset(full, 0xcc, sizeof full);
1278 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1279 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1280 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1281 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1283 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1285 memset(full, 0xdd, sizeof full);
1286 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1287 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1288 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1289 if (ret)
1291 UINT last = range[j].last - range[j].first;
1292 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1293 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1294 "GetCharABCWidthsA %x should match. codepage = %u\n",
1295 range[j].last, c[i].cs);
1299 hfont = SelectObject(hdc, hfont);
1300 DeleteObject(hfont);
1303 memset(&lf, 0, sizeof(lf));
1304 strcpy(lf.lfFaceName, "Tahoma");
1305 lf.lfHeight = 200;
1306 hfont = CreateFontIndirectA(&lf);
1308 /* test empty glyph's metrics */
1309 hfont = SelectObject(hdc, hfont);
1310 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1311 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1312 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1313 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1314 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1315 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1317 /* 1) prepare unrotated font metrics */
1318 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1319 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1320 DeleteObject(SelectObject(hdc, hfont));
1322 /* 2) get rotated font metrics */
1323 lf.lfEscapement = lf.lfOrientation = 900;
1324 hfont = CreateFontIndirectA(&lf);
1325 hfont = SelectObject(hdc, hfont);
1326 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1327 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1329 /* 3) compare ABC results */
1330 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1331 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1332 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1333 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1334 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1335 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1337 DeleteObject(SelectObject(hdc, hfont));
1338 ReleaseDC(NULL, hdc);
1340 trace("ABC sign test for a variety of transforms:\n");
1341 memset(&lf, 0, sizeof(lf));
1342 strcpy(lf.lfFaceName, "Tahoma");
1343 lf.lfHeight = 20;
1344 hfont = CreateFontIndirectA(&lf);
1345 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1346 0, 0, 0, NULL);
1347 hdc = GetDC(hwnd);
1348 SetMapMode(hdc, MM_ANISOTROPIC);
1349 SelectObject(hdc, hfont);
1351 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1352 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1354 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1355 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1356 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1357 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1358 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1359 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1361 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1362 SetWindowExtEx(hdc, -1, -1, NULL);
1363 SetGraphicsMode(hdc, GM_COMPATIBLE);
1364 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1365 SetGraphicsMode(hdc, GM_ADVANCED);
1366 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1367 SetWindowExtEx(hdc, 1, 1, NULL);
1368 SetGraphicsMode(hdc, GM_COMPATIBLE);
1369 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1370 SetGraphicsMode(hdc, GM_ADVANCED);
1371 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1373 ReleaseDC(hwnd, hdc);
1374 DestroyWindow(hwnd);
1376 trace("RTL layout\n");
1377 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1378 0, 0, 0, NULL);
1379 hdc = GetDC(hwnd);
1380 SetMapMode(hdc, MM_ANISOTROPIC);
1381 SelectObject(hdc, hfont);
1383 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1384 SetWindowExtEx(hdc, -1, -1, NULL);
1385 SetGraphicsMode(hdc, GM_COMPATIBLE);
1386 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1387 SetGraphicsMode(hdc, GM_ADVANCED);
1388 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1389 SetWindowExtEx(hdc, 1, 1, NULL);
1390 SetGraphicsMode(hdc, GM_COMPATIBLE);
1391 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1392 SetGraphicsMode(hdc, GM_ADVANCED);
1393 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1395 ReleaseDC(hwnd, hdc);
1396 DestroyWindow(hwnd);
1397 DeleteObject(hfont);
1400 static void test_text_extents(void)
1402 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1403 LPINT extents;
1404 INT i, len, fit1, fit2, extents2[3];
1405 LOGFONTA lf;
1406 TEXTMETRICA tm;
1407 HDC hdc;
1408 HFONT hfont;
1409 SIZE sz;
1410 SIZE sz1, sz2;
1411 BOOL ret;
1413 memset(&lf, 0, sizeof(lf));
1414 strcpy(lf.lfFaceName, "Arial");
1415 lf.lfHeight = 20;
1417 hfont = CreateFontIndirectA(&lf);
1418 hdc = GetDC(0);
1419 hfont = SelectObject(hdc, hfont);
1420 GetTextMetricsA(hdc, &tm);
1421 GetTextExtentPointA(hdc, "o", 1, &sz);
1422 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1424 SetLastError(0xdeadbeef);
1425 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1426 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1428 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1429 hfont = SelectObject(hdc, hfont);
1430 DeleteObject(hfont);
1431 ReleaseDC(0, hdc);
1432 return;
1435 len = lstrlenW(wt);
1436 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1437 extents[0] = 1; /* So that the increasing sequence test will fail
1438 if the extents array is untouched. */
1439 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1440 GetTextExtentPointW(hdc, wt, len, &sz2);
1441 ok(sz1.cy == sz2.cy,
1442 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1443 /* Because of the '\n' in the string GetTextExtentExPoint and
1444 GetTextExtentPoint return different widths under Win2k, but
1445 under WinXP they return the same width. So we don't test that
1446 here. */
1448 for (i = 1; i < len; ++i)
1449 ok(extents[i-1] <= extents[i],
1450 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1452 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1453 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1454 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1455 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1456 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1457 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1458 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1459 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1460 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1461 ok(extents[0] == extents[2] && extents[1] == extents[3],
1462 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1463 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1464 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1465 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1467 /* extents functions fail with -ve counts (the interesting case being -1) */
1468 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1469 ok(ret == FALSE, "got %d\n", ret);
1470 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1471 ok(ret == FALSE, "got %d\n", ret);
1472 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1473 ok(ret == FALSE, "got %d\n", ret);
1475 /* max_extent = 0 succeeds and returns zero */
1476 fit1 = fit2 = -215;
1477 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1478 ok(ret == TRUE ||
1479 broken(ret == FALSE), /* NT4, 2k */
1480 "got %d\n", ret);
1481 ok(fit1 == 0 ||
1482 broken(fit1 == -215), /* NT4, 2k */
1483 "fit = %d\n", fit1);
1484 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1485 ok(ret == TRUE, "got %d\n", ret);
1486 ok(fit2 == 0, "fit = %d\n", fit2);
1488 /* max_extent = -1 is interpreted as a very large width that will
1489 * definitely fit our three characters */
1490 fit1 = fit2 = -215;
1491 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1492 ok(ret == TRUE, "got %d\n", ret);
1493 ok(fit1 == 3, "fit = %d\n", fit1);
1494 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1495 ok(ret == TRUE, "got %d\n", ret);
1496 ok(fit2 == 3, "fit = %d\n", fit2);
1498 /* max_extent = -2 is interpreted similarly, but the Ansi version
1499 * rejects it while the Unicode one accepts it */
1500 fit1 = fit2 = -215;
1501 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1502 ok(ret == FALSE, "got %d\n", ret);
1503 ok(fit1 == -215, "fit = %d\n", fit1);
1504 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1505 ok(ret == TRUE, "got %d\n", ret);
1506 ok(fit2 == 3, "fit = %d\n", fit2);
1508 hfont = SelectObject(hdc, hfont);
1509 DeleteObject(hfont);
1511 /* non-MM_TEXT mapping mode */
1512 lf.lfHeight = 2000;
1513 hfont = CreateFontIndirectA(&lf);
1514 hfont = SelectObject(hdc, hfont);
1516 SetMapMode( hdc, MM_HIMETRIC );
1517 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1518 ok(ret, "got %d\n", ret);
1519 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1521 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1522 ok(ret, "got %d\n", ret);
1523 ok(fit1 == 2, "got %d\n", fit1);
1524 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1525 for(i = 0; i < 2; i++)
1526 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1528 hfont = SelectObject(hdc, hfont);
1529 DeleteObject(hfont);
1530 HeapFree(GetProcessHeap(), 0, extents);
1531 ReleaseDC(NULL, hdc);
1534 static void test_GetGlyphIndices(void)
1536 HDC hdc;
1537 HFONT hfont;
1538 DWORD charcount;
1539 LOGFONTA lf;
1540 DWORD flags = 0;
1541 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1542 WORD glyphs[(sizeof(testtext)/2)-1];
1543 TEXTMETRICA textm;
1544 HFONT hOldFont;
1546 if (!pGetGlyphIndicesW) {
1547 win_skip("GetGlyphIndicesW not available on platform\n");
1548 return;
1551 hdc = GetDC(0);
1553 memset(&lf, 0, sizeof(lf));
1554 strcpy(lf.lfFaceName, "System");
1555 lf.lfHeight = 16;
1556 lf.lfCharSet = ANSI_CHARSET;
1558 hfont = CreateFontIndirectA(&lf);
1559 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1560 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1561 if (textm.tmCharSet == ANSI_CHARSET)
1563 flags |= GGI_MARK_NONEXISTING_GLYPHS;
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] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1567 flags = 0;
1568 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1569 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1570 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1571 textm.tmDefaultChar, glyphs[4]);
1573 else
1574 /* FIXME: Write tests for non-ANSI charsets. */
1575 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1577 if(!is_font_installed("Tahoma"))
1579 skip("Tahoma is not installed so skipping this test\n");
1580 return;
1582 memset(&lf, 0, sizeof(lf));
1583 strcpy(lf.lfFaceName, "Tahoma");
1584 lf.lfHeight = 20;
1586 hfont = CreateFontIndirectA(&lf);
1587 hOldFont = SelectObject(hdc, hfont);
1588 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1589 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1590 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1591 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1592 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1593 flags = 0;
1594 testtext[0] = textm.tmDefaultChar;
1595 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1596 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1597 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1598 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1599 DeleteObject(SelectObject(hdc, hOldFont));
1602 static void test_GetKerningPairs(void)
1604 static const struct kerning_data
1606 const char face_name[LF_FACESIZE];
1607 LONG height;
1608 /* some interesting fields from OUTLINETEXTMETRIC */
1609 LONG tmHeight, tmAscent, tmDescent;
1610 UINT otmEMSquare;
1611 INT otmAscent;
1612 INT otmDescent;
1613 UINT otmLineGap;
1614 UINT otmsCapEmHeight;
1615 UINT otmsXHeight;
1616 INT otmMacAscent;
1617 INT otmMacDescent;
1618 UINT otmMacLineGap;
1619 UINT otmusMinimumPPEM;
1620 /* small subset of kerning pairs to test */
1621 DWORD total_kern_pairs;
1622 const KERNINGPAIR kern_pair[26];
1623 } kd[] =
1625 {"Arial", 12, 12, 9, 3,
1626 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1629 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1630 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1631 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1632 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1633 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1634 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1635 {933,970,+1},{933,972,-1}
1638 {"Arial", -34, 39, 32, 7,
1639 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1642 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1643 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1644 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1645 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1646 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1647 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1648 {933,970,+2},{933,972,-3}
1651 { "Arial", 120, 120, 97, 23,
1652 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1655 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1656 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1657 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1658 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1659 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1660 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1661 {933,970,+6},{933,972,-10}
1664 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1665 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1666 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1669 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1670 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1671 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1672 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1673 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1674 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1675 {933,970,+54},{933,972,-83}
1678 #endif
1680 LOGFONTA lf;
1681 HFONT hfont, hfont_old;
1682 KERNINGPAIR *kern_pair;
1683 HDC hdc;
1684 DWORD total_kern_pairs, ret, i, n, matches;
1686 hdc = GetDC(0);
1688 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1689 * which may render this test unusable, so we're trying to avoid that.
1691 SetLastError(0xdeadbeef);
1692 GetKerningPairsW(hdc, 0, NULL);
1693 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1695 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1696 ReleaseDC(0, hdc);
1697 return;
1700 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1702 OUTLINETEXTMETRICW otm;
1703 UINT uiRet;
1705 if (!is_font_installed(kd[i].face_name))
1707 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1708 continue;
1711 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1713 memset(&lf, 0, sizeof(lf));
1714 strcpy(lf.lfFaceName, kd[i].face_name);
1715 lf.lfHeight = kd[i].height;
1716 hfont = CreateFontIndirectA(&lf);
1717 assert(hfont != 0);
1719 hfont_old = SelectObject(hdc, hfont);
1721 SetLastError(0xdeadbeef);
1722 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1723 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1724 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1726 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1727 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1728 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1729 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1730 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1731 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1733 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1734 kd[i].otmEMSquare, otm.otmEMSquare);
1735 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1736 kd[i].otmAscent, otm.otmAscent);
1737 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1738 kd[i].otmDescent, otm.otmDescent);
1739 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1740 kd[i].otmLineGap, otm.otmLineGap);
1741 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1742 kd[i].otmMacDescent, otm.otmMacDescent);
1743 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1744 kd[i].otmMacAscent, otm.otmMacAscent);
1745 todo_wine {
1746 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1747 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1748 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1749 kd[i].otmsXHeight, otm.otmsXHeight);
1750 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1751 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1752 kd[i].otmMacLineGap, otm.otmMacLineGap);
1753 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1754 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1757 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1758 trace("total_kern_pairs %u\n", total_kern_pairs);
1759 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1761 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1762 * passes on XP.
1764 SetLastError(0xdeadbeef);
1765 ret = GetKerningPairsW(hdc, 0, kern_pair);
1766 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1767 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1768 ok(ret == 0, "got %u, expected 0\n", ret);
1770 ret = GetKerningPairsW(hdc, 100, NULL);
1771 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1773 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1774 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1776 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1777 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1779 matches = 0;
1781 for (n = 0; n < ret; n++)
1783 DWORD j;
1784 /* Disabled to limit console spam */
1785 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1786 trace("{'%c','%c',%d},\n",
1787 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1788 for (j = 0; j < kd[i].total_kern_pairs; j++)
1790 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1791 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1793 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1794 "pair %d:%d got %d, expected %d\n",
1795 kern_pair[n].wFirst, kern_pair[n].wSecond,
1796 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1797 matches++;
1802 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1803 matches, kd[i].total_kern_pairs);
1805 HeapFree(GetProcessHeap(), 0, kern_pair);
1807 SelectObject(hdc, hfont_old);
1808 DeleteObject(hfont);
1811 ReleaseDC(0, hdc);
1814 struct font_data
1816 const char face_name[LF_FACESIZE];
1817 int requested_height;
1818 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1819 BOOL exact;
1822 static void test_height( HDC hdc, const struct font_data *fd )
1824 LOGFONTA lf;
1825 HFONT hfont, old_hfont;
1826 TEXTMETRICA tm;
1827 INT ret, i;
1829 for (i = 0; fd[i].face_name[0]; i++)
1831 if (!is_truetype_font_installed(fd[i].face_name))
1833 skip("%s is not installed\n", fd[i].face_name);
1834 continue;
1837 memset(&lf, 0, sizeof(lf));
1838 lf.lfHeight = fd[i].requested_height;
1839 lf.lfWeight = fd[i].weight;
1840 strcpy(lf.lfFaceName, fd[i].face_name);
1842 hfont = CreateFontIndirectA(&lf);
1843 assert(hfont);
1845 old_hfont = SelectObject(hdc, hfont);
1846 ret = GetTextMetricsA(hdc, &tm);
1847 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1848 if(fd[i].dpi == tm.tmDigitizedAspectX)
1850 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);
1851 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);
1852 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);
1853 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);
1854 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);
1855 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);
1858 SelectObject(hdc, old_hfont);
1859 /* force GDI to use new font, otherwise Windows leaks the font reference */
1860 GetTextMetricsA(hdc, &tm);
1861 DeleteObject(hfont);
1865 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1867 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1868 DWORD *table = (DWORD *)ttf + 3;
1870 for (i = 0; i < num_tables; i++)
1872 if (table[0] == tag)
1873 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1874 table += 4;
1876 return NULL;
1879 static void test_height_selection_vdmx( HDC hdc )
1881 static const struct font_data charset_0[] = /* doesn't use VDMX */
1883 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1884 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1885 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1886 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1887 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1888 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1889 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1890 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1891 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1892 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1893 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1894 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1895 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1896 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1897 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1898 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1899 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1900 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1901 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1902 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1903 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1904 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1905 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1906 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1907 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1908 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1909 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1910 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1911 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1912 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1913 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1914 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1915 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1916 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1917 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1918 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1919 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1920 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1921 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1922 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1923 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1924 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1925 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1926 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1927 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1928 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1929 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1930 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1931 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1932 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1933 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1934 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1935 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1938 static const struct font_data charset_1[] = /* Uses VDMX */
1940 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1941 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1942 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1943 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1944 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1945 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1946 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1947 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1948 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1949 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1950 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1951 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1952 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1953 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1954 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1955 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1956 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1957 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1958 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1959 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1960 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1961 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1962 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1963 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
1964 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
1965 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
1966 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1967 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1968 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1969 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1970 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1971 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1972 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1973 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1974 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1975 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1976 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1977 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1978 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1979 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1980 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1981 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
1982 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
1983 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
1984 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
1985 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
1986 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
1987 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
1988 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
1989 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
1990 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
1991 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
1992 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1995 static const struct vdmx_data
1997 WORD version;
1998 BYTE bCharSet;
1999 const struct font_data *fd;
2000 } data[] =
2002 { 0, 0, charset_0 },
2003 { 0, 1, charset_1 },
2004 { 1, 0, charset_0 },
2005 { 1, 1, charset_1 }
2007 int i;
2008 DWORD size, num;
2009 WORD *vdmx_header;
2010 BYTE *ratio_rec;
2011 char ttf_name[MAX_PATH];
2012 void *res, *copy;
2013 BOOL ret;
2015 if (!pAddFontResourceExA)
2017 win_skip("AddFontResourceExA unavailable\n");
2018 return;
2021 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2023 res = get_res_data( "wine_vdmx.ttf", &size );
2025 copy = HeapAlloc( GetProcessHeap(), 0, size );
2026 memcpy( copy, res, size );
2027 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2028 vdmx_header[0] = GET_BE_WORD( data[i].version );
2029 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2030 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2031 ratio_rec = (BYTE *)&vdmx_header[3];
2032 ratio_rec[0] = data[i].bCharSet;
2034 write_tmp_file( copy, &size, ttf_name );
2035 HeapFree( GetProcessHeap(), 0, copy );
2037 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2038 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2039 if (!num) win_skip("Unable to add ttf font resource\n");
2040 else
2042 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2043 test_height( hdc, data[i].fd );
2044 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2046 ret = DeleteFileA( ttf_name );
2047 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2048 "DeleteFile error %d\n", GetLastError());
2052 static void test_height_selection(void)
2054 static const struct font_data tahoma[] =
2056 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2057 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2058 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2059 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2060 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2061 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2062 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2063 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2064 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2065 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2066 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2068 HDC hdc = CreateCompatibleDC(0);
2069 assert(hdc);
2071 test_height( hdc, tahoma );
2072 test_height_selection_vdmx( hdc );
2074 DeleteDC(hdc);
2077 static void test_GetOutlineTextMetrics(void)
2079 OUTLINETEXTMETRICA *otm;
2080 LOGFONTA lf;
2081 HFONT hfont, hfont_old;
2082 HDC hdc;
2083 DWORD ret, otm_size;
2084 LPSTR unset_ptr;
2086 if (!is_font_installed("Arial"))
2088 skip("Arial is not installed\n");
2089 return;
2092 hdc = GetDC(0);
2094 memset(&lf, 0, sizeof(lf));
2095 strcpy(lf.lfFaceName, "Arial");
2096 lf.lfHeight = -13;
2097 lf.lfWeight = FW_NORMAL;
2098 lf.lfPitchAndFamily = DEFAULT_PITCH;
2099 lf.lfQuality = PROOF_QUALITY;
2100 hfont = CreateFontIndirectA(&lf);
2101 assert(hfont != 0);
2103 hfont_old = SelectObject(hdc, hfont);
2104 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2105 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2107 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2109 memset(otm, 0xAA, otm_size);
2110 SetLastError(0xdeadbeef);
2111 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2112 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2113 ok(ret == 1 /* Win9x */ ||
2114 ret == otm->otmSize /* XP*/,
2115 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2116 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2118 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2119 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2120 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2121 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2124 memset(otm, 0xAA, otm_size);
2125 SetLastError(0xdeadbeef);
2126 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2127 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2128 ok(ret == 1 /* Win9x */ ||
2129 ret == otm->otmSize /* XP*/,
2130 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2131 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2133 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2134 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2135 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2136 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2139 /* ask about truncated data */
2140 memset(otm, 0xAA, otm_size);
2141 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2142 SetLastError(0xdeadbeef);
2143 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2144 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2145 ok(ret == 1 /* Win9x */ ||
2146 ret == otm->otmSize /* XP*/,
2147 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2148 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2150 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2151 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2152 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2154 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2156 /* check handling of NULL pointer */
2157 SetLastError(0xdeadbeef);
2158 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2159 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2161 HeapFree(GetProcessHeap(), 0, otm);
2163 SelectObject(hdc, hfont_old);
2164 DeleteObject(hfont);
2166 ReleaseDC(0, hdc);
2169 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2171 INT y,
2172 breakCount,
2173 areaWidth = clientArea->right - clientArea->left,
2174 nErrors = 0, e;
2175 const char *pFirstChar, *pLastChar;
2176 SIZE size;
2177 TEXTMETRICA tm;
2178 struct err
2180 const char *start;
2181 int len;
2182 int GetTextExtentExPointWWidth;
2183 } error[20];
2185 GetTextMetricsA(hdc, &tm);
2186 y = clientArea->top;
2187 do {
2188 breakCount = 0;
2189 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2190 pFirstChar = str;
2192 do {
2193 pLastChar = str;
2195 /* if not at the end of the string, ... */
2196 if (*str == '\0') break;
2197 /* ... add the next word to the current extent */
2198 while (*str != '\0' && *str++ != tm.tmBreakChar);
2199 breakCount++;
2200 SetTextJustification(hdc, 0, 0);
2201 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2202 } while ((int) size.cx < areaWidth);
2204 /* ignore trailing break chars */
2205 breakCount--;
2206 while (*(pLastChar - 1) == tm.tmBreakChar)
2208 pLastChar--;
2209 breakCount--;
2212 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2214 SetTextJustification(hdc, 0, 0);
2215 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2217 /* do not justify the last extent */
2218 if (*str != '\0' && breakCount > 0)
2220 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2221 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2222 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2224 error[nErrors].start = pFirstChar;
2225 error[nErrors].len = pLastChar - pFirstChar;
2226 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2227 nErrors++;
2231 y += size.cy;
2232 str = pLastChar;
2233 } while (*str && y < clientArea->bottom);
2235 for (e = 0; e < nErrors; e++)
2237 /* The width returned by GetTextExtentPoint32() is exactly the same
2238 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2239 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2240 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2241 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2245 static void test_SetTextJustification(void)
2247 HDC hdc;
2248 RECT clientArea;
2249 LOGFONTA lf;
2250 HFONT hfont;
2251 HWND hwnd;
2252 SIZE size, expect;
2253 int i;
2254 WORD indices[2];
2255 static const char testText[] =
2256 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2257 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2258 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2259 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2260 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2261 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2262 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2264 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2265 GetClientRect( hwnd, &clientArea );
2266 hdc = GetDC( hwnd );
2268 if (!is_font_installed("Times New Roman"))
2270 skip("Times New Roman is not installed\n");
2271 return;
2274 memset(&lf, 0, sizeof lf);
2275 lf.lfCharSet = ANSI_CHARSET;
2276 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2277 lf.lfWeight = FW_DONTCARE;
2278 lf.lfHeight = 20;
2279 lf.lfQuality = DEFAULT_QUALITY;
2280 lstrcpyA(lf.lfFaceName, "Times New Roman");
2281 hfont = create_font("Times New Roman", &lf);
2282 SelectObject(hdc, hfont);
2284 testJustification(hdc, testText, &clientArea);
2286 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2287 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2289 SetTextJustification(hdc, 0, 0);
2290 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2291 GetTextExtentPoint32A(hdc, " ", 3, &size);
2292 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2293 SetTextJustification(hdc, 4, 1);
2294 GetTextExtentPoint32A(hdc, " ", 1, &size);
2295 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2296 SetTextJustification(hdc, 9, 2);
2297 GetTextExtentPoint32A(hdc, " ", 2, &size);
2298 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2299 SetTextJustification(hdc, 7, 3);
2300 GetTextExtentPoint32A(hdc, " ", 3, &size);
2301 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2302 SetTextJustification(hdc, 7, 3);
2303 SetTextCharacterExtra(hdc, 2 );
2304 GetTextExtentPoint32A(hdc, " ", 3, &size);
2305 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2306 SetTextJustification(hdc, 0, 0);
2307 SetTextCharacterExtra(hdc, 0);
2308 size.cx = size.cy = 1234;
2309 GetTextExtentPoint32A(hdc, " ", 0, &size);
2310 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2311 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2312 SetTextJustification(hdc, 5, 1);
2313 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2314 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2315 SetTextJustification(hdc, 0, 0);
2317 SetMapMode( hdc, MM_ANISOTROPIC );
2318 SetWindowExtEx( hdc, 2, 2, NULL );
2319 GetClientRect( hwnd, &clientArea );
2320 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2321 testJustification(hdc, testText, &clientArea);
2323 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2324 for (i = 0; i < 10; i++)
2326 SetTextCharacterExtra(hdc, i);
2327 GetTextExtentPoint32A(hdc, "A", 1, &size);
2328 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2330 SetTextCharacterExtra(hdc, 0);
2331 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2332 for (i = 0; i < 10; i++)
2334 SetTextCharacterExtra(hdc, i);
2335 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2336 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2338 SetTextCharacterExtra(hdc, 0);
2340 SetViewportExtEx( hdc, 3, 3, NULL );
2341 GetClientRect( hwnd, &clientArea );
2342 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2343 testJustification(hdc, testText, &clientArea);
2345 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2346 for (i = 0; i < 10; i++)
2348 SetTextCharacterExtra(hdc, i);
2349 GetTextExtentPoint32A(hdc, "A", 1, &size);
2350 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2353 done:
2354 DeleteObject(hfont);
2355 ReleaseDC(hwnd, hdc);
2356 DestroyWindow(hwnd);
2359 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2361 HDC hdc;
2362 LOGFONTA lf;
2363 HFONT hfont, hfont_old;
2364 CHARSETINFO csi;
2365 FONTSIGNATURE fs;
2366 INT cs;
2367 DWORD i, ret;
2368 char name[64];
2370 assert(count <= 128);
2372 memset(&lf, 0, sizeof(lf));
2374 lf.lfCharSet = charset;
2375 lf.lfHeight = 10;
2376 lstrcpyA(lf.lfFaceName, "Arial");
2377 SetLastError(0xdeadbeef);
2378 hfont = CreateFontIndirectA(&lf);
2379 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2381 hdc = GetDC(0);
2382 hfont_old = SelectObject(hdc, hfont);
2384 cs = GetTextCharsetInfo(hdc, &fs, 0);
2385 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2387 SetLastError(0xdeadbeef);
2388 ret = GetTextFaceA(hdc, sizeof(name), name);
2389 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2391 if (charset == SYMBOL_CHARSET)
2393 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2394 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
2396 else
2398 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2399 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2402 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2404 trace("Can't find codepage for charset %d\n", cs);
2405 ReleaseDC(0, hdc);
2406 return FALSE;
2408 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2410 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2412 skip("Font code page %d, looking for code page %d\n",
2413 pGdiGetCodePage(hdc), code_page);
2414 ReleaseDC(0, hdc);
2415 return FALSE;
2418 if (unicode)
2420 char ansi_buf[128];
2421 WCHAR unicode_buf[128];
2423 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2425 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2427 SetLastError(0xdeadbeef);
2428 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2429 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2430 count, ret, GetLastError());
2432 else
2434 char ansi_buf[128];
2436 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2438 SetLastError(0xdeadbeef);
2439 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2440 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2441 count, ret, GetLastError());
2444 SelectObject(hdc, hfont_old);
2445 DeleteObject(hfont);
2447 ReleaseDC(0, hdc);
2449 return TRUE;
2452 static void test_font_charset(void)
2454 static struct charset_data
2456 INT charset;
2457 UINT code_page;
2458 WORD font_idxA[128], font_idxW[128];
2459 } cd[] =
2461 { ANSI_CHARSET, 1252 },
2462 { RUSSIAN_CHARSET, 1251 },
2463 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2465 int i;
2467 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2469 win_skip("Skipping the font charset test on a Win9x platform\n");
2470 return;
2473 if (!is_font_installed("Arial"))
2475 skip("Arial is not installed\n");
2476 return;
2479 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2481 if (cd[i].charset == SYMBOL_CHARSET)
2483 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2485 skip("Symbol or Wingdings is not installed\n");
2486 break;
2489 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2490 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2491 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2494 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2495 if (i > 2)
2497 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2498 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2500 else
2501 skip("Symbol or Wingdings is not installed\n");
2504 static void test_GdiGetCodePage(void)
2506 static const struct _matching_data
2508 UINT current_codepage;
2509 LPCSTR lfFaceName;
2510 UCHAR lfCharSet;
2511 UINT expected_codepage;
2512 } matching_data[] = {
2513 {1251, "Arial", ANSI_CHARSET, 1252},
2514 {1251, "Tahoma", ANSI_CHARSET, 1252},
2516 {1252, "Arial", ANSI_CHARSET, 1252},
2517 {1252, "Tahoma", ANSI_CHARSET, 1252},
2519 {1253, "Arial", ANSI_CHARSET, 1252},
2520 {1253, "Tahoma", ANSI_CHARSET, 1252},
2522 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2523 { 932, "Tahoma", ANSI_CHARSET, 1252},
2524 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2526 { 936, "Arial", ANSI_CHARSET, 936},
2527 { 936, "Tahoma", ANSI_CHARSET, 936},
2528 { 936, "Simsun", ANSI_CHARSET, 936},
2530 { 949, "Arial", ANSI_CHARSET, 949},
2531 { 949, "Tahoma", ANSI_CHARSET, 949},
2532 { 949, "Gulim", ANSI_CHARSET, 949},
2534 { 950, "Arial", ANSI_CHARSET, 950},
2535 { 950, "Tahoma", ANSI_CHARSET, 950},
2536 { 950, "PMingLiU", ANSI_CHARSET, 950},
2538 HDC hdc;
2539 LOGFONTA lf;
2540 HFONT hfont;
2541 UINT charset, acp;
2542 DWORD codepage;
2543 int i;
2545 if (!pGdiGetCodePage)
2547 skip("GdiGetCodePage not available on this platform\n");
2548 return;
2551 acp = GetACP();
2553 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2555 /* only test data matched current locale codepage */
2556 if (matching_data[i].current_codepage != acp)
2557 continue;
2559 if (!is_font_installed(matching_data[i].lfFaceName))
2561 skip("%s is not installed\n", matching_data[i].lfFaceName);
2562 continue;
2565 hdc = GetDC(0);
2567 memset(&lf, 0, sizeof(lf));
2568 lf.lfHeight = -16;
2569 lf.lfCharSet = matching_data[i].lfCharSet;
2570 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2571 hfont = CreateFontIndirectA(&lf);
2572 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2574 hfont = SelectObject(hdc, hfont);
2575 charset = GetTextCharset(hdc);
2576 codepage = pGdiGetCodePage(hdc);
2577 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2578 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2579 ok(codepage == matching_data[i].expected_codepage,
2580 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2582 hfont = SelectObject(hdc, hfont);
2583 DeleteObject(hfont);
2585 /* CLIP_DFA_DISABLE turns off the font association */
2586 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2587 hfont = CreateFontIndirectA(&lf);
2588 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2590 hfont = SelectObject(hdc, hfont);
2591 charset = GetTextCharset(hdc);
2592 codepage = pGdiGetCodePage(hdc);
2593 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2594 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2595 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2597 hfont = SelectObject(hdc, hfont);
2598 DeleteObject(hfont);
2600 ReleaseDC(NULL, hdc);
2604 static void test_GetFontUnicodeRanges(void)
2606 LOGFONTA lf;
2607 HDC hdc;
2608 HFONT hfont, hfont_old;
2609 DWORD size;
2610 GLYPHSET *gs;
2611 DWORD i;
2613 if (!pGetFontUnicodeRanges)
2615 win_skip("GetFontUnicodeRanges not available before W2K\n");
2616 return;
2619 memset(&lf, 0, sizeof(lf));
2620 lstrcpyA(lf.lfFaceName, "Arial");
2621 hfont = create_font("Arial", &lf);
2623 hdc = GetDC(0);
2624 hfont_old = SelectObject(hdc, hfont);
2626 size = pGetFontUnicodeRanges(NULL, NULL);
2627 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2629 size = pGetFontUnicodeRanges(hdc, NULL);
2630 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2632 gs = HeapAlloc(GetProcessHeap(), 0, size);
2634 size = pGetFontUnicodeRanges(hdc, gs);
2635 ok(size, "GetFontUnicodeRanges failed\n");
2637 if (0) /* Disabled to limit console spam */
2638 for (i = 0; i < gs->cRanges; i++)
2639 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2640 trace("found %u ranges\n", gs->cRanges);
2642 HeapFree(GetProcessHeap(), 0, gs);
2644 SelectObject(hdc, hfont_old);
2645 DeleteObject(hfont);
2646 ReleaseDC(NULL, hdc);
2649 #define MAX_ENUM_FONTS 4096
2651 struct enum_font_data
2653 int total;
2654 LOGFONTA lf[MAX_ENUM_FONTS];
2657 struct enum_fullname_data
2659 int total;
2660 ENUMLOGFONTA elf[MAX_ENUM_FONTS];
2663 struct enum_font_dataW
2665 int total;
2666 LOGFONTW lf[MAX_ENUM_FONTS];
2669 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2671 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2672 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2674 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2675 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2677 if (type != TRUETYPE_FONTTYPE) return 1;
2679 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2681 if (0) /* Disabled to limit console spam */
2682 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2683 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2684 if (efd->total < MAX_ENUM_FONTS)
2685 efd->lf[efd->total++] = *lf;
2686 else
2687 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2689 return 1;
2692 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2694 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2695 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2697 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2698 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2700 if (type != TRUETYPE_FONTTYPE) return 1;
2702 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2704 if (0) /* Disabled to limit console spam */
2705 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2706 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2707 if (efd->total < MAX_ENUM_FONTS)
2708 efd->lf[efd->total++] = *lf;
2709 else
2710 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2712 return 1;
2715 static void get_charset_stats(struct enum_font_data *efd,
2716 int *ansi_charset, int *symbol_charset,
2717 int *russian_charset)
2719 int i;
2721 *ansi_charset = 0;
2722 *symbol_charset = 0;
2723 *russian_charset = 0;
2725 for (i = 0; i < efd->total; i++)
2727 switch (efd->lf[i].lfCharSet)
2729 case ANSI_CHARSET:
2730 (*ansi_charset)++;
2731 break;
2732 case SYMBOL_CHARSET:
2733 (*symbol_charset)++;
2734 break;
2735 case RUSSIAN_CHARSET:
2736 (*russian_charset)++;
2737 break;
2742 static void get_charset_statsW(struct enum_font_dataW *efd,
2743 int *ansi_charset, int *symbol_charset,
2744 int *russian_charset)
2746 int i;
2748 *ansi_charset = 0;
2749 *symbol_charset = 0;
2750 *russian_charset = 0;
2752 for (i = 0; i < efd->total; i++)
2754 switch (efd->lf[i].lfCharSet)
2756 case ANSI_CHARSET:
2757 (*ansi_charset)++;
2758 break;
2759 case SYMBOL_CHARSET:
2760 (*symbol_charset)++;
2761 break;
2762 case RUSSIAN_CHARSET:
2763 (*russian_charset)++;
2764 break;
2769 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2771 struct enum_font_data efd;
2772 struct enum_font_dataW efdw;
2773 LOGFONTA lf;
2774 HDC hdc;
2775 int i, ret, ansi_charset, symbol_charset, russian_charset;
2777 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2779 if (*font_name && !is_truetype_font_installed(font_name))
2781 skip("%s is not installed\n", font_name);
2782 return;
2785 hdc = GetDC(0);
2787 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2788 * while EnumFontFamiliesEx doesn't.
2790 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2793 * Use EnumFontFamiliesW since win98 crashes when the
2794 * second parameter is NULL using EnumFontFamilies
2796 efdw.total = 0;
2797 SetLastError(0xdeadbeef);
2798 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2799 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2800 if(ret)
2802 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2803 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2804 ansi_charset, symbol_charset, russian_charset);
2805 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2806 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2807 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2808 ok(russian_charset > 0 ||
2809 broken(russian_charset == 0), /* NT4 */
2810 "NULL family should enumerate RUSSIAN_CHARSET\n");
2813 efdw.total = 0;
2814 SetLastError(0xdeadbeef);
2815 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2816 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2817 if(ret)
2819 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2820 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2821 ansi_charset, symbol_charset, russian_charset);
2822 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2823 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2824 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2825 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2829 efd.total = 0;
2830 SetLastError(0xdeadbeef);
2831 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2832 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2833 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2834 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2835 ansi_charset, symbol_charset, russian_charset,
2836 *font_name ? font_name : "<empty>");
2837 if (*font_name)
2838 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2839 else
2840 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2841 for (i = 0; i < efd.total; i++)
2843 /* FIXME: remove completely once Wine is fixed */
2844 if (efd.lf[i].lfCharSet != font_charset)
2846 todo_wine
2847 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2849 else
2850 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2851 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2852 font_name, efd.lf[i].lfFaceName);
2855 memset(&lf, 0, sizeof(lf));
2856 lf.lfCharSet = ANSI_CHARSET;
2857 strcpy(lf.lfFaceName, font_name);
2858 efd.total = 0;
2859 SetLastError(0xdeadbeef);
2860 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2861 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2862 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2863 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2864 ansi_charset, symbol_charset, russian_charset,
2865 *font_name ? font_name : "<empty>");
2866 if (font_charset == SYMBOL_CHARSET)
2868 if (*font_name)
2869 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2870 else
2871 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2873 else
2875 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2876 for (i = 0; i < efd.total; i++)
2878 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2879 if (*font_name)
2880 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2881 font_name, efd.lf[i].lfFaceName);
2885 /* DEFAULT_CHARSET should enumerate all available charsets */
2886 memset(&lf, 0, sizeof(lf));
2887 lf.lfCharSet = DEFAULT_CHARSET;
2888 strcpy(lf.lfFaceName, font_name);
2889 efd.total = 0;
2890 SetLastError(0xdeadbeef);
2891 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2892 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2893 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2894 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2895 ansi_charset, symbol_charset, russian_charset,
2896 *font_name ? font_name : "<empty>");
2897 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2898 for (i = 0; i < efd.total; i++)
2900 if (*font_name)
2901 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2902 font_name, efd.lf[i].lfFaceName);
2904 if (*font_name)
2906 switch (font_charset)
2908 case ANSI_CHARSET:
2909 ok(ansi_charset > 0,
2910 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2911 ok(!symbol_charset,
2912 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2913 ok(russian_charset > 0,
2914 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2915 break;
2916 case SYMBOL_CHARSET:
2917 ok(!ansi_charset,
2918 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2919 ok(symbol_charset,
2920 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2921 ok(!russian_charset,
2922 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2923 break;
2924 case DEFAULT_CHARSET:
2925 ok(ansi_charset > 0,
2926 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2927 ok(symbol_charset > 0,
2928 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2929 ok(russian_charset > 0,
2930 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2931 break;
2934 else
2936 ok(ansi_charset > 0,
2937 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2938 ok(symbol_charset > 0,
2939 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2940 ok(russian_charset > 0,
2941 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2944 memset(&lf, 0, sizeof(lf));
2945 lf.lfCharSet = SYMBOL_CHARSET;
2946 strcpy(lf.lfFaceName, font_name);
2947 efd.total = 0;
2948 SetLastError(0xdeadbeef);
2949 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2950 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2951 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2952 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2953 ansi_charset, symbol_charset, russian_charset,
2954 *font_name ? font_name : "<empty>");
2955 if (*font_name && font_charset == ANSI_CHARSET)
2956 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2957 else
2959 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2960 for (i = 0; i < efd.total; i++)
2962 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2963 if (*font_name)
2964 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2965 font_name, efd.lf[i].lfFaceName);
2968 ok(!ansi_charset,
2969 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2970 ok(symbol_charset > 0,
2971 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2972 ok(!russian_charset,
2973 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2976 ReleaseDC(0, hdc);
2979 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2981 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
2982 LOGFONTA *target = (LOGFONTA *)lParam;
2983 const DWORD valid_bits = 0x003f01ff;
2984 CHARSETINFO csi;
2985 DWORD fs;
2987 if (type != TRUETYPE_FONTTYPE) return TRUE;
2989 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
2990 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
2991 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
2992 *target = *lf;
2993 return FALSE;
2997 return TRUE;
3000 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3002 struct enum_font_data *efd = (struct enum_font_data *)lParam;
3004 if (type != TRUETYPE_FONTTYPE) return 1;
3006 if (efd->total < MAX_ENUM_FONTS)
3007 efd->lf[efd->total++] = *lf;
3008 else
3009 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
3011 return 1;
3014 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3016 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3018 if (type != TRUETYPE_FONTTYPE) return 1;
3020 if (efnd->total < MAX_ENUM_FONTS)
3021 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3022 else
3023 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
3025 return 1;
3028 static void test_EnumFontFamiliesEx_default_charset(void)
3030 struct enum_font_data efd;
3031 LOGFONTA target, enum_font;
3032 UINT acp;
3033 HDC hdc;
3034 CHARSETINFO csi;
3036 acp = GetACP();
3037 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3038 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3039 return;
3042 hdc = GetDC(0);
3043 memset(&enum_font, 0, sizeof(enum_font));
3044 enum_font.lfCharSet = csi.ciCharset;
3045 target.lfFaceName[0] = '\0';
3046 target.lfCharSet = csi.ciCharset;
3047 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3048 if (target.lfFaceName[0] == '\0') {
3049 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3050 return;
3052 if (acp == 874 || acp == 1255 || acp == 1256) {
3053 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3054 target.lfCharSet = ANSI_CHARSET;
3057 efd.total = 0;
3058 memset(&enum_font, 0, sizeof(enum_font));
3059 strcpy(enum_font.lfFaceName, target.lfFaceName);
3060 enum_font.lfCharSet = DEFAULT_CHARSET;
3061 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3062 ReleaseDC(0, hdc);
3064 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3065 if (efd.total < 2) {
3066 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3067 return;
3070 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3071 "(%s) got charset %d expected %d\n",
3072 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3074 return;
3077 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3079 HFONT hfont, hfont_prev;
3080 DWORD ret;
3081 GLYPHMETRICS gm1, gm2;
3082 LOGFONTA lf2 = *lf;
3083 WORD idx;
3085 if(!pGetGlyphIndicesA)
3086 return;
3088 /* negative widths are handled just as positive ones */
3089 lf2.lfWidth = -lf->lfWidth;
3091 SetLastError(0xdeadbeef);
3092 hfont = CreateFontIndirectA(lf);
3093 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3094 check_font("original", lf, hfont);
3096 hfont_prev = SelectObject(hdc, hfont);
3098 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3099 if (ret == GDI_ERROR || idx == 0xffff)
3101 SelectObject(hdc, hfont_prev);
3102 DeleteObject(hfont);
3103 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3104 return;
3107 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3108 memset(&gm1, 0xab, sizeof(gm1));
3109 SetLastError(0xdeadbeef);
3110 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3111 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3113 SelectObject(hdc, hfont_prev);
3114 DeleteObject(hfont);
3116 SetLastError(0xdeadbeef);
3117 hfont = CreateFontIndirectA(&lf2);
3118 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3119 check_font("negative width", &lf2, hfont);
3121 hfont_prev = SelectObject(hdc, hfont);
3123 memset(&gm2, 0xbb, sizeof(gm2));
3124 SetLastError(0xdeadbeef);
3125 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3126 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3128 SelectObject(hdc, hfont_prev);
3129 DeleteObject(hfont);
3131 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3132 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3133 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3134 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3135 gm1.gmCellIncX == gm2.gmCellIncX &&
3136 gm1.gmCellIncY == gm2.gmCellIncY,
3137 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3138 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3139 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3140 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3141 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3144 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3145 #include "pshpack2.h"
3146 typedef struct
3148 USHORT version;
3149 SHORT xAvgCharWidth;
3150 USHORT usWeightClass;
3151 USHORT usWidthClass;
3152 SHORT fsType;
3153 SHORT ySubscriptXSize;
3154 SHORT ySubscriptYSize;
3155 SHORT ySubscriptXOffset;
3156 SHORT ySubscriptYOffset;
3157 SHORT ySuperscriptXSize;
3158 SHORT ySuperscriptYSize;
3159 SHORT ySuperscriptXOffset;
3160 SHORT ySuperscriptYOffset;
3161 SHORT yStrikeoutSize;
3162 SHORT yStrikeoutPosition;
3163 SHORT sFamilyClass;
3164 PANOSE panose;
3165 ULONG ulUnicodeRange1;
3166 ULONG ulUnicodeRange2;
3167 ULONG ulUnicodeRange3;
3168 ULONG ulUnicodeRange4;
3169 CHAR achVendID[4];
3170 USHORT fsSelection;
3171 USHORT usFirstCharIndex;
3172 USHORT usLastCharIndex;
3173 /* According to the Apple spec, original version didn't have the below fields,
3174 * version numbers were taken from the OpenType spec.
3176 /* version 0 (TrueType 1.5) */
3177 USHORT sTypoAscender;
3178 USHORT sTypoDescender;
3179 USHORT sTypoLineGap;
3180 USHORT usWinAscent;
3181 USHORT usWinDescent;
3182 /* version 1 (TrueType 1.66) */
3183 ULONG ulCodePageRange1;
3184 ULONG ulCodePageRange2;
3185 /* version 2 (OpenType 1.2) */
3186 SHORT sxHeight;
3187 SHORT sCapHeight;
3188 USHORT usDefaultChar;
3189 USHORT usBreakChar;
3190 USHORT usMaxContext;
3191 } TT_OS2_V2;
3192 #include "poppack.h"
3194 typedef struct
3196 USHORT version;
3197 USHORT num_tables;
3198 } cmap_header;
3200 typedef struct
3202 USHORT plat_id;
3203 USHORT enc_id;
3204 ULONG offset;
3205 } cmap_encoding_record;
3207 typedef struct
3209 USHORT format;
3210 USHORT length;
3211 USHORT language;
3213 BYTE glyph_ids[256];
3214 } cmap_format_0;
3216 typedef struct
3218 USHORT format;
3219 USHORT length;
3220 USHORT language;
3222 USHORT seg_countx2;
3223 USHORT search_range;
3224 USHORT entry_selector;
3225 USHORT range_shift;
3227 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3228 /* Then follows:
3229 USHORT pad;
3230 USHORT start_count[seg_countx2 / 2];
3231 USHORT id_delta[seg_countx2 / 2];
3232 USHORT id_range_offset[seg_countx2 / 2];
3233 USHORT glyph_ids[];
3235 } cmap_format_4;
3237 typedef struct
3239 USHORT end_count;
3240 USHORT start_count;
3241 USHORT id_delta;
3242 USHORT id_range_offset;
3243 } cmap_format_4_seg;
3245 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
3247 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3248 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3249 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3250 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3251 os2->panose.bWeight, os2->panose.bProportion);
3254 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3256 int i;
3257 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3259 *first = 256;
3261 for(i = 0; i < 256; i++)
3263 if(cmap->glyph_ids[i] == 0) continue;
3264 *last = i;
3265 if(*first == 256) *first = i;
3267 if(*first == 256) return FALSE;
3268 return TRUE;
3271 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3273 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3274 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3275 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3276 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3277 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3280 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3282 int i;
3283 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3284 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3286 *first = 0x10000;
3288 for(i = 0; i < seg_count; i++)
3290 cmap_format_4_seg seg;
3292 get_seg4(cmap, i, &seg);
3294 if(seg.start_count > 0xfffe) break;
3296 if(*first == 0x10000) *first = seg.start_count;
3298 *last = min(seg.end_count, 0xfffe);
3301 if(*first == 0x10000) return FALSE;
3302 return TRUE;
3305 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3307 USHORT i;
3308 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3310 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3312 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3313 return (BYTE *)header + GET_BE_DWORD(record->offset);
3314 record++;
3316 return NULL;
3319 typedef enum
3321 cmap_none,
3322 cmap_ms_unicode,
3323 cmap_ms_symbol
3324 } cmap_type;
3326 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3328 LONG size, ret;
3329 cmap_header *header;
3330 void *cmap;
3331 BOOL r = FALSE;
3332 WORD format;
3334 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3335 ok(size != GDI_ERROR, "no cmap table found\n");
3336 if(size == GDI_ERROR) return FALSE;
3338 header = HeapAlloc(GetProcessHeap(), 0, size);
3339 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3340 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3341 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3343 cmap = get_cmap(header, 3, 1);
3344 if(cmap)
3345 *cmap_type = cmap_ms_unicode;
3346 else
3348 cmap = get_cmap(header, 3, 0);
3349 if(cmap) *cmap_type = cmap_ms_symbol;
3351 if(!cmap)
3353 *cmap_type = cmap_none;
3354 goto end;
3357 format = GET_BE_WORD(*(WORD *)cmap);
3358 switch(format)
3360 case 0:
3361 r = get_first_last_from_cmap0(cmap, first, last);
3362 break;
3363 case 4:
3364 r = get_first_last_from_cmap4(cmap, first, last, size);
3365 break;
3366 default:
3367 trace("unhandled cmap format %d\n", format);
3368 break;
3371 end:
3372 HeapFree(GetProcessHeap(), 0, header);
3373 return r;
3376 #define TT_PLATFORM_APPLE_UNICODE 0
3377 #define TT_PLATFORM_MACINTOSH 1
3378 #define TT_PLATFORM_MICROSOFT 3
3379 #define TT_APPLE_ID_DEFAULT 0
3380 #define TT_APPLE_ID_ISO_10646 2
3381 #define TT_APPLE_ID_UNICODE_2_0 3
3382 #define TT_MS_ID_SYMBOL_CS 0
3383 #define TT_MS_ID_UNICODE_CS 1
3384 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3385 #define TT_NAME_ID_FONT_FAMILY 1
3386 #define TT_NAME_ID_FONT_SUBFAMILY 2
3387 #define TT_NAME_ID_UNIQUE_ID 3
3388 #define TT_NAME_ID_FULL_NAME 4
3389 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3391 typedef struct sfnt_name
3393 USHORT platform_id;
3394 USHORT encoding_id;
3395 USHORT language_id;
3396 USHORT name_id;
3397 USHORT length;
3398 USHORT offset;
3399 } sfnt_name;
3401 static const LANGID mac_langid_table[] =
3403 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3404 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3405 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3406 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3407 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3408 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3409 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3410 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3411 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3412 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3413 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3414 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3415 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3416 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3417 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3418 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3419 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3420 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3421 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3422 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3423 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3424 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3425 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3426 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3427 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3428 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3429 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3430 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3431 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3432 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3433 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3434 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3435 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3436 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3437 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3438 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3439 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3440 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3441 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3442 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3443 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3444 0, /* TT_MAC_LANGID_YIDDISH */
3445 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3446 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3447 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3448 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3449 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3450 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3451 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3452 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3453 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3454 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3455 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3456 0, /* TT_MAC_LANGID_MOLDAVIAN */
3457 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3458 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3459 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3460 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3461 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3462 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3463 0, /* TT_MAC_LANGID_KURDISH */
3464 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3465 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3466 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3467 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3468 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3469 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3470 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3471 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3472 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3473 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3474 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3475 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3476 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3477 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3478 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3479 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3480 0, /* TT_MAC_LANGID_BURMESE */
3481 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3482 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3483 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3484 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3485 0, /* TT_MAC_LANGID_TAGALOG */
3486 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3487 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3488 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3489 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3490 0, /* TT_MAC_LANGID_GALLA */
3491 0, /* TT_MAC_LANGID_SOMALI */
3492 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3493 0, /* TT_MAC_LANGID_RUANDA */
3494 0, /* TT_MAC_LANGID_RUNDI */
3495 0, /* TT_MAC_LANGID_CHEWA */
3496 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3497 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3500 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3501 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3502 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3503 0, /* TT_MAC_LANGID_LATIN */
3504 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3505 0, /* TT_MAC_LANGID_GUARANI */
3506 0, /* TT_MAC_LANGID_AYMARA */
3507 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3508 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3509 0, /* TT_MAC_LANGID_DZONGKHA */
3510 0, /* TT_MAC_LANGID_JAVANESE */
3511 0, /* TT_MAC_LANGID_SUNDANESE */
3512 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3513 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3514 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3515 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3516 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3517 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3518 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3519 0, /* TT_MAC_LANGID_TONGAN */
3520 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3521 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3522 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3525 static inline WORD get_mac_code_page( const sfnt_name *name )
3527 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3528 return 10000 + GET_BE_WORD(name->encoding_id);
3531 static int match_name_table_language( const sfnt_name *name, LANGID lang )
3533 LANGID name_lang;
3534 int res = 0;
3536 switch (GET_BE_WORD(name->platform_id))
3538 case TT_PLATFORM_MICROSOFT:
3539 res += 5; /* prefer the Microsoft name */
3540 switch (GET_BE_WORD(name->encoding_id))
3542 case TT_MS_ID_UNICODE_CS:
3543 case TT_MS_ID_SYMBOL_CS:
3544 name_lang = GET_BE_WORD(name->language_id);
3545 break;
3546 default:
3547 return 0;
3549 break;
3550 case TT_PLATFORM_MACINTOSH:
3551 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3552 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3553 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3554 break;
3555 case TT_PLATFORM_APPLE_UNICODE:
3556 res += 2; /* prefer Unicode encodings */
3557 switch (GET_BE_WORD(name->encoding_id))
3559 case TT_APPLE_ID_DEFAULT:
3560 case TT_APPLE_ID_ISO_10646:
3561 case TT_APPLE_ID_UNICODE_2_0:
3562 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3563 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3564 break;
3565 default:
3566 return 0;
3568 break;
3569 default:
3570 return 0;
3572 if (name_lang == lang) res += 30;
3573 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3574 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3575 return res;
3578 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3580 struct sfnt_name_header
3582 USHORT format;
3583 USHORT number_of_record;
3584 USHORT storage_offset;
3585 } *header;
3586 sfnt_name *entry;
3587 BOOL r = FALSE;
3588 LONG size, offset, length;
3589 LONG c, ret;
3590 WCHAR *name;
3591 BYTE *data;
3592 USHORT i;
3593 int res, best_lang = 0, best_index = -1;
3595 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3596 ok(size != GDI_ERROR, "no name table found\n");
3597 if(size == GDI_ERROR) return FALSE;
3599 data = HeapAlloc(GetProcessHeap(), 0, size);
3600 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3601 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3603 header = (void *)data;
3604 header->format = GET_BE_WORD(header->format);
3605 header->number_of_record = GET_BE_WORD(header->number_of_record);
3606 header->storage_offset = GET_BE_WORD(header->storage_offset);
3607 if (header->format != 0)
3609 trace("got format %u\n", header->format);
3610 goto out;
3612 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3614 trace("number records out of range: %d\n", header->number_of_record);
3615 goto out;
3617 if (header->storage_offset >= size)
3619 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3620 goto out;
3623 entry = (void *)&header[1];
3624 for (i = 0; i < header->number_of_record; i++)
3626 if (GET_BE_WORD(entry[i].name_id) != name_id) continue;
3627 res = match_name_table_language( &entry[i], language_id);
3628 if (res > best_lang)
3630 best_lang = res;
3631 best_index = i;
3635 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset);
3636 length = GET_BE_WORD(entry[best_index].length);
3637 if (offset + length > size)
3639 trace("entry %d is out of range\n", best_index);
3640 goto out;
3642 if (length >= out_size)
3644 trace("buffer too small for entry %d\n", best_index);
3645 goto out;
3648 name = (WCHAR *)(data + offset);
3649 for (c = 0; c < length / 2; c++)
3650 out_buf[c] = GET_BE_WORD(name[c]);
3651 out_buf[c] = 0;
3653 r = TRUE;
3655 out:
3656 HeapFree(GetProcessHeap(), 0, data);
3657 return r;
3660 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3662 HDC hdc;
3663 HFONT hfont, hfont_old;
3664 TEXTMETRICA tmA;
3665 TT_OS2_V2 tt_os2;
3666 LONG size, ret;
3667 const char *font_name = lf->lfFaceName;
3668 DWORD cmap_first = 0, cmap_last = 0;
3669 UINT ascent, descent, cell_height;
3670 cmap_type cmap_type;
3671 BOOL sys_lang_non_english;
3673 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3674 hdc = GetDC(0);
3676 SetLastError(0xdeadbeef);
3677 hfont = CreateFontIndirectA(lf);
3678 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3680 hfont_old = SelectObject(hdc, hfont);
3682 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3683 if (size == GDI_ERROR)
3685 trace("OS/2 chunk was not found\n");
3686 goto end_of_test;
3688 if (size > sizeof(tt_os2))
3690 trace("got too large OS/2 chunk of size %u\n", size);
3691 size = sizeof(tt_os2);
3694 memset(&tt_os2, 0, sizeof(tt_os2));
3695 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3696 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3698 SetLastError(0xdeadbeef);
3699 ret = GetTextMetricsA(hdc, &tmA);
3700 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3702 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3704 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3706 else
3708 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3709 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3710 UINT os2_first_char, os2_last_char, default_char, break_char;
3711 USHORT version;
3712 TEXTMETRICW tmW;
3714 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3715 descent = GET_BE_WORD(tt_os2.usWinDescent);
3716 cell_height = ascent + descent;
3717 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3718 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3720 version = GET_BE_WORD(tt_os2.version);
3722 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3723 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3724 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3725 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3727 if (winetest_debug > 1)
3728 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3729 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3730 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3732 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3734 expect_first_W = 0;
3735 switch(GetACP())
3737 case 1255: /* Hebrew */
3738 expect_last_W = 0xf896;
3739 break;
3740 case 1257: /* Baltic */
3741 expect_last_W = 0xf8fd;
3742 break;
3743 default:
3744 expect_last_W = 0xf0ff;
3746 expect_break_W = 0x20;
3747 expect_default_W = expect_break_W - 1;
3748 expect_first_A = 0x1e;
3749 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3751 else
3753 expect_first_W = cmap_first;
3754 expect_last_W = cmap_last;
3755 if(os2_first_char <= 1)
3756 expect_break_W = os2_first_char + 2;
3757 else if(os2_first_char > 0xff)
3758 expect_break_W = 0x20;
3759 else
3760 expect_break_W = os2_first_char;
3761 expect_default_W = expect_break_W - 1;
3762 expect_first_A = expect_default_W - 1;
3763 expect_last_A = min(expect_last_W, 0xff);
3765 expect_break_A = expect_break_W;
3766 expect_default_A = expect_default_W;
3768 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3769 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3770 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3771 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3772 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3773 else
3774 ok(tmA.tmFirstChar == expect_first_A ||
3775 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3776 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3777 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3778 ok(tmA.tmLastChar == expect_last_A ||
3779 tmA.tmLastChar == 0xff /* win9x */,
3780 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3781 else
3782 skip("tmLastChar is DBCS lead byte\n");
3783 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3784 font_name, tmA.tmBreakChar, expect_break_A);
3785 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3786 "A: tmDefaultChar for %s got %02x expected %02x\n",
3787 font_name, tmA.tmDefaultChar, expect_default_A);
3790 SetLastError(0xdeadbeef);
3791 ret = GetTextMetricsW(hdc, &tmW);
3792 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3793 "GetTextMetricsW error %u\n", GetLastError());
3794 if (ret)
3796 /* Wine uses the os2 first char */
3797 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3798 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3799 font_name, tmW.tmFirstChar, expect_first_W);
3800 else
3801 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3802 font_name, tmW.tmFirstChar, expect_first_W);
3804 /* Wine uses the os2 last char */
3805 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3806 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3807 font_name, tmW.tmLastChar, expect_last_W);
3808 else
3809 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3810 font_name, tmW.tmLastChar, expect_last_W);
3811 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3812 font_name, tmW.tmBreakChar, expect_break_W);
3813 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3814 "W: tmDefaultChar for %s got %02x expected %02x\n",
3815 font_name, tmW.tmDefaultChar, expect_default_W);
3817 /* Test the aspect ratio while we have tmW */
3818 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3819 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3820 tmW.tmDigitizedAspectX, ret);
3821 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3822 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3823 tmW.tmDigitizedAspectX, ret);
3827 /* test FF_ values */
3828 switch(tt_os2.panose.bFamilyType)
3830 case PAN_ANY:
3831 case PAN_NO_FIT:
3832 case PAN_FAMILY_TEXT_DISPLAY:
3833 case PAN_FAMILY_PICTORIAL:
3834 default:
3835 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3836 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3838 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3839 break;
3841 switch(tt_os2.panose.bSerifStyle)
3843 case PAN_ANY:
3844 case PAN_NO_FIT:
3845 default:
3846 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3847 break;
3849 case PAN_SERIF_COVE:
3850 case PAN_SERIF_OBTUSE_COVE:
3851 case PAN_SERIF_SQUARE_COVE:
3852 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3853 case PAN_SERIF_SQUARE:
3854 case PAN_SERIF_THIN:
3855 case PAN_SERIF_BONE:
3856 case PAN_SERIF_EXAGGERATED:
3857 case PAN_SERIF_TRIANGLE:
3858 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3859 break;
3861 case PAN_SERIF_NORMAL_SANS:
3862 case PAN_SERIF_OBTUSE_SANS:
3863 case PAN_SERIF_PERP_SANS:
3864 case PAN_SERIF_FLARED:
3865 case PAN_SERIF_ROUNDED:
3866 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3867 break;
3869 break;
3871 case PAN_FAMILY_SCRIPT:
3872 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3873 break;
3875 case PAN_FAMILY_DECORATIVE:
3876 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3877 break;
3880 test_negative_width(hdc, lf);
3882 end_of_test:
3883 SelectObject(hdc, hfont_old);
3884 DeleteObject(hfont);
3886 ReleaseDC(0, hdc);
3889 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3891 INT *enumed = (INT *)lParam;
3893 if (type == TRUETYPE_FONTTYPE)
3895 (*enumed)++;
3896 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
3898 return 1;
3901 static void test_GetTextMetrics(void)
3903 LOGFONTA lf;
3904 HDC hdc;
3905 INT enumed;
3907 /* Report only once */
3908 if(!pGetGlyphIndicesA)
3909 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3911 hdc = GetDC(0);
3913 memset(&lf, 0, sizeof(lf));
3914 lf.lfCharSet = DEFAULT_CHARSET;
3915 enumed = 0;
3916 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3917 trace("Tested metrics of %d truetype fonts\n", enumed);
3919 ReleaseDC(0, hdc);
3922 static void test_nonexistent_font(void)
3924 static const struct
3926 const char *name;
3927 int charset;
3928 } font_subst[] =
3930 { "Times New Roman Baltic", 186 },
3931 { "Times New Roman CE", 238 },
3932 { "Times New Roman CYR", 204 },
3933 { "Times New Roman Greek", 161 },
3934 { "Times New Roman TUR", 162 }
3936 static const struct
3938 const char *name;
3939 int charset;
3940 } shell_subst[] =
3942 { "MS Shell Dlg", 186 },
3943 { "MS Shell Dlg", 238 },
3944 { "MS Shell Dlg", 204 },
3945 { "MS Shell Dlg", 161 },
3946 { "MS Shell Dlg", 162 }
3948 LOGFONTA lf;
3949 HDC hdc;
3950 HFONT hfont;
3951 CHARSETINFO csi;
3952 INT cs, expected_cs, i, ret;
3953 char buf[LF_FACESIZE];
3955 expected_cs = GetACP();
3956 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3958 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3959 return;
3961 expected_cs = csi.ciCharset;
3962 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3964 hdc = CreateCompatibleDC(0);
3966 for (i = 0; i < sizeof(shell_subst)/sizeof(shell_subst[0]); i++)
3968 ret = is_font_installed(shell_subst[i].name);
3969 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
3970 ret = is_truetype_font_installed(shell_subst[i].name);
3971 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
3973 memset(&lf, 0, sizeof(lf));
3974 lf.lfHeight = -13;
3975 lf.lfWeight = FW_REGULAR;
3976 strcpy(lf.lfFaceName, shell_subst[i].name);
3977 hfont = CreateFontIndirectA(&lf);
3978 hfont = SelectObject(hdc, hfont);
3979 GetTextFaceA(hdc, sizeof(buf), buf);
3980 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
3981 cs = GetTextCharset(hdc);
3982 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name);
3984 DeleteObject(SelectObject(hdc, hfont));
3986 memset(&lf, 0, sizeof(lf));
3987 lf.lfHeight = -13;
3988 lf.lfWeight = FW_DONTCARE;
3989 strcpy(lf.lfFaceName, shell_subst[i].name);
3990 hfont = CreateFontIndirectA(&lf);
3991 hfont = SelectObject(hdc, hfont);
3992 GetTextFaceA(hdc, sizeof(buf), buf);
3993 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
3994 cs = GetTextCharset(hdc);
3995 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name);
3996 DeleteObject(SelectObject(hdc, hfont));
3999 if (!is_truetype_font_installed("Arial") ||
4000 !is_truetype_font_installed("Times New Roman"))
4002 DeleteDC(hdc);
4003 skip("Arial or Times New Roman not installed\n");
4004 return;
4007 memset(&lf, 0, sizeof(lf));
4008 lf.lfHeight = 100;
4009 lf.lfWeight = FW_REGULAR;
4010 lf.lfCharSet = ANSI_CHARSET;
4011 lf.lfPitchAndFamily = FF_SWISS;
4012 strcpy(lf.lfFaceName, "Nonexistent font");
4013 hfont = CreateFontIndirectA(&lf);
4014 hfont = SelectObject(hdc, hfont);
4015 GetTextFaceA(hdc, sizeof(buf), buf);
4016 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4017 cs = GetTextCharset(hdc);
4018 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4019 DeleteObject(SelectObject(hdc, hfont));
4021 memset(&lf, 0, sizeof(lf));
4022 lf.lfHeight = -13;
4023 lf.lfWeight = FW_DONTCARE;
4024 strcpy(lf.lfFaceName, "Nonexistent font");
4025 hfont = CreateFontIndirectA(&lf);
4026 hfont = SelectObject(hdc, hfont);
4027 GetTextFaceA(hdc, sizeof(buf), buf);
4028 todo_wine /* Wine uses Arial for all substitutions */
4029 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
4030 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
4031 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4032 "Got %s\n", buf);
4033 cs = GetTextCharset(hdc);
4034 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
4035 DeleteObject(SelectObject(hdc, hfont));
4037 memset(&lf, 0, sizeof(lf));
4038 lf.lfHeight = -13;
4039 lf.lfWeight = FW_REGULAR;
4040 strcpy(lf.lfFaceName, "Nonexistent font");
4041 hfont = CreateFontIndirectA(&lf);
4042 hfont = SelectObject(hdc, hfont);
4043 GetTextFaceA(hdc, sizeof(buf), buf);
4044 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4045 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
4046 cs = GetTextCharset(hdc);
4047 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4048 DeleteObject(SelectObject(hdc, hfont));
4050 memset(&lf, 0, sizeof(lf));
4051 lf.lfHeight = -13;
4052 lf.lfWeight = FW_DONTCARE;
4053 strcpy(lf.lfFaceName, "Times New Roman");
4054 hfont = CreateFontIndirectA(&lf);
4055 hfont = SelectObject(hdc, hfont);
4056 GetTextFaceA(hdc, sizeof(buf), buf);
4057 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
4058 cs = GetTextCharset(hdc);
4059 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4060 DeleteObject(SelectObject(hdc, hfont));
4062 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
4064 ret = is_font_installed(font_subst[i].name);
4065 todo_wine
4066 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4067 "%s should be enumerated\n", font_subst[i].name);
4068 ret = is_truetype_font_installed(font_subst[i].name);
4069 todo_wine
4070 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4071 "%s should be enumerated\n", font_subst[i].name);
4073 memset(&lf, 0, sizeof(lf));
4074 lf.lfHeight = -13;
4075 lf.lfWeight = FW_REGULAR;
4076 strcpy(lf.lfFaceName, font_subst[i].name);
4077 hfont = CreateFontIndirectA(&lf);
4078 hfont = SelectObject(hdc, hfont);
4079 cs = GetTextCharset(hdc);
4080 if (font_subst[i].charset == expected_cs)
4082 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4083 GetTextFaceA(hdc, sizeof(buf), buf);
4084 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
4086 else
4088 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
4089 GetTextFaceA(hdc, sizeof(buf), buf);
4090 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4091 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
4093 DeleteObject(SelectObject(hdc, hfont));
4095 memset(&lf, 0, sizeof(lf));
4096 lf.lfHeight = -13;
4097 lf.lfWeight = FW_DONTCARE;
4098 strcpy(lf.lfFaceName, font_subst[i].name);
4099 hfont = CreateFontIndirectA(&lf);
4100 hfont = SelectObject(hdc, hfont);
4101 GetTextFaceA(hdc, sizeof(buf), buf);
4102 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
4103 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
4104 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
4105 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4106 "got %s for font %s\n", buf, font_subst[i].name);
4107 cs = GetTextCharset(hdc);
4108 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4109 DeleteObject(SelectObject(hdc, hfont));
4112 DeleteDC(hdc);
4115 static void test_RealizationInfo(void)
4117 struct font_realization_info {
4118 DWORD size;
4119 DWORD flags;
4120 DWORD cache_num;
4121 DWORD instance_id;
4122 DWORD unk;
4123 DWORD face_index;
4126 struct realization_info_t
4128 DWORD flags;
4129 DWORD cache_num;
4130 DWORD instance_id;
4133 HDC hdc;
4134 DWORD info[4], info2[10];
4135 BOOL r, have_file = FALSE;
4136 HFONT hfont, hfont_old;
4137 LOGFONTA lf;
4138 DWORD needed, read;
4139 HANDLE h;
4140 BYTE file[16], data[14];
4141 struct file_info
4143 FILETIME time;
4144 LARGE_INTEGER size;
4145 WCHAR path[MAX_PATH];
4146 } file_info;
4147 FILETIME time;
4148 LARGE_INTEGER size;
4150 if(!pGdiRealizationInfo)
4152 win_skip("GdiRealizationInfo not available\n");
4153 return;
4156 hdc = GetDC(0);
4158 memset(info, 0xcc, sizeof(info));
4159 r = pGdiRealizationInfo(hdc, info);
4160 ok(r != 0, "ret 0\n");
4161 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
4162 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4164 if (!is_truetype_font_installed("Arial"))
4166 skip("skipping GdiRealizationInfo with truetype font\n");
4167 goto end;
4170 memset(&lf, 0, sizeof(lf));
4171 strcpy(lf.lfFaceName, "Arial");
4172 lf.lfHeight = 20;
4173 lf.lfWeight = FW_NORMAL;
4174 hfont = CreateFontIndirectA(&lf);
4175 hfont_old = SelectObject(hdc, hfont);
4177 memset(info, 0xcc, sizeof(info));
4178 r = pGdiRealizationInfo(hdc, info);
4179 ok(r != 0, "ret 0\n");
4180 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
4181 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4183 if (pGetFontRealizationInfo)
4185 struct font_realization_info *fri = (struct font_realization_info*)info2;
4186 struct realization_info_t *ri = (struct realization_info_t*)info;
4188 /* The first DWORD represents a struct size. On a
4189 newly rebooted system setting this to < 16 results
4190 in GetFontRealizationInfo failing. However there
4191 appears to be some caching going on which results
4192 in calls after a successful call also succeeding even
4193 if the size < 16. This means we can't reliably test
4194 this behaviour. */
4196 memset(info2, 0xcc, sizeof(info2));
4197 info2[0] = 16;
4198 r = pGetFontRealizationInfo(hdc, info2);
4199 ok(r != 0, "ret 0\n");
4200 /* We may get the '24' version here if that has been previously
4201 requested. */
4202 ok(fri->size == 16 || fri->size == 24, "got %d\n", info2[0]);
4203 ok(fri->flags == ri->flags, "flags mismatch\n");
4204 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4205 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4206 ok(info2[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2[6]);
4208 memset(info2, 0xcc, sizeof(info2));
4209 info2[0] = 28;
4210 r = pGetFontRealizationInfo(hdc, info2);
4211 ok(r == FALSE, "got %d\n", r);
4213 memset(info2, 0xcc, sizeof(info2));
4214 info2[0] = 24;
4215 r = pGetFontRealizationInfo(hdc, info2);
4216 ok(r != 0, "ret 0\n");
4217 ok(fri->size == 24, "got %d\n", fri->size);
4218 ok(fri->flags == ri->flags, "flags mismatch\n");
4219 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4220 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4221 ok(fri->face_index == 0, "got wrong face index %u\n", fri->face_index);
4222 ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4224 /* Test GetFontFileInfo() */
4225 if (pGetFontFileInfo) {
4226 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed);
4227 ok(r != 0 || GetLastError() == ERROR_NOACCESS, "ret %d gle %d\n", r, GetLastError());
4229 if (r)
4231 h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
4232 ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError());
4234 GetFileTime(h, NULL, NULL, &time);
4235 ok(!CompareFileTime(&file_info.time, &time), "time mismatch\n");
4236 GetFileSizeEx(h, &size);
4237 ok(file_info.size.QuadPart == size.QuadPart, "size mismatch\n");
4239 /* Read first 16 bytes from the file */
4240 ReadFile(h, file, sizeof(file), &read, NULL);
4241 CloseHandle(h);
4242 have_file = TRUE;
4245 /* Get bytes 2 - 16 using GetFontFileData */
4246 r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data));
4247 ok(r != 0, "ret 0 gle %d\n", GetLastError());
4249 if (have_file)
4250 ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n");
4251 else
4252 win_skip("GetFontFileInfo() failed, skipping\n");
4256 DeleteObject(SelectObject(hdc, hfont_old));
4258 end:
4259 ReleaseDC(0, hdc);
4262 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4263 the nul in the count of characters copied when the face name buffer is not
4264 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4265 always includes it. */
4266 static void test_GetTextFace(void)
4268 static const char faceA[] = "Tahoma";
4269 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
4270 LOGFONTA fA = {0};
4271 LOGFONTW fW = {0};
4272 char bufA[LF_FACESIZE];
4273 WCHAR bufW[LF_FACESIZE];
4274 HFONT f, g;
4275 HDC dc;
4276 int n;
4278 if(!is_font_installed("Tahoma"))
4280 skip("Tahoma is not installed so skipping this test\n");
4281 return;
4284 /* 'A' case. */
4285 memcpy(fA.lfFaceName, faceA, sizeof faceA);
4286 f = CreateFontIndirectA(&fA);
4287 ok(f != NULL, "CreateFontIndirectA failed\n");
4289 dc = GetDC(NULL);
4290 g = SelectObject(dc, f);
4291 n = GetTextFaceA(dc, sizeof bufA, bufA);
4292 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
4293 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
4295 /* Play with the count arg. */
4296 bufA[0] = 'x';
4297 n = GetTextFaceA(dc, 0, bufA);
4298 ok(n == 0, "GetTextFaceA returned %d\n", n);
4299 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4301 bufA[0] = 'x';
4302 n = GetTextFaceA(dc, 1, bufA);
4303 ok(n == 0, "GetTextFaceA returned %d\n", n);
4304 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4306 bufA[0] = 'x'; bufA[1] = 'y';
4307 n = GetTextFaceA(dc, 2, bufA);
4308 ok(n == 1, "GetTextFaceA returned %d\n", n);
4309 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
4311 n = GetTextFaceA(dc, 0, NULL);
4312 ok(n == sizeof faceA ||
4313 broken(n == 0), /* win98, winMe */
4314 "GetTextFaceA returned %d\n", n);
4316 DeleteObject(SelectObject(dc, g));
4317 ReleaseDC(NULL, dc);
4319 /* 'W' case. */
4320 memcpy(fW.lfFaceName, faceW, sizeof faceW);
4321 SetLastError(0xdeadbeef);
4322 f = CreateFontIndirectW(&fW);
4323 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
4325 win_skip("CreateFontIndirectW is not implemented\n");
4326 return;
4328 ok(f != NULL, "CreateFontIndirectW failed\n");
4330 dc = GetDC(NULL);
4331 g = SelectObject(dc, f);
4332 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
4333 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4334 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
4336 /* Play with the count arg. */
4337 bufW[0] = 'x';
4338 n = GetTextFaceW(dc, 0, bufW);
4339 ok(n == 0, "GetTextFaceW returned %d\n", n);
4340 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4342 bufW[0] = 'x';
4343 n = GetTextFaceW(dc, 1, bufW);
4344 ok(n == 1, "GetTextFaceW returned %d\n", n);
4345 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4347 bufW[0] = 'x'; bufW[1] = 'y';
4348 n = GetTextFaceW(dc, 2, bufW);
4349 ok(n == 2, "GetTextFaceW returned %d\n", n);
4350 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4352 n = GetTextFaceW(dc, 0, NULL);
4353 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4355 DeleteObject(SelectObject(dc, g));
4356 ReleaseDC(NULL, dc);
4359 static void test_orientation(void)
4361 static const char test_str[11] = "Test String";
4362 HDC hdc;
4363 LOGFONTA lf;
4364 HFONT hfont, old_hfont;
4365 SIZE size;
4367 if (!is_truetype_font_installed("Arial"))
4369 skip("Arial is not installed\n");
4370 return;
4373 hdc = CreateCompatibleDC(0);
4374 memset(&lf, 0, sizeof(lf));
4375 lstrcpyA(lf.lfFaceName, "Arial");
4376 lf.lfHeight = 72;
4377 lf.lfOrientation = lf.lfEscapement = 900;
4378 hfont = create_font("orientation", &lf);
4379 old_hfont = SelectObject(hdc, hfont);
4380 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4381 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4382 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4383 SelectObject(hdc, old_hfont);
4384 DeleteObject(hfont);
4385 DeleteDC(hdc);
4388 static void test_oemcharset(void)
4390 HDC hdc;
4391 LOGFONTA lf, clf;
4392 HFONT hfont, old_hfont;
4393 int charset;
4395 hdc = CreateCompatibleDC(0);
4396 ZeroMemory(&lf, sizeof(lf));
4397 lf.lfHeight = 12;
4398 lf.lfCharSet = OEM_CHARSET;
4399 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4400 lstrcpyA(lf.lfFaceName, "Terminal");
4401 hfont = CreateFontIndirectA(&lf);
4402 old_hfont = SelectObject(hdc, hfont);
4403 charset = GetTextCharset(hdc);
4404 todo_wine
4405 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4406 hfont = SelectObject(hdc, old_hfont);
4407 GetObjectA(hfont, sizeof(clf), &clf);
4408 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4409 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4410 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4411 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4412 DeleteObject(hfont);
4413 DeleteDC(hdc);
4416 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4417 const TEXTMETRICA *lpntme,
4418 DWORD FontType, LPARAM lParam)
4420 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4421 CHARSETINFO csi;
4422 LOGFONTA lf = *lpelfe;
4423 HFONT hfont;
4424 DWORD found_subset;
4426 /* skip bitmap, proportional or vertical font */
4427 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4428 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4429 lf.lfFaceName[0] == '@')
4430 return 1;
4432 /* skip linked font */
4433 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4434 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4435 return 1;
4437 /* skip linked font, like SimSun-ExtB */
4438 switch (lpelfe->lfCharSet) {
4439 case SHIFTJIS_CHARSET:
4440 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4441 break;
4442 case GB2312_CHARSET:
4443 case CHINESEBIG5_CHARSET:
4444 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4445 break;
4446 case HANGEUL_CHARSET:
4447 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4448 break;
4449 default:
4450 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4451 break;
4453 if (!found_subset)
4454 return 1;
4456 /* test with an odd height */
4457 lf.lfHeight = -19;
4458 lf.lfWidth = 0;
4459 hfont = CreateFontIndirectA(&lf);
4460 if (hfont)
4462 *(HFONT *)lParam = hfont;
4463 return 0;
4465 return 1;
4468 static void test_GetGlyphOutline(void)
4470 HDC hdc;
4471 GLYPHMETRICS gm, gm2;
4472 LOGFONTA lf;
4473 HFONT hfont, old_hfont;
4474 INT ret, ret2;
4475 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4476 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4477 static const struct
4479 UINT cs;
4480 UINT a;
4481 UINT w;
4482 } c[] =
4484 {ANSI_CHARSET, 0x30, 0x30},
4485 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4486 {HANGEUL_CHARSET, 0x8141, 0xac02},
4487 {GB2312_CHARSET, 0x8141, 0x4e04},
4488 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4490 UINT i;
4492 if (!is_truetype_font_installed("Tahoma"))
4494 skip("Tahoma is not installed\n");
4495 return;
4498 hdc = CreateCompatibleDC(0);
4499 memset(&lf, 0, sizeof(lf));
4500 lf.lfHeight = 72;
4501 lstrcpyA(lf.lfFaceName, "Tahoma");
4502 SetLastError(0xdeadbeef);
4503 hfont = CreateFontIndirectA(&lf);
4504 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4505 old_hfont = SelectObject(hdc, hfont);
4507 memset(&gm, 0, sizeof(gm));
4508 SetLastError(0xdeadbeef);
4509 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4510 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4512 memset(&gm, 0, sizeof(gm));
4513 SetLastError(0xdeadbeef);
4514 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4515 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4516 ok(GetLastError() == 0xdeadbeef ||
4517 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4518 "expected 0xdeadbeef, got %u\n", GetLastError());
4520 memset(&gm, 0, sizeof(gm));
4521 SetLastError(0xdeadbeef);
4522 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4523 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4524 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4526 memset(&gm, 0, sizeof(gm));
4527 SetLastError(0xdeadbeef);
4528 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4529 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4531 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4532 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4535 /* test for needed buffer size request on space char */
4536 memset(&gm, 0, sizeof(gm));
4537 SetLastError(0xdeadbeef);
4538 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4539 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4541 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4542 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX);
4543 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY);
4546 /* requesting buffer size for space char + error */
4547 memset(&gm, 0, sizeof(gm));
4548 SetLastError(0xdeadbeef);
4549 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4550 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4552 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4553 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4554 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX);
4555 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY);
4558 /* test GetGlyphOutline with a buffer too small */
4559 SetLastError(0xdeadbeef);
4560 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat);
4561 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4562 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4564 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4566 DWORD dummy;
4568 memset(&gm, 0xab, sizeof(gm));
4569 SetLastError(0xdeadbeef);
4570 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4571 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4573 if (fmt[i] == GGO_METRICS)
4574 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4575 else
4576 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4577 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4578 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4581 memset(&gm, 0xab, sizeof(gm));
4582 SetLastError(0xdeadbeef);
4583 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4584 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4586 if (fmt[i] == GGO_METRICS)
4587 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4588 else
4589 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4590 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4591 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4594 memset(&gm, 0xab, sizeof(gm));
4595 SetLastError(0xdeadbeef);
4596 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4597 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4599 if (fmt[i] == GGO_METRICS)
4600 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4601 else
4602 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4603 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4604 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4607 memset(&gm, 0xab, sizeof(gm));
4608 SetLastError(0xdeadbeef);
4609 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4610 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4612 if (fmt[i] == GGO_METRICS) {
4613 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4614 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4615 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4617 else
4619 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4620 memset(&gm2, 0xab, sizeof(gm2));
4621 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4622 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4627 SelectObject(hdc, old_hfont);
4628 DeleteObject(hfont);
4630 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4632 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4633 TEXTMETRICA tm;
4635 lf.lfFaceName[0] = '\0';
4636 lf.lfCharSet = c[i].cs;
4637 lf.lfPitchAndFamily = 0;
4638 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4640 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4641 continue;
4644 old_hfont = SelectObject(hdc, hfont);
4646 /* expected to ignore superfluous bytes (sigle-byte character) */
4647 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4648 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4649 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4651 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4652 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4653 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4655 /* expected to ignore superfluous bytes (double-byte character) */
4656 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4657 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4658 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4659 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4661 /* expected to match wide-char version results */
4662 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4663 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4665 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4667 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4668 continue;
4670 DeleteObject(SelectObject(hdc, hfont));
4671 if (c[i].a <= 0xff)
4673 DeleteObject(SelectObject(hdc, old_hfont));
4674 continue;
4677 ret = GetObjectA(hfont, sizeof lf, &lf);
4678 ok(ret > 0, "GetObject error %u\n", GetLastError());
4680 ret = GetTextMetricsA(hdc, &tm);
4681 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4682 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4683 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4684 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4685 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4686 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4687 "expected %d, got %d (%s:%d)\n",
4688 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4690 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4691 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4692 ok(gm2.gmCellIncY == -lf.lfHeight,
4693 "expected %d, got %d (%s:%d)\n",
4694 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4696 lf.lfItalic = TRUE;
4697 hfont = CreateFontIndirectA(&lf);
4698 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4699 DeleteObject(SelectObject(hdc, hfont));
4700 ret = GetTextMetricsA(hdc, &tm);
4701 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4702 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4703 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4704 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4705 "expected %d, got %d (%s:%d)\n",
4706 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4708 lf.lfItalic = FALSE;
4709 lf.lfEscapement = lf.lfOrientation = 2700;
4710 hfont = CreateFontIndirectA(&lf);
4711 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4712 DeleteObject(SelectObject(hdc, hfont));
4713 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4714 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4715 ok(gm2.gmCellIncY == -lf.lfHeight,
4716 "expected %d, got %d (%s:%d)\n",
4717 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4719 hfont = SelectObject(hdc, old_hfont);
4720 DeleteObject(hfont);
4723 DeleteDC(hdc);
4726 /* bug #9995: there is a limit to the character width that can be specified */
4727 static void test_GetTextMetrics2(const char *fontname, int font_height)
4729 HFONT of, hf;
4730 HDC hdc;
4731 TEXTMETRICA tm;
4732 BOOL ret;
4733 int ave_width, height, width, ratio, scale;
4735 if (!is_truetype_font_installed( fontname)) {
4736 skip("%s is not installed\n", fontname);
4737 return;
4739 hdc = CreateCompatibleDC(0);
4740 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4741 /* select width = 0 */
4742 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4743 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4744 DEFAULT_QUALITY, VARIABLE_PITCH,
4745 fontname);
4746 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4747 of = SelectObject( hdc, hf);
4748 ret = GetTextMetricsA( hdc, &tm);
4749 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4750 height = tm.tmHeight;
4751 ave_width = tm.tmAveCharWidth;
4752 SelectObject( hdc, of);
4753 DeleteObject( hf);
4755 trace("height %d, ave width %d\n", height, ave_width);
4757 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4759 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4760 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4761 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4762 ok(hf != 0, "CreateFont failed\n");
4763 of = SelectObject(hdc, hf);
4764 ret = GetTextMetricsA(hdc, &tm);
4765 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4766 SelectObject(hdc, of);
4767 DeleteObject(hf);
4769 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4770 break;
4773 DeleteDC(hdc);
4775 ratio = width / height;
4776 scale = width / ave_width;
4778 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4779 width, height, ratio, width, ave_width, scale);
4781 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4784 static void test_CreateFontIndirect(void)
4786 LOGFONTA lf, getobj_lf;
4787 int ret, i;
4788 HFONT hfont;
4789 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4791 memset(&lf, 0, sizeof(lf));
4792 lf.lfCharSet = ANSI_CHARSET;
4793 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4794 lf.lfHeight = 16;
4795 lf.lfWidth = 16;
4796 lf.lfQuality = DEFAULT_QUALITY;
4797 lf.lfItalic = FALSE;
4798 lf.lfWeight = FW_DONTCARE;
4800 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4802 lstrcpyA(lf.lfFaceName, TestName[i]);
4803 hfont = CreateFontIndirectA(&lf);
4804 ok(hfont != 0, "CreateFontIndirectA failed\n");
4805 SetLastError(0xdeadbeef);
4806 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4807 ok(ret, "GetObject failed: %d\n", GetLastError());
4808 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4809 ok(lf.lfWeight == getobj_lf.lfWeight ||
4810 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4811 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4812 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4813 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4814 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4815 DeleteObject(hfont);
4819 static void test_CreateFontIndirectEx(void)
4821 ENUMLOGFONTEXDVA lfex;
4822 HFONT hfont;
4824 if (!pCreateFontIndirectExA)
4826 win_skip("CreateFontIndirectExA is not available\n");
4827 return;
4830 if (!is_truetype_font_installed("Arial"))
4832 skip("Arial is not installed\n");
4833 return;
4836 SetLastError(0xdeadbeef);
4837 hfont = pCreateFontIndirectExA(NULL);
4838 ok(hfont == NULL, "got %p\n", hfont);
4839 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4841 memset(&lfex, 0, sizeof(lfex));
4842 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
4843 hfont = pCreateFontIndirectExA(&lfex);
4844 ok(hfont != 0, "CreateFontIndirectEx failed\n");
4845 if (hfont)
4846 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
4847 DeleteObject(hfont);
4850 static void free_font(void *font)
4852 UnmapViewOfFile(font);
4855 static void *load_font(const char *font_name, DWORD *font_size)
4857 char file_name[MAX_PATH];
4858 HANDLE file, mapping;
4859 void *font;
4861 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
4862 strcat(file_name, "\\fonts\\");
4863 strcat(file_name, font_name);
4865 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4866 if (file == INVALID_HANDLE_VALUE) return NULL;
4868 *font_size = GetFileSize(file, NULL);
4870 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4871 if (!mapping)
4873 CloseHandle(file);
4874 return NULL;
4877 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4879 CloseHandle(file);
4880 CloseHandle(mapping);
4881 return font;
4884 static void test_AddFontMemResource(void)
4886 void *font;
4887 DWORD font_size, num_fonts;
4888 HANDLE ret;
4889 BOOL bRet;
4891 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4893 win_skip("AddFontMemResourceEx is not available on this platform\n");
4894 return;
4897 font = load_font("sserife.fon", &font_size);
4898 if (!font)
4900 skip("Unable to locate and load font sserife.fon\n");
4901 return;
4904 SetLastError(0xdeadbeef);
4905 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4906 ok(!ret, "AddFontMemResourceEx should fail\n");
4907 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4908 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4909 GetLastError());
4911 SetLastError(0xdeadbeef);
4912 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4913 ok(!ret, "AddFontMemResourceEx should fail\n");
4914 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4915 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4916 GetLastError());
4918 SetLastError(0xdeadbeef);
4919 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4920 ok(!ret, "AddFontMemResourceEx should fail\n");
4921 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4922 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4923 GetLastError());
4925 SetLastError(0xdeadbeef);
4926 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4927 ok(!ret, "AddFontMemResourceEx should fail\n");
4928 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4929 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4930 GetLastError());
4932 SetLastError(0xdeadbeef);
4933 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4934 ok(!ret, "AddFontMemResourceEx should fail\n");
4935 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4936 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4937 GetLastError());
4939 SetLastError(0xdeadbeef);
4940 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4941 ok(!ret, "AddFontMemResourceEx should fail\n");
4942 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4943 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4944 GetLastError());
4946 num_fonts = 0xdeadbeef;
4947 SetLastError(0xdeadbeef);
4948 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4949 ok(!ret, "AddFontMemResourceEx should fail\n");
4950 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4951 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4952 GetLastError());
4953 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4955 if (0) /* hangs under windows 2000 */
4957 num_fonts = 0xdeadbeef;
4958 SetLastError(0xdeadbeef);
4959 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4960 ok(!ret, "AddFontMemResourceEx should fail\n");
4961 ok(GetLastError() == 0xdeadbeef,
4962 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4963 GetLastError());
4964 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4967 num_fonts = 0xdeadbeef;
4968 SetLastError(0xdeadbeef);
4969 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4970 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4971 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4972 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4974 free_font(font);
4976 SetLastError(0xdeadbeef);
4977 bRet = pRemoveFontMemResourceEx(ret);
4978 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4980 /* test invalid pointer to number of loaded fonts */
4981 font = load_font("sserife.fon", &font_size);
4982 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4984 SetLastError(0xdeadbeef);
4985 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4986 ok(!ret, "AddFontMemResourceEx should fail\n");
4987 ok(GetLastError() == 0xdeadbeef,
4988 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4989 GetLastError());
4991 SetLastError(0xdeadbeef);
4992 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4993 ok(!ret, "AddFontMemResourceEx should fail\n");
4994 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4995 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4996 GetLastError());
4998 free_font(font);
5001 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5003 LOGFONTA *lf;
5005 if (type != TRUETYPE_FONTTYPE) return 1;
5007 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5009 lf = (LOGFONTA *)lparam;
5010 *lf = *elf;
5011 return 0;
5014 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5016 int ret;
5017 LOGFONTA *lf;
5019 if (type != TRUETYPE_FONTTYPE) return 1;
5021 lf = (LOGFONTA *)lparam;
5022 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
5023 if(ret == 0)
5025 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5026 *lf = *elf;
5027 return 0;
5029 return 1;
5032 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5034 return lparam;
5037 static void test_EnumFonts(void)
5039 int ret;
5040 LOGFONTA lf;
5041 HDC hdc;
5043 if (!is_truetype_font_installed("Arial"))
5045 skip("Arial is not installed\n");
5046 return;
5049 /* Windows uses localized font face names, so Arial Bold won't be found */
5050 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
5052 skip("User locale is not English, skipping the test\n");
5053 return;
5056 hdc = CreateCompatibleDC(0);
5058 /* check that the enumproc's retval is returned */
5059 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
5060 ok(ret == 0xcafe, "got %08x\n", ret);
5062 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
5063 ok(!ret, "font Arial is not enumerated\n");
5064 ret = strcmp(lf.lfFaceName, "Arial");
5065 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5066 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5068 strcpy(lf.lfFaceName, "Arial");
5069 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5070 ok(!ret, "font Arial is not enumerated\n");
5071 ret = strcmp(lf.lfFaceName, "Arial");
5072 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5073 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5075 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
5076 ok(!ret, "font Arial Bold is not enumerated\n");
5077 ret = strcmp(lf.lfFaceName, "Arial");
5078 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5079 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5081 strcpy(lf.lfFaceName, "Arial Bold");
5082 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5083 ok(ret, "font Arial Bold should not be enumerated\n");
5085 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
5086 ok(!ret, "font Arial Bold Italic is not enumerated\n");
5087 ret = strcmp(lf.lfFaceName, "Arial");
5088 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5089 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5091 strcpy(lf.lfFaceName, "Arial Bold Italic");
5092 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5093 ok(ret, "font Arial Bold Italic should not be enumerated\n");
5095 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
5096 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5098 strcpy(lf.lfFaceName, "Arial Italic Bold");
5099 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5100 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5102 DeleteDC(hdc);
5105 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5107 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5109 if (0) /* Disabled to limit console spam */
5110 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5111 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5113 if (type != TRUETYPE_FONTTYPE) return 1;
5114 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1;
5116 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5117 return 0;
5120 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5122 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5124 if (0) /* Disabled to limit console spam */
5125 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5126 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5128 if (type != TRUETYPE_FONTTYPE) return 1;
5129 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1;
5131 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5132 return 0;
5135 static void test_EnumFonts_subst(void)
5137 int ret;
5138 LOGFONTA lf;
5139 HDC hdc;
5140 struct enum_fullname_data efnd;
5142 ret = is_font_installed("MS Shell Dlg");
5143 ok(ret, "MS Shell Dlg should be enumerated\n");
5144 ret = is_truetype_font_installed("MS Shell Dlg");
5145 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n");
5147 ret = is_font_installed("MS Shell Dlg 2");
5148 ok(ret, "MS Shell Dlg 2 should be enumerated\n");
5149 ret = is_truetype_font_installed("MS Shell Dlg 2");
5150 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5152 hdc = CreateCompatibleDC(0);
5154 memset(&efnd, 0, sizeof(efnd));
5155 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5156 ok(ret, "MS Shell Dlg should not be enumerated\n");
5157 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n");
5159 memset(&lf, 0, sizeof(lf));
5160 lf.lfCharSet = DEFAULT_CHARSET;
5162 memset(&efnd, 0, sizeof(efnd));
5163 strcpy(lf.lfFaceName, "MS Shell Dlg");
5164 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5165 ok(!ret, "MS Shell Dlg should be enumerated\n");
5166 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n");
5167 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
5168 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5169 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg");
5170 ok(ret, "did not expect MS Shell Dlg\n");
5172 memset(&efnd, 0, sizeof(efnd));
5173 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5174 ok(ret, "MS Shell Dlg 2 should not be enumerated\n");
5175 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n");
5177 memset(&efnd, 0, sizeof(efnd));
5178 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
5179 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5180 ok(!ret, "MS Shell Dlg 2 should be enumerated\n");
5181 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n");
5182 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
5183 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5184 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
5185 ok(ret, "did not expect MS Shell Dlg 2\n");
5187 DeleteDC(hdc);
5190 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5192 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
5193 const char *fullname = (const char *)lParam;
5195 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
5197 return 1;
5200 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
5202 HDC hdc = GetDC(0);
5203 BOOL ret = FALSE;
5205 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
5206 ret = TRUE;
5208 ReleaseDC(0, hdc);
5209 return ret;
5212 static void test_fullname(void)
5214 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5215 WCHAR bufW[LF_FULLFACESIZE];
5216 char bufA[LF_FULLFACESIZE];
5217 HFONT hfont, of;
5218 LOGFONTA lf;
5219 HDC hdc;
5220 int i;
5221 DWORD ret;
5223 hdc = CreateCompatibleDC(0);
5224 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5226 memset(&lf, 0, sizeof(lf));
5227 lf.lfCharSet = ANSI_CHARSET;
5228 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5229 lf.lfHeight = 16;
5230 lf.lfWidth = 16;
5231 lf.lfQuality = DEFAULT_QUALITY;
5232 lf.lfItalic = FALSE;
5233 lf.lfWeight = FW_DONTCARE;
5235 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
5237 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
5239 skip("%s is not installed\n", TestName[i]);
5240 continue;
5243 lstrcpyA(lf.lfFaceName, TestName[i]);
5244 hfont = CreateFontIndirectA(&lf);
5245 ok(hfont != 0, "CreateFontIndirectA failed\n");
5247 of = SelectObject(hdc, hfont);
5248 bufW[0] = 0;
5249 bufA[0] = 0;
5250 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
5251 ok(ret, "face full name could not be read\n");
5252 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
5253 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
5254 SelectObject(hdc, of);
5255 DeleteObject(hfont);
5257 DeleteDC(hdc);
5260 static WCHAR *prepend_at(WCHAR *family)
5262 if (!family)
5263 return NULL;
5265 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
5266 family[0] = '@';
5267 return family;
5270 static void test_fullname2_helper(const char *Family)
5272 char *FamilyName, *FaceName, *StyleName, *otmStr;
5273 struct enum_fullname_data efnd;
5274 WCHAR *bufW;
5275 char *bufA;
5276 HFONT hfont, of;
5277 LOGFONTA lf;
5278 HDC hdc;
5279 int i;
5280 DWORD otm_size, ret, buf_size;
5281 OUTLINETEXTMETRICA *otm;
5282 BOOL want_vertical, get_vertical;
5283 want_vertical = ( Family[0] == '@' );
5285 hdc = CreateCompatibleDC(0);
5286 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5288 memset(&lf, 0, sizeof(lf));
5289 lf.lfCharSet = DEFAULT_CHARSET;
5290 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5291 lf.lfHeight = 16;
5292 lf.lfWidth = 16;
5293 lf.lfQuality = DEFAULT_QUALITY;
5294 lf.lfItalic = FALSE;
5295 lf.lfWeight = FW_DONTCARE;
5296 strcpy(lf.lfFaceName, Family);
5297 efnd.total = 0;
5298 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
5299 if (efnd.total == 0)
5300 skip("%s is not installed\n", lf.lfFaceName);
5302 for (i = 0; i < efnd.total; i++)
5304 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
5305 FaceName = (char *)efnd.elf[i].elfFullName;
5306 StyleName = (char *)efnd.elf[i].elfStyle;
5308 get_vertical = ( FamilyName[0] == '@' );
5309 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
5311 lstrcpyA(lf.lfFaceName, FaceName);
5312 hfont = CreateFontIndirectA(&lf);
5313 ok(hfont != 0, "CreateFontIndirectA failed\n");
5315 of = SelectObject(hdc, hfont);
5316 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
5317 ok(buf_size != GDI_ERROR, "no name table found\n");
5318 if (buf_size == GDI_ERROR) continue;
5320 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
5321 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
5323 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5324 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5325 memset(otm, 0, otm_size);
5326 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
5327 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
5328 if (ret == 0) continue;
5330 bufW[0] = 0;
5331 bufA[0] = 0;
5332 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
5333 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5334 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
5335 if (want_vertical) bufW = prepend_at(bufW);
5336 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5337 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
5338 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
5339 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
5341 bufW[0] = 0;
5342 bufA[0] = 0;
5343 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
5344 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5345 ok(ret, "FULL_NAME (face name) could not be read\n");
5346 if (want_vertical) bufW = prepend_at(bufW);
5347 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5348 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
5349 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
5350 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
5352 bufW[0] = 0;
5353 bufA[0] = 0;
5354 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
5355 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5356 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
5357 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5358 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
5359 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
5360 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
5362 bufW[0] = 0;
5363 bufA[0] = 0;
5364 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
5365 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5366 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
5367 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5368 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
5369 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
5371 SelectObject(hdc, of);
5372 DeleteObject(hfont);
5374 HeapFree(GetProcessHeap(), 0, otm);
5375 HeapFree(GetProcessHeap(), 0, bufW);
5376 HeapFree(GetProcessHeap(), 0, bufA);
5378 DeleteDC(hdc);
5381 static void test_fullname2(void)
5383 test_fullname2_helper("Arial");
5384 test_fullname2_helper("DejaVu Sans");
5385 test_fullname2_helper("Lucida Sans");
5386 test_fullname2_helper("Tahoma");
5387 test_fullname2_helper("Webdings");
5388 test_fullname2_helper("Wingdings");
5389 test_fullname2_helper("SimSun");
5390 test_fullname2_helper("NSimSun");
5391 test_fullname2_helper("MingLiu");
5392 test_fullname2_helper("PMingLiu");
5393 test_fullname2_helper("WenQuanYi Micro Hei");
5394 test_fullname2_helper("MS UI Gothic");
5395 test_fullname2_helper("Ume UI Gothic");
5396 test_fullname2_helper("MS Gothic");
5397 test_fullname2_helper("Ume Gothic");
5398 test_fullname2_helper("MS PGothic");
5399 test_fullname2_helper("Ume P Gothic");
5400 test_fullname2_helper("Gulim");
5401 test_fullname2_helper("Batang");
5402 test_fullname2_helper("UnBatang");
5403 test_fullname2_helper("UnDotum");
5404 test_fullname2_helper("@SimSun");
5405 test_fullname2_helper("@NSimSun");
5406 test_fullname2_helper("@MingLiu");
5407 test_fullname2_helper("@PMingLiu");
5408 test_fullname2_helper("@WenQuanYi Micro Hei");
5409 test_fullname2_helper("@MS UI Gothic");
5410 test_fullname2_helper("@Ume UI Gothic");
5411 test_fullname2_helper("@MS Gothic");
5412 test_fullname2_helper("@Ume Gothic");
5413 test_fullname2_helper("@MS PGothic");
5414 test_fullname2_helper("@Ume P Gothic");
5415 test_fullname2_helper("@Gulim");
5416 test_fullname2_helper("@Batang");
5417 test_fullname2_helper("@UnBatang");
5418 test_fullname2_helper("@UnDotum");
5422 static void test_GetGlyphOutline_empty_contour(void)
5424 HDC hdc;
5425 LOGFONTA lf;
5426 HFONT hfont, hfont_prev;
5427 TTPOLYGONHEADER *header;
5428 GLYPHMETRICS gm;
5429 char buf[1024];
5430 DWORD ret;
5432 memset(&lf, 0, sizeof(lf));
5433 lf.lfHeight = 72;
5434 lstrcpyA(lf.lfFaceName, "wine_test");
5436 hfont = CreateFontIndirectA(&lf);
5437 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5439 hdc = GetDC(NULL);
5441 hfont_prev = SelectObject(hdc, hfont);
5442 ok(hfont_prev != NULL, "SelectObject failed\n");
5444 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5445 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5447 header = (TTPOLYGONHEADER*)buf;
5448 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5449 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5450 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5451 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5452 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5453 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5454 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5455 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5457 SelectObject(hdc, hfont_prev);
5458 DeleteObject(hfont);
5459 ReleaseDC(NULL, hdc);
5462 static void test_GetGlyphOutline_metric_clipping(void)
5464 HDC hdc;
5465 LOGFONTA lf;
5466 HFONT hfont, hfont_prev;
5467 GLYPHMETRICS gm;
5468 TEXTMETRICA tm;
5469 TEXTMETRICW tmW;
5470 DWORD ret;
5472 memset(&lf, 0, sizeof(lf));
5473 lf.lfHeight = 72;
5474 lstrcpyA(lf.lfFaceName, "wine_test");
5476 SetLastError(0xdeadbeef);
5477 hfont = CreateFontIndirectA(&lf);
5478 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5480 hdc = GetDC(NULL);
5482 hfont_prev = SelectObject(hdc, hfont);
5483 ok(hfont_prev != NULL, "SelectObject failed\n");
5485 SetLastError(0xdeadbeef);
5486 ret = GetTextMetricsA(hdc, &tm);
5487 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5489 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5490 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5491 "Glyph top(%d) exceeds ascent(%d)\n",
5492 gm.gmptGlyphOrigin.y, tm.tmAscent);
5493 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5494 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5495 "Glyph bottom(%d) exceeds descent(%d)\n",
5496 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5498 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5499 GetTextMetricsW(hdc, &tmW);
5500 todo_wine
5501 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5503 SelectObject(hdc, hfont_prev);
5504 DeleteObject(hfont);
5505 ReleaseDC(NULL, hdc);
5508 static void test_CreateScalableFontResource(void)
5510 char ttf_name[MAX_PATH];
5511 char tmp_path[MAX_PATH];
5512 char fot_name[MAX_PATH];
5513 char *file_part;
5514 DWORD ret;
5515 int i;
5517 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5519 win_skip("AddFontResourceExA is not available on this platform\n");
5520 return;
5523 if (!write_ttf_file("wine_test.ttf", ttf_name))
5525 skip("Failed to create ttf file for testing\n");
5526 return;
5529 trace("created %s\n", ttf_name);
5531 ret = is_truetype_font_installed("wine_test");
5532 ok(!ret, "font wine_test should not be enumerated\n");
5534 ret = GetTempPathA(MAX_PATH, tmp_path);
5535 ok(ret, "GetTempPath() error %d\n", GetLastError());
5536 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5537 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5539 ret = GetFileAttributesA(fot_name);
5540 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5542 SetLastError(0xdeadbeef);
5543 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5544 ok(!ret, "CreateScalableFontResource() should fail\n");
5545 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5547 SetLastError(0xdeadbeef);
5548 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5549 ok(!ret, "CreateScalableFontResource() should fail\n");
5550 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5552 file_part = strrchr(ttf_name, '\\');
5553 SetLastError(0xdeadbeef);
5554 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5555 ok(!ret, "CreateScalableFontResource() should fail\n");
5556 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5558 SetLastError(0xdeadbeef);
5559 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5560 ok(!ret, "CreateScalableFontResource() should fail\n");
5561 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5563 SetLastError(0xdeadbeef);
5564 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5565 ok(!ret, "CreateScalableFontResource() should fail\n");
5566 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5568 ret = DeleteFileA(fot_name);
5569 ok(ret, "DeleteFile() error %d\n", GetLastError());
5571 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5572 ok(!ret, "RemoveFontResourceEx() should fail\n");
5574 /* test public font resource */
5575 SetLastError(0xdeadbeef);
5576 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5577 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5579 ret = is_truetype_font_installed("wine_test");
5580 ok(!ret, "font wine_test should not be enumerated\n");
5582 SetLastError(0xdeadbeef);
5583 ret = pAddFontResourceExA(fot_name, 0, 0);
5584 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5586 ret = is_truetype_font_installed("wine_test");
5587 ok(ret, "font wine_test should be enumerated\n");
5589 test_GetGlyphOutline_empty_contour();
5590 test_GetGlyphOutline_metric_clipping();
5592 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5593 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5595 SetLastError(0xdeadbeef);
5596 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5597 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5599 ret = is_truetype_font_installed("wine_test");
5600 ok(!ret, "font wine_test should not be enumerated\n");
5602 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5603 ok(!ret, "RemoveFontResourceEx() should fail\n");
5605 /* test refcounting */
5606 for (i = 0; i < 5; i++)
5608 SetLastError(0xdeadbeef);
5609 ret = pAddFontResourceExA(fot_name, 0, 0);
5610 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5612 for (i = 0; i < 5; i++)
5614 SetLastError(0xdeadbeef);
5615 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5616 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5618 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5619 ok(!ret, "RemoveFontResourceEx() should fail\n");
5621 DeleteFileA(fot_name);
5623 /* test hidden font resource */
5624 SetLastError(0xdeadbeef);
5625 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5626 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5628 ret = is_truetype_font_installed("wine_test");
5629 ok(!ret, "font wine_test should not be enumerated\n");
5631 SetLastError(0xdeadbeef);
5632 ret = pAddFontResourceExA(fot_name, 0, 0);
5633 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5635 ret = is_truetype_font_installed("wine_test");
5636 todo_wine
5637 ok(!ret, "font wine_test should not be enumerated\n");
5639 /* XP allows removing a private font added with 0 flags */
5640 SetLastError(0xdeadbeef);
5641 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5642 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5644 ret = is_truetype_font_installed("wine_test");
5645 ok(!ret, "font wine_test should not be enumerated\n");
5647 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5648 ok(!ret, "RemoveFontResourceEx() should fail\n");
5650 DeleteFileA(fot_name);
5651 DeleteFileA(ttf_name);
5654 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5656 LOGFONTA lf;
5657 HFONT hfont, hfont_prev;
5658 HDC hdc;
5659 char facename[100];
5660 DWORD ret;
5661 static const WCHAR str[] = { 0x2025 };
5663 *installed = is_truetype_font_installed(name);
5665 lf.lfHeight = -18;
5666 lf.lfWidth = 0;
5667 lf.lfEscapement = 0;
5668 lf.lfOrientation = 0;
5669 lf.lfWeight = FW_DONTCARE;
5670 lf.lfItalic = 0;
5671 lf.lfUnderline = 0;
5672 lf.lfStrikeOut = 0;
5673 lf.lfCharSet = DEFAULT_CHARSET;
5674 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5675 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5676 lf.lfQuality = DEFAULT_QUALITY;
5677 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5678 strcpy(lf.lfFaceName, name);
5680 hfont = CreateFontIndirectA(&lf);
5681 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5683 hdc = GetDC(NULL);
5685 hfont_prev = SelectObject(hdc, hfont);
5686 ok(hfont_prev != NULL, "SelectObject failed\n");
5688 ret = GetTextFaceA(hdc, sizeof facename, facename);
5689 ok(ret, "GetTextFaceA failed\n");
5690 *selected = !strcmp(facename, name);
5692 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5693 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5694 if (!*selected)
5695 memset(gm, 0, sizeof *gm);
5697 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5698 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5700 SelectObject(hdc, hfont_prev);
5701 DeleteObject(hfont);
5702 ReleaseDC(NULL, hdc);
5705 static void check_vertical_metrics(const char *face)
5707 LOGFONTA lf;
5708 HFONT hfont, hfont_prev;
5709 HDC hdc;
5710 DWORD ret;
5711 GLYPHMETRICS rgm, vgm;
5712 const UINT code = 0x5EAD, height = 1000;
5713 WORD idx;
5714 ABC abc;
5715 OUTLINETEXTMETRICA otm;
5716 USHORT numOfLongVerMetrics;
5718 hdc = GetDC(NULL);
5720 memset(&lf, 0, sizeof(lf));
5721 strcpy(lf.lfFaceName, face);
5722 lf.lfHeight = -height;
5723 lf.lfCharSet = DEFAULT_CHARSET;
5724 lf.lfEscapement = lf.lfOrientation = 900;
5725 hfont = CreateFontIndirectA(&lf);
5726 hfont_prev = SelectObject(hdc, hfont);
5727 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5728 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5729 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5730 ok(ret, "GetCharABCWidthsW failed\n");
5731 DeleteObject(SelectObject(hdc, hfont_prev));
5733 memset(&lf, 0, sizeof(lf));
5734 strcpy(lf.lfFaceName, "@");
5735 strcat(lf.lfFaceName, face);
5736 lf.lfHeight = -height;
5737 lf.lfCharSet = DEFAULT_CHARSET;
5738 hfont = CreateFontIndirectA(&lf);
5739 hfont_prev = SelectObject(hdc, hfont);
5740 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5741 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5743 memset(&otm, 0, sizeof(otm));
5744 otm.otmSize = sizeof(otm);
5745 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5746 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5748 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5749 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5750 int offset;
5751 SHORT topSideBearing;
5753 if (!pGetGlyphIndicesW) {
5754 win_skip("GetGlyphIndices is not available on this platform\n");
5756 else {
5757 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5758 ok(ret != 0, "GetGlyphIndicesW failed\n");
5759 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5760 if (numOfLongVerMetrics > idx)
5761 offset = idx * 2 + 1;
5762 else
5763 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5764 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5765 &topSideBearing, sizeof(SHORT));
5766 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5767 topSideBearing = GET_BE_WORD(topSideBearing);
5768 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5769 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5770 "expected %d, got %d\n",
5771 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5774 else
5776 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5777 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5778 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5781 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
5782 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
5783 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5784 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
5786 DeleteObject(SelectObject(hdc, hfont_prev));
5787 ReleaseDC(NULL, hdc);
5790 static void test_vertical_font(void)
5792 char ttf_name[MAX_PATH];
5793 int num, i;
5794 BOOL ret, installed, selected;
5795 GLYPHMETRICS gm;
5796 WORD hgi, vgi;
5797 const char* face_list[] = {
5798 "@WineTestVertical", /* has vmtx table */
5799 "@Ume Gothic", /* doesn't have vmtx table */
5800 "@MS UI Gothic", /* has vmtx table, available on native */
5803 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
5805 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5806 return;
5809 if (!write_ttf_file("vertical.ttf", ttf_name))
5811 skip("Failed to create ttf file for testing\n");
5812 return;
5815 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
5816 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5818 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
5819 ok(installed, "WineTestVertical is not installed\n");
5820 ok(selected, "WineTestVertical is not selected\n");
5821 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5822 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5823 gm.gmBlackBoxX, gm.gmBlackBoxY);
5825 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
5826 ok(installed, "@WineTestVertical is not installed\n");
5827 ok(selected, "@WineTestVertical is not selected\n");
5828 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5829 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5830 gm.gmBlackBoxX, gm.gmBlackBoxY);
5832 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
5834 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
5835 const char* face = face_list[i];
5836 if (!is_truetype_font_installed(face)) {
5837 skip("%s is not installed\n", face);
5838 continue;
5840 trace("Testing %s...\n", face);
5841 check_vertical_metrics(&face[1]);
5844 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
5845 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5847 DeleteFileA(ttf_name);
5850 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
5851 DWORD type, LPARAM lParam)
5853 if (lf->lfFaceName[0] == '@') {
5854 return 0;
5856 return 1;
5859 static void test_east_asian_font_selection(void)
5861 HDC hdc;
5862 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
5863 GB2312_CHARSET, CHINESEBIG5_CHARSET };
5864 size_t i;
5866 hdc = GetDC(NULL);
5868 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
5870 LOGFONTA lf;
5871 HFONT hfont;
5872 char face_name[LF_FACESIZE];
5873 int ret;
5875 memset(&lf, 0, sizeof lf);
5876 lf.lfFaceName[0] = '\0';
5877 lf.lfCharSet = charset[i];
5879 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
5881 skip("Vertical font for charset %u is not installed\n", charset[i]);
5882 continue;
5885 hfont = CreateFontIndirectA(&lf);
5886 hfont = SelectObject(hdc, hfont);
5887 memset(face_name, 0, sizeof face_name);
5888 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5889 ok(ret && face_name[0] != '@',
5890 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
5891 DeleteObject(SelectObject(hdc, hfont));
5893 memset(&lf, 0, sizeof lf);
5894 strcpy(lf.lfFaceName, "@");
5895 lf.lfCharSet = charset[i];
5896 hfont = CreateFontIndirectA(&lf);
5897 hfont = SelectObject(hdc, hfont);
5898 memset(face_name, 0, sizeof face_name);
5899 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5900 ok(ret && face_name[0] == '@',
5901 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
5902 DeleteObject(SelectObject(hdc, hfont));
5904 ReleaseDC(NULL, hdc);
5907 static int get_font_dpi(const LOGFONTA *lf, int *height)
5909 HDC hdc = CreateCompatibleDC(0);
5910 HFONT hfont;
5911 TEXTMETRICA tm;
5912 int ret;
5914 hfont = CreateFontIndirectA(lf);
5915 ok(hfont != 0, "CreateFontIndirect failed\n");
5917 SelectObject(hdc, hfont);
5918 ret = GetTextMetricsA(hdc, &tm);
5919 ok(ret, "GetTextMetrics failed\n");
5920 ret = tm.tmDigitizedAspectX;
5921 if (height) *height = tm.tmHeight;
5923 DeleteDC(hdc);
5924 DeleteObject(hfont);
5926 return ret;
5929 static void test_stock_fonts(void)
5931 static const int font[] =
5933 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
5934 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5936 static const struct test_data
5938 int charset, weight, height, height_pixels, dpi;
5939 const char face_name[LF_FACESIZE];
5940 WORD lang_id;
5941 } td[][12] =
5943 { /* ANSI_FIXED_FONT */
5944 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
5945 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
5946 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
5947 { 0 }
5949 { /* ANSI_VAR_FONT */
5950 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
5951 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
5952 { 0 }
5954 { /* SYSTEM_FONT */
5955 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5956 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5957 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5958 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5959 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5960 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5961 { 0 }
5963 { /* DEVICE_DEFAULT_FONT */
5964 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
5965 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
5966 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
5967 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
5968 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
5969 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
5970 { 0 }
5972 { /* DEFAULT_GUI_FONT */
5973 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5974 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
5975 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
5976 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
5977 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
5978 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
5979 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
5980 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
5981 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
5982 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
5983 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
5984 { 0 }
5987 int i, j;
5989 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
5991 HFONT hfont;
5992 LOGFONTA lf;
5993 int ret, height;
5995 hfont = GetStockObject(font[i]);
5996 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
5998 ret = GetObjectA(hfont, sizeof(lf), &lf);
5999 if (ret != sizeof(lf))
6001 /* NT4 */
6002 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
6003 continue;
6006 for (j = 0; td[i][j].face_name[0] != 0; j++)
6008 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) ||
6009 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) ||
6010 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name)))
6012 continue;
6015 ret = get_font_dpi(&lf, &height);
6016 if (ret != td[i][j].dpi)
6018 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6019 i, j, lf.lfFaceName, ret, td[i][j].dpi);
6020 continue;
6023 /* FIXME: Remove once Wine is fixed */
6024 if (td[i][j].dpi != 96 &&
6025 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6026 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
6027 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6028 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
6029 todo_wine
6030 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6031 else
6032 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6034 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
6035 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
6036 if (td[i][j].face_name[0] == '?')
6038 /* Wine doesn't have this font, skip this case for now.
6039 Actually, the face name is localized on Windows and varies
6040 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6041 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
6043 else
6045 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);
6047 break;
6052 static void test_max_height(void)
6054 HDC hdc;
6055 LOGFONTA lf;
6056 HFONT hfont, hfont_old;
6057 TEXTMETRICA tm1, tm;
6058 BOOL r;
6059 LONG invalid_height[] = { -65536, -123456, 123456 };
6060 size_t i;
6062 memset(&tm1, 0, sizeof(tm1));
6063 memset(&lf, 0, sizeof(lf));
6064 strcpy(lf.lfFaceName, "Tahoma");
6065 lf.lfHeight = -1;
6067 hdc = GetDC(NULL);
6069 /* get 1 ppem value */
6070 hfont = CreateFontIndirectA(&lf);
6071 hfont_old = SelectObject(hdc, hfont);
6072 r = GetTextMetricsA(hdc, &tm1);
6073 ok(r, "GetTextMetrics failed\n");
6074 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6075 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6076 DeleteObject(SelectObject(hdc, hfont_old));
6078 /* test the largest value */
6079 lf.lfHeight = -((1 << 16) - 1);
6080 hfont = CreateFontIndirectA(&lf);
6081 hfont_old = SelectObject(hdc, hfont);
6082 memset(&tm, 0, sizeof(tm));
6083 r = GetTextMetricsA(hdc, &tm);
6084 ok(r, "GetTextMetrics failed\n");
6085 ok(tm.tmHeight > tm1.tmHeight,
6086 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6087 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
6088 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6089 DeleteObject(SelectObject(hdc, hfont_old));
6091 /* test an invalid value */
6092 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
6093 lf.lfHeight = invalid_height[i];
6094 hfont = CreateFontIndirectA(&lf);
6095 hfont_old = SelectObject(hdc, hfont);
6096 memset(&tm, 0, sizeof(tm));
6097 r = GetTextMetricsA(hdc, &tm);
6098 ok(r, "GetTextMetrics failed\n");
6099 ok(tm.tmHeight == tm1.tmHeight,
6100 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6101 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
6102 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6103 DeleteObject(SelectObject(hdc, hfont_old));
6106 ReleaseDC(NULL, hdc);
6107 return;
6110 static void test_vertical_order(void)
6112 struct enum_font_data efd;
6113 LOGFONTA lf;
6114 HDC hdc;
6115 int i, j;
6117 hdc = CreateCompatibleDC(0);
6118 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6120 memset(&lf, 0, sizeof(lf));
6121 lf.lfCharSet = DEFAULT_CHARSET;
6122 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6123 lf.lfHeight = 16;
6124 lf.lfWidth = 16;
6125 lf.lfQuality = DEFAULT_QUALITY;
6126 lf.lfItalic = FALSE;
6127 lf.lfWeight = FW_DONTCARE;
6128 efd.total = 0;
6129 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
6130 for (i = 0; i < efd.total; i++)
6132 if (efd.lf[i].lfFaceName[0] != '@') continue;
6133 for (j = 0; j < efd.total; j++)
6135 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
6137 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
6138 break;
6142 DeleteDC( hdc );
6145 static void test_GetCharWidth32(void)
6147 BOOL ret;
6148 HDC hdc;
6149 LOGFONTA lf;
6150 HFONT hfont;
6151 INT bufferA;
6152 INT bufferW;
6153 HWND hwnd;
6155 if (!pGetCharWidth32A || !pGetCharWidth32W)
6157 win_skip("GetCharWidth32A/W not available on this platform\n");
6158 return;
6161 memset(&lf, 0, sizeof(lf));
6162 strcpy(lf.lfFaceName, "System");
6163 lf.lfHeight = 20;
6165 hfont = CreateFontIndirectA(&lf);
6166 hdc = GetDC(0);
6167 hfont = SelectObject(hdc, hfont);
6169 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6170 ok(ret, "GetCharWidth32W should have succeeded\n");
6171 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
6172 ok(ret, "GetCharWidth32A should have succeeded\n");
6173 ok (bufferA == bufferW, "Widths should be the same\n");
6174 ok (bufferA > 0," Width should be greater than zero\n");
6176 hfont = SelectObject(hdc, hfont);
6177 DeleteObject(hfont);
6178 ReleaseDC(NULL, hdc);
6180 memset(&lf, 0, sizeof(lf));
6181 strcpy(lf.lfFaceName, "Tahoma");
6182 lf.lfHeight = 20;
6184 hfont = CreateFontIndirectA(&lf);
6185 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
6186 0, 0, 0, NULL);
6187 hdc = GetDC(hwnd);
6188 SetMapMode( hdc, MM_ANISOTROPIC );
6189 SelectObject(hdc, hfont);
6191 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6192 ok(ret, "GetCharWidth32W should have succeeded\n");
6193 ok (bufferW > 0," Width should be greater than zero\n");
6194 SetWindowExtEx(hdc, -1,-1,NULL);
6195 SetGraphicsMode(hdc, GM_COMPATIBLE);
6196 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6197 ok(ret, "GetCharWidth32W should have succeeded\n");
6198 ok (bufferW > 0," Width should be greater than zero\n");
6199 SetGraphicsMode(hdc, GM_ADVANCED);
6200 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6201 ok(ret, "GetCharWidth32W should have succeeded\n");
6202 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6203 SetWindowExtEx(hdc, 1,1,NULL);
6204 SetGraphicsMode(hdc, GM_COMPATIBLE);
6205 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6206 ok(ret, "GetCharWidth32W should have succeeded\n");
6207 ok (bufferW > 0," Width should be greater than zero\n");
6208 SetGraphicsMode(hdc, GM_ADVANCED);
6209 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6210 ok(ret, "GetCharWidth32W should have succeeded\n");
6211 ok (bufferW > 0," Width should be greater than zero\n");
6213 ReleaseDC(hwnd, hdc);
6214 DestroyWindow(hwnd);
6216 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
6217 0, 0, 0, NULL);
6218 hdc = GetDC(hwnd);
6219 SetMapMode( hdc, MM_ANISOTROPIC );
6220 SelectObject(hdc, hfont);
6222 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6223 ok(ret, "GetCharWidth32W should have succeeded\n");
6224 ok (bufferW > 0," Width should be greater than zero\n");
6225 SetWindowExtEx(hdc, -1,-1,NULL);
6226 SetGraphicsMode(hdc, GM_COMPATIBLE);
6227 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6228 ok(ret, "GetCharWidth32W should have succeeded\n");
6229 ok (bufferW > 0," Width should be greater than zero\n");
6230 SetGraphicsMode(hdc, GM_ADVANCED);
6231 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6232 ok(ret, "GetCharWidth32W should have succeeded\n");
6233 ok (bufferW > 0," Width should be greater than zero\n");
6234 SetWindowExtEx(hdc, 1,1,NULL);
6235 SetGraphicsMode(hdc, GM_COMPATIBLE);
6236 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6237 ok(ret, "GetCharWidth32W should have succeeded\n");
6238 ok (bufferW > 0," Width should be greater than zero\n");
6239 SetGraphicsMode(hdc, GM_ADVANCED);
6240 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6241 ok(ret, "GetCharWidth32W should have succeeded\n");
6242 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6244 ReleaseDC(hwnd, hdc);
6245 DestroyWindow(hwnd);
6246 DeleteObject(hfont);
6249 static void test_fake_bold_font(void)
6251 HDC hdc;
6252 HFONT hfont, hfont_old;
6253 LOGFONTA lf;
6254 BOOL ret;
6255 TEXTMETRICA tm[2];
6256 ABC abc[2];
6257 INT w[2];
6259 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
6260 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6261 return;
6264 /* Test outline font */
6265 memset(&lf, 0, sizeof(lf));
6266 strcpy(lf.lfFaceName, "Wingdings");
6267 lf.lfWeight = FW_NORMAL;
6268 lf.lfCharSet = SYMBOL_CHARSET;
6269 hfont = CreateFontIndirectA(&lf);
6271 hdc = GetDC(NULL);
6272 hfont_old = SelectObject(hdc, hfont);
6274 /* base metrics */
6275 ret = GetTextMetricsA(hdc, &tm[0]);
6276 ok(ret, "got %d\n", ret);
6277 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[0]);
6278 ok(ret, "got %d\n", ret);
6280 lf.lfWeight = FW_BOLD;
6281 hfont = CreateFontIndirectA(&lf);
6282 DeleteObject(SelectObject(hdc, hfont));
6284 /* bold metrics */
6285 ret = GetTextMetricsA(hdc, &tm[1]);
6286 ok(ret, "got %d\n", ret);
6287 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[1]);
6288 ok(ret, "got %d\n", ret);
6290 DeleteObject(SelectObject(hdc, hfont_old));
6291 ReleaseDC(NULL, hdc);
6293 /* compare results (outline) */
6294 ok(tm[0].tmHeight == tm[1].tmHeight, "expected %d, got %d\n", tm[0].tmHeight, tm[1].tmHeight);
6295 ok(tm[0].tmAscent == tm[1].tmAscent, "expected %d, got %d\n", tm[0].tmAscent, tm[1].tmAscent);
6296 ok(tm[0].tmDescent == tm[1].tmDescent, "expected %d, got %d\n", tm[0].tmDescent, tm[1].tmDescent);
6297 ok((tm[0].tmAveCharWidth + 1) == tm[1].tmAveCharWidth,
6298 "expected %d, got %d\n", tm[0].tmAveCharWidth + 1, tm[1].tmAveCharWidth);
6299 ok((tm[0].tmMaxCharWidth + 1) == tm[1].tmMaxCharWidth,
6300 "expected %d, got %d\n", tm[0].tmMaxCharWidth + 1, tm[1].tmMaxCharWidth);
6301 ok(tm[0].tmOverhang == tm[1].tmOverhang, "expected %d, got %d\n", tm[0].tmOverhang, tm[1].tmOverhang);
6302 w[0] = abc[0].abcA + abc[0].abcB + abc[0].abcC;
6303 w[1] = abc[1].abcA + abc[1].abcB + abc[1].abcC;
6304 ok((w[0] + 1) == w[1], "expected %d, got %d\n", w[0] + 1, w[1]);
6308 static void test_bitmap_font_glyph_index(void)
6310 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
6311 const struct {
6312 LPCSTR face;
6313 BYTE charset;
6314 } bitmap_font_list[] = {
6315 { "Courier", ANSI_CHARSET },
6316 { "Small Fonts", ANSI_CHARSET },
6317 { "Fixedsys", DEFAULT_CHARSET },
6318 { "System", DEFAULT_CHARSET }
6320 HDC hdc;
6321 LOGFONTA lf;
6322 HFONT hFont;
6323 CHAR facename[LF_FACESIZE];
6324 BITMAPINFO bmi;
6325 HBITMAP hBmp[2];
6326 void *pixels[2];
6327 int i, j;
6328 DWORD ret;
6329 BITMAP bmp;
6330 TEXTMETRICA tm;
6331 CHARSETINFO ci;
6332 BYTE chr = '\xA9';
6334 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
6335 win_skip("GetGlyphIndices is unavailable\n");
6336 return;
6339 hdc = CreateCompatibleDC(0);
6340 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6342 memset(&bmi, 0, sizeof(bmi));
6343 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
6344 bmi.bmiHeader.biBitCount = 32;
6345 bmi.bmiHeader.biPlanes = 1;
6346 bmi.bmiHeader.biWidth = 128;
6347 bmi.bmiHeader.biHeight = 32;
6348 bmi.bmiHeader.biCompression = BI_RGB;
6350 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
6351 memset(&lf, 0, sizeof(lf));
6352 lf.lfCharSet = bitmap_font_list[i].charset;
6353 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
6354 hFont = CreateFontIndirectA(&lf);
6355 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
6356 hFont = SelectObject(hdc, hFont);
6357 ret = GetTextMetricsA(hdc, &tm);
6358 ok(ret, "GetTextMetric failed\n");
6359 ret = GetTextFaceA(hdc, sizeof(facename), facename);
6360 ok(ret, "GetTextFace failed\n");
6361 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
6362 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
6363 continue;
6365 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
6366 skip("expected %s, got %s\n", lf.lfFaceName, facename);
6367 continue;
6370 for (j = 0; j < 2; j++) {
6371 HBITMAP hBmpPrev;
6372 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
6373 ok(hBmp[j] != NULL, "Can't create DIB\n");
6374 hBmpPrev = SelectObject(hdc, hBmp[j]);
6375 switch (j) {
6376 case 0:
6377 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
6378 break;
6379 case 1:
6381 int len = lstrlenW(text);
6382 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
6383 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
6384 ok(ret, "GetGlyphIndices failed\n");
6385 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
6386 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
6387 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
6388 HeapFree(GetProcessHeap(), 0, indices);
6389 break;
6392 ok(ret, "ExtTextOutW failed\n");
6393 SelectObject(hdc, hBmpPrev);
6396 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
6397 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6398 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6400 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
6401 if (!ret) {
6402 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6403 goto next;
6405 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
6406 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
6407 goto next;
6410 for (j = 0; j < 2; j++) {
6411 HBITMAP hBmpPrev;
6412 WORD code;
6413 hBmpPrev = SelectObject(hdc, hBmp[j]);
6414 switch (j) {
6415 case 0:
6416 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6417 break;
6418 case 1:
6419 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6420 ok(ret, "GetGlyphIndices failed\n");
6421 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6422 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6423 break;
6425 ok(ret, "ExtTextOutA failed\n");
6426 SelectObject(hdc, hBmpPrev);
6429 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6430 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6431 next:
6432 for (j = 0; j < 2; j++)
6433 DeleteObject(hBmp[j]);
6434 hFont = SelectObject(hdc, hFont);
6435 DeleteObject(hFont);
6438 DeleteDC(hdc);
6441 START_TEST(font)
6443 init();
6445 test_stock_fonts();
6446 test_logfont();
6447 test_bitmap_font();
6448 test_outline_font();
6449 test_bitmap_font_metrics();
6450 test_GdiGetCharDimensions();
6451 test_GetCharABCWidths();
6452 test_text_extents();
6453 test_GetGlyphIndices();
6454 test_GetKerningPairs();
6455 test_GetOutlineTextMetrics();
6456 test_SetTextJustification();
6457 test_font_charset();
6458 test_GdiGetCodePage();
6459 test_GetFontUnicodeRanges();
6460 test_nonexistent_font();
6461 test_orientation();
6462 test_height_selection();
6463 test_AddFontMemResource();
6464 test_EnumFonts();
6465 test_EnumFonts_subst();
6467 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6468 * I'd like to avoid them in this test.
6470 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6471 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6472 if (is_truetype_font_installed("Arial Black") &&
6473 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6475 test_EnumFontFamilies("", ANSI_CHARSET);
6476 test_EnumFontFamilies("", SYMBOL_CHARSET);
6477 test_EnumFontFamilies("", DEFAULT_CHARSET);
6479 else
6480 skip("Arial Black or Symbol/Wingdings is not installed\n");
6481 test_EnumFontFamiliesEx_default_charset();
6482 test_GetTextMetrics();
6483 test_RealizationInfo();
6484 test_GetTextFace();
6485 test_GetGlyphOutline();
6486 test_GetTextMetrics2("Tahoma", -11);
6487 test_GetTextMetrics2("Tahoma", -55);
6488 test_GetTextMetrics2("Tahoma", -110);
6489 test_GetTextMetrics2("Arial", -11);
6490 test_GetTextMetrics2("Arial", -55);
6491 test_GetTextMetrics2("Arial", -110);
6492 test_CreateFontIndirect();
6493 test_CreateFontIndirectEx();
6494 test_oemcharset();
6495 test_fullname();
6496 test_fullname2();
6497 test_east_asian_font_selection();
6498 test_max_height();
6499 test_vertical_order();
6500 test_GetCharWidth32();
6501 test_fake_bold_font();
6502 test_bitmap_font_glyph_index();
6504 /* These tests should be last test until RemoveFontResource
6505 * is properly implemented.
6507 test_vertical_font();
6508 test_CreateScalableFontResource();