TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / gdi32 / tests / font.c
blob53945da1bbd3e2846cdf0dece08cbdc94aef112e
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 WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
757 static const struct font_data
759 const char face_name[LF_FACESIZE];
760 int weight, height, ascent, descent, int_leading, ext_leading;
761 int ave_char_width, max_char_width, dpi;
762 BYTE first_char, last_char, def_char, break_char;
763 DWORD ansi_bitfield;
764 const WORD *skip_lang_id;
765 int scaled_height;
766 } fd[] =
768 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
769 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
770 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
771 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
772 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
773 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
775 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 16 },
777 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
779 { "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 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
781 { "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 },
782 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
783 { "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 },
784 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
785 { "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 },
786 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
787 { "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 },
788 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
790 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
791 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
792 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
793 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
794 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
795 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
796 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
797 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
798 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
799 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
800 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
801 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
802 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
803 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
804 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
805 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
807 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
808 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
809 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
810 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
811 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
812 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
813 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
814 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
815 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
816 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
817 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
818 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
820 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
822 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
823 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
824 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
825 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
826 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
827 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
828 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
829 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
830 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
831 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
833 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
834 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
835 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
836 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
838 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
839 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
840 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
841 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
842 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
843 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
844 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
845 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
846 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
847 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
848 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
850 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
851 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
852 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
854 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
855 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
856 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
858 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
859 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
860 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
862 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
863 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
865 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
866 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
867 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
868 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
869 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
870 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
871 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
872 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
873 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
874 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
875 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
876 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
877 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
878 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
879 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
880 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
881 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
882 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
883 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
884 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
885 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
887 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
888 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
889 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
890 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
891 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
892 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
893 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
894 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
895 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
896 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
897 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
898 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
900 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
901 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
902 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
904 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
906 /* FIXME: add "Terminal" */
908 static const int font_log_pixels[] = { 96, 120 };
909 HDC hdc;
910 LOGFONTA lf;
911 HFONT hfont, old_hfont;
912 TEXTMETRICA tm;
913 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
914 char face_name[LF_FACESIZE];
915 CHARSETINFO csi;
917 trace("system language id %04x\n", system_lang_id);
919 expected_cs = GetACP();
920 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
922 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
923 return;
925 expected_cs = csi.ciCharset;
926 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
928 hdc = CreateCompatibleDC(0);
929 assert(hdc);
931 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
932 GetDeviceCaps(hdc, LOGPIXELSY));
934 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
935 diff = 32768;
936 font_res = 0;
937 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
939 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
940 if (new_diff < diff)
942 diff = new_diff;
943 font_res = font_log_pixels[i];
946 trace("best font resolution is %d\n", font_res);
948 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
950 int bit, height;
952 memset(&lf, 0, sizeof(lf));
954 height = fd[i].height & ~FH_SCALE;
955 lf.lfHeight = height;
956 strcpy(lf.lfFaceName, fd[i].face_name);
958 for(bit = 0; bit < 32; bit++)
960 GLYPHMETRICS gm;
961 DWORD fs[2];
962 BOOL bRet;
964 fs[0] = 1L << bit;
965 fs[1] = 0;
966 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
967 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
969 lf.lfCharSet = csi.ciCharset;
970 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
971 if (fd[i].height & FH_SCALE)
972 ok(ret, "scaled font height %d should not be enumerated\n", height);
973 else
975 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
977 if (ret) /* FIXME: Remove once Wine is fixed */
978 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
979 else
980 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
983 if (ret && !(fd[i].height & FH_SCALE))
984 continue;
986 hfont = create_font(lf.lfFaceName, &lf);
987 old_hfont = SelectObject(hdc, hfont);
989 SetLastError(0xdeadbeef);
990 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
991 ok(ret, "GetTextFace error %u\n", GetLastError());
993 if (strcmp(face_name, fd[i].face_name) != 0)
995 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
996 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
997 SelectObject(hdc, old_hfont);
998 DeleteObject(hfont);
999 continue;
1002 memset(&gm, 0, sizeof(gm));
1003 SetLastError(0xdeadbeef);
1004 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1005 todo_wine {
1006 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1007 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1010 bRet = GetTextMetricsA(hdc, &tm);
1011 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1013 SetLastError(0xdeadbeef);
1014 ret = GetTextCharset(hdc);
1015 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1016 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1017 else
1018 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1020 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1021 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1023 if(fd[i].dpi == tm.tmDigitizedAspectX)
1025 int skipme = 0;
1026 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1027 if (fd[i].skip_lang_id)
1029 int si = 0;
1030 skipme = 0;
1031 while(!skipme && fd[i].skip_lang_id[si])
1032 if (fd[i].skip_lang_id[si++] == system_lang_id)
1033 skipme = 1;
1035 if (!skipme)
1037 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1038 if (fd[i].height & FH_SCALE)
1039 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);
1040 else
1041 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);
1042 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1043 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1044 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);
1045 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);
1046 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);
1047 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1048 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1049 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1050 make default char test fail */
1051 if (tm.tmCharSet == lf.lfCharSet)
1052 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1053 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1054 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);
1056 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1057 that make the max width bigger */
1058 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1059 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);
1061 else
1062 skip("Skipping font metrics test for system langid 0x%x\n",
1063 system_lang_id);
1065 SelectObject(hdc, old_hfont);
1066 DeleteObject(hfont);
1070 DeleteDC(hdc);
1073 static void test_GdiGetCharDimensions(void)
1075 HDC hdc;
1076 TEXTMETRICW tm;
1077 LONG ret;
1078 SIZE size;
1079 LONG avgwidth, height;
1080 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1082 if (!pGdiGetCharDimensions)
1084 win_skip("GdiGetCharDimensions not available on this platform\n");
1085 return;
1088 hdc = CreateCompatibleDC(NULL);
1090 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1091 avgwidth = ((size.cx / 26) + 1) / 2;
1093 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1094 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1095 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1097 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1098 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1100 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1101 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1103 height = 0;
1104 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1105 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1106 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1108 DeleteDC(hdc);
1111 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1112 const TEXTMETRICA *lpntme,
1113 DWORD FontType, LPARAM lParam)
1115 if (FontType & TRUETYPE_FONTTYPE)
1117 HFONT hfont;
1119 hfont = CreateFontIndirectA(lpelfe);
1120 if (hfont)
1122 *(HFONT *)lParam = hfont;
1123 return 0;
1127 return 1;
1130 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1132 ABC abc[1];
1133 ABCFLOAT abcf[1];
1134 BOOL ret = FALSE;
1136 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1137 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1138 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1139 if (todo) todo_wine ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1140 else ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1141 if (todo) todo_wine ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1142 else ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1144 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1145 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1146 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1147 if (todo) todo_wine ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1148 else ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1149 if (todo) todo_wine ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1150 else ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's should be unchanged\n", description);
1152 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1153 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1154 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1155 if (todo) todo_wine ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1156 else ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's should be unchanged\n", description);
1157 if (todo) todo_wine ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1158 else ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1161 static void test_GetCharABCWidths(void)
1163 static const WCHAR str[] = {'i',0};
1164 BOOL ret;
1165 HDC hdc;
1166 LOGFONTA lf;
1167 HFONT hfont;
1168 ABC abc[1];
1169 ABC abcw[1];
1170 ABCFLOAT abcf[1];
1171 WORD glyphs[1];
1172 DWORD nb;
1173 HWND hwnd;
1174 static const struct
1176 UINT first;
1177 UINT last;
1178 } range[] =
1180 {0xff, 0xff},
1181 {0x100, 0x100},
1182 {0xff, 0x100},
1183 {0x1ff, 0xff00},
1184 {0xffff, 0xffff},
1185 {0x10000, 0x10000},
1186 {0xffff, 0x10000},
1187 {0xffffff, 0xffffff},
1188 {0x1000000, 0x1000000},
1189 {0xffffff, 0x1000000},
1190 {0xffffffff, 0xffffffff},
1191 {0x00, 0xff}
1193 static const struct
1195 UINT cs;
1196 UINT a;
1197 UINT w;
1198 BOOL r[sizeof range / sizeof range[0]];
1199 } c[] =
1201 {ANSI_CHARSET, 0x30, 0x30,
1202 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1203 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1204 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1205 {HANGEUL_CHARSET, 0x8141, 0xac02,
1206 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1207 {GB2312_CHARSET, 0x8141, 0x4e04,
1208 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1209 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1210 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1212 UINT i;
1214 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1216 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1217 return;
1220 memset(&lf, 0, sizeof(lf));
1221 strcpy(lf.lfFaceName, "System");
1222 lf.lfHeight = 20;
1224 hfont = CreateFontIndirectA(&lf);
1225 hdc = GetDC(0);
1226 hfont = SelectObject(hdc, hfont);
1228 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1229 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1231 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1232 ok(!ret, "GetCharABCWidthsI should have failed\n");
1234 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1235 ok(!ret, "GetCharABCWidthsI should have failed\n");
1237 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1238 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1240 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1241 ok(!ret, "GetCharABCWidthsW should have failed\n");
1243 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1244 ok(!ret, "GetCharABCWidthsW should have failed\n");
1246 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1247 ok(!ret, "GetCharABCWidthsW should have failed\n");
1249 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1250 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1252 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1253 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1255 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1256 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1258 hfont = SelectObject(hdc, hfont);
1259 DeleteObject(hfont);
1261 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1263 ABC a[2], w[2];
1264 ABC full[256];
1265 UINT code = 0x41, j;
1267 lf.lfFaceName[0] = '\0';
1268 lf.lfCharSet = c[i].cs;
1269 lf.lfPitchAndFamily = 0;
1270 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1272 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1273 continue;
1276 memset(a, 0, sizeof a);
1277 memset(w, 0, sizeof w);
1278 hfont = SelectObject(hdc, hfont);
1279 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1280 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1281 memcmp(a, w, sizeof a) == 0,
1282 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1284 memset(a, 0xbb, sizeof a);
1285 ret = pGetCharABCWidthsA(hdc, code, code, a);
1286 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1287 memset(full, 0xcc, sizeof full);
1288 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1289 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1290 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1291 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1293 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1295 memset(full, 0xdd, sizeof full);
1296 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1297 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1298 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1299 if (ret)
1301 UINT last = range[j].last - range[j].first;
1302 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1303 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1304 "GetCharABCWidthsA %x should match. codepage = %u\n",
1305 range[j].last, c[i].cs);
1309 hfont = SelectObject(hdc, hfont);
1310 DeleteObject(hfont);
1313 memset(&lf, 0, sizeof(lf));
1314 strcpy(lf.lfFaceName, "Tahoma");
1315 lf.lfHeight = 200;
1316 hfont = CreateFontIndirectA(&lf);
1318 /* test empty glyph's metrics */
1319 hfont = SelectObject(hdc, hfont);
1320 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1321 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1322 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1323 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1324 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1325 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1327 /* 1) prepare unrotated font metrics */
1328 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1329 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1330 DeleteObject(SelectObject(hdc, hfont));
1332 /* 2) get rotated font metrics */
1333 lf.lfEscapement = lf.lfOrientation = 900;
1334 hfont = CreateFontIndirectA(&lf);
1335 hfont = SelectObject(hdc, hfont);
1336 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1337 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1339 /* 3) compare ABC results */
1340 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1341 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1342 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1343 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1344 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1345 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1347 DeleteObject(SelectObject(hdc, hfont));
1348 ReleaseDC(NULL, hdc);
1350 trace("ABC sign test for a variety of transforms:\n");
1351 memset(&lf, 0, sizeof(lf));
1352 strcpy(lf.lfFaceName, "Tahoma");
1353 lf.lfHeight = 20;
1354 hfont = CreateFontIndirectA(&lf);
1355 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1356 0, 0, 0, NULL);
1357 hdc = GetDC(hwnd);
1358 SetMapMode(hdc, MM_ANISOTROPIC);
1359 SelectObject(hdc, hfont);
1361 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1362 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1364 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1365 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1366 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1367 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1368 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1369 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1371 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1372 SetWindowExtEx(hdc, -1, -1, NULL);
1373 SetGraphicsMode(hdc, GM_COMPATIBLE);
1374 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1375 SetGraphicsMode(hdc, GM_ADVANCED);
1376 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1377 SetWindowExtEx(hdc, 1, 1, NULL);
1378 SetGraphicsMode(hdc, GM_COMPATIBLE);
1379 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1380 SetGraphicsMode(hdc, GM_ADVANCED);
1381 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1383 ReleaseDC(hwnd, hdc);
1384 DestroyWindow(hwnd);
1386 trace("RTL layout\n");
1387 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1388 0, 0, 0, NULL);
1389 hdc = GetDC(hwnd);
1390 SetMapMode(hdc, MM_ANISOTROPIC);
1391 SelectObject(hdc, hfont);
1393 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1394 SetWindowExtEx(hdc, -1, -1, NULL);
1395 SetGraphicsMode(hdc, GM_COMPATIBLE);
1396 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1397 SetGraphicsMode(hdc, GM_ADVANCED);
1398 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1399 SetWindowExtEx(hdc, 1, 1, NULL);
1400 SetGraphicsMode(hdc, GM_COMPATIBLE);
1401 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1402 SetGraphicsMode(hdc, GM_ADVANCED);
1403 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1405 ReleaseDC(hwnd, hdc);
1406 DestroyWindow(hwnd);
1407 DeleteObject(hfont);
1410 static void test_text_extents(void)
1412 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1413 static const WCHAR emptyW[] = {0};
1414 LPINT extents;
1415 INT i, len, fit1, fit2, extents2[3];
1416 LOGFONTA lf;
1417 TEXTMETRICA tm;
1418 HDC hdc;
1419 HFONT hfont;
1420 SIZE sz;
1421 SIZE sz1, sz2;
1422 BOOL ret;
1424 memset(&lf, 0, sizeof(lf));
1425 strcpy(lf.lfFaceName, "Arial");
1426 lf.lfHeight = 20;
1428 hfont = CreateFontIndirectA(&lf);
1429 hdc = GetDC(0);
1430 hfont = SelectObject(hdc, hfont);
1431 GetTextMetricsA(hdc, &tm);
1432 ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1433 ok(ret, "got %d\n", ret);
1434 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1436 memset(&sz, 0xcc, sizeof(sz));
1437 ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1438 ok(ret, "got %d\n", ret);
1439 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1441 memset(&sz, 0xcc, sizeof(sz));
1442 ret = GetTextExtentPointA(hdc, "", 0, &sz);
1443 ok(ret, "got %d\n", ret);
1444 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1446 SetLastError(0xdeadbeef);
1447 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1448 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1450 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1451 hfont = SelectObject(hdc, hfont);
1452 DeleteObject(hfont);
1453 ReleaseDC(0, hdc);
1454 return;
1457 memset(&sz, 0xcc, sizeof(sz));
1458 ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1459 ok(ret, "got %d\n", ret);
1460 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1462 memset(&sz, 0xcc, sizeof(sz));
1463 ret = GetTextExtentPointW(hdc, emptyW, 0, &sz);
1464 ok(ret, "got %d\n", ret);
1465 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1467 len = lstrlenW(wt);
1468 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1469 extents[0] = 1; /* So that the increasing sequence test will fail
1470 if the extents array is untouched. */
1471 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1472 GetTextExtentPointW(hdc, wt, len, &sz2);
1473 ok(sz1.cy == sz2.cy,
1474 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1475 /* Because of the '\n' in the string GetTextExtentExPoint and
1476 GetTextExtentPoint return different widths under Win2k, but
1477 under WinXP they return the same width. So we don't test that
1478 here. */
1480 for (i = 1; i < len; ++i)
1481 ok(extents[i-1] <= extents[i],
1482 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1484 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1485 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1486 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1487 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1488 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1489 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1490 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1491 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1492 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1493 ok(extents[0] == extents[2] && extents[1] == extents[3],
1494 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1495 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1496 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1497 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1499 /* extents functions fail with -ve counts (the interesting case being -1) */
1500 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1501 ok(ret == FALSE, "got %d\n", ret);
1502 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1503 ok(ret == FALSE, "got %d\n", ret);
1504 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1505 ok(ret == FALSE, "got %d\n", ret);
1507 /* max_extent = 0 succeeds and returns zero */
1508 fit1 = fit2 = -215;
1509 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1510 ok(ret == TRUE ||
1511 broken(ret == FALSE), /* NT4, 2k */
1512 "got %d\n", ret);
1513 ok(fit1 == 0 ||
1514 broken(fit1 == -215), /* NT4, 2k */
1515 "fit = %d\n", fit1);
1516 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1517 ok(ret == TRUE, "got %d\n", ret);
1518 ok(fit2 == 0, "fit = %d\n", fit2);
1520 /* max_extent = -1 is interpreted as a very large width that will
1521 * definitely fit our three characters */
1522 fit1 = fit2 = -215;
1523 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1524 ok(ret == TRUE, "got %d\n", ret);
1525 ok(fit1 == 3, "fit = %d\n", fit1);
1526 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1527 ok(ret == TRUE, "got %d\n", ret);
1528 ok(fit2 == 3, "fit = %d\n", fit2);
1530 /* max_extent = -2 is interpreted similarly, but the Ansi version
1531 * rejects it while the Unicode one accepts it */
1532 fit1 = fit2 = -215;
1533 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1534 ok(ret == FALSE, "got %d\n", ret);
1535 ok(fit1 == -215, "fit = %d\n", fit1);
1536 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1537 ok(ret == TRUE, "got %d\n", ret);
1538 ok(fit2 == 3, "fit = %d\n", fit2);
1540 hfont = SelectObject(hdc, hfont);
1541 DeleteObject(hfont);
1543 /* non-MM_TEXT mapping mode */
1544 lf.lfHeight = 2000;
1545 hfont = CreateFontIndirectA(&lf);
1546 hfont = SelectObject(hdc, hfont);
1548 SetMapMode( hdc, MM_HIMETRIC );
1549 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1550 ok(ret, "got %d\n", ret);
1551 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1553 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1554 ok(ret, "got %d\n", ret);
1555 ok(fit1 == 2, "got %d\n", fit1);
1556 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1557 for(i = 0; i < 2; i++)
1558 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1560 hfont = SelectObject(hdc, hfont);
1561 DeleteObject(hfont);
1562 HeapFree(GetProcessHeap(), 0, extents);
1563 ReleaseDC(NULL, hdc);
1566 static void test_GetGlyphIndices(void)
1568 HDC hdc;
1569 HFONT hfont;
1570 DWORD charcount;
1571 LOGFONTA lf;
1572 DWORD flags = 0;
1573 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1574 WORD glyphs[(sizeof(testtext)/2)-1];
1575 TEXTMETRICA textm;
1576 HFONT hOldFont;
1578 if (!pGetGlyphIndicesW) {
1579 win_skip("GetGlyphIndicesW not available on platform\n");
1580 return;
1583 hdc = GetDC(0);
1585 memset(&lf, 0, sizeof(lf));
1586 strcpy(lf.lfFaceName, "System");
1587 lf.lfHeight = 16;
1588 lf.lfCharSet = ANSI_CHARSET;
1590 hfont = CreateFontIndirectA(&lf);
1591 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1592 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1593 if (textm.tmCharSet == ANSI_CHARSET)
1595 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1596 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1597 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1598 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1599 flags = 0;
1600 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1601 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1602 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1603 textm.tmDefaultChar, glyphs[4]);
1605 else
1606 /* FIXME: Write tests for non-ANSI charsets. */
1607 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1609 if(!is_font_installed("Tahoma"))
1611 skip("Tahoma is not installed so skipping this test\n");
1612 return;
1614 memset(&lf, 0, sizeof(lf));
1615 strcpy(lf.lfFaceName, "Tahoma");
1616 lf.lfHeight = 20;
1618 hfont = CreateFontIndirectA(&lf);
1619 hOldFont = SelectObject(hdc, hfont);
1620 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1621 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1622 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1623 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1624 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1625 flags = 0;
1626 testtext[0] = textm.tmDefaultChar;
1627 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1628 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1629 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1630 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1631 DeleteObject(SelectObject(hdc, hOldFont));
1634 static void test_GetKerningPairs(void)
1636 static const struct kerning_data
1638 const char face_name[LF_FACESIZE];
1639 LONG height;
1640 /* some interesting fields from OUTLINETEXTMETRIC */
1641 LONG tmHeight, tmAscent, tmDescent;
1642 UINT otmEMSquare;
1643 INT otmAscent;
1644 INT otmDescent;
1645 UINT otmLineGap;
1646 UINT otmsCapEmHeight;
1647 UINT otmsXHeight;
1648 INT otmMacAscent;
1649 INT otmMacDescent;
1650 UINT otmMacLineGap;
1651 UINT otmusMinimumPPEM;
1652 /* small subset of kerning pairs to test */
1653 DWORD total_kern_pairs;
1654 const KERNINGPAIR kern_pair[26];
1655 } kd[] =
1657 {"Arial", 12, 12, 9, 3,
1658 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1661 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1662 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1663 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1664 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1665 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1666 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1667 {933,970,+1},{933,972,-1}
1670 {"Arial", -34, 39, 32, 7,
1671 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1674 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1675 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1676 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1677 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1678 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1679 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1680 {933,970,+2},{933,972,-3}
1683 { "Arial", 120, 120, 97, 23,
1684 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1687 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1688 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1689 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1690 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1691 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1692 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1693 {933,970,+6},{933,972,-10}
1696 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1697 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1698 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1701 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1702 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1703 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1704 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1705 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1706 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1707 {933,970,+54},{933,972,-83}
1710 #endif
1712 LOGFONTA lf;
1713 HFONT hfont, hfont_old;
1714 KERNINGPAIR *kern_pair;
1715 HDC hdc;
1716 DWORD total_kern_pairs, ret, i, n, matches;
1718 hdc = GetDC(0);
1720 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1721 * which may render this test unusable, so we're trying to avoid that.
1723 SetLastError(0xdeadbeef);
1724 GetKerningPairsW(hdc, 0, NULL);
1725 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1727 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1728 ReleaseDC(0, hdc);
1729 return;
1732 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1734 OUTLINETEXTMETRICW otm;
1735 UINT uiRet;
1737 if (!is_font_installed(kd[i].face_name))
1739 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1740 continue;
1743 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1745 memset(&lf, 0, sizeof(lf));
1746 strcpy(lf.lfFaceName, kd[i].face_name);
1747 lf.lfHeight = kd[i].height;
1748 hfont = CreateFontIndirectA(&lf);
1749 assert(hfont != 0);
1751 hfont_old = SelectObject(hdc, hfont);
1753 SetLastError(0xdeadbeef);
1754 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1755 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1756 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1758 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1759 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1760 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1761 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1762 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1763 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1765 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1766 kd[i].otmEMSquare, otm.otmEMSquare);
1767 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1768 kd[i].otmAscent, otm.otmAscent);
1769 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1770 kd[i].otmDescent, otm.otmDescent);
1771 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1772 kd[i].otmLineGap, otm.otmLineGap);
1773 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1774 kd[i].otmMacDescent, otm.otmMacDescent);
1775 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1776 kd[i].otmMacAscent, otm.otmMacAscent);
1777 todo_wine {
1778 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1779 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1780 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1781 kd[i].otmsXHeight, otm.otmsXHeight);
1782 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1783 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1784 kd[i].otmMacLineGap, otm.otmMacLineGap);
1785 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1786 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1789 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1790 trace("total_kern_pairs %u\n", total_kern_pairs);
1791 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1793 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1794 * passes on XP.
1796 SetLastError(0xdeadbeef);
1797 ret = GetKerningPairsW(hdc, 0, kern_pair);
1798 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1799 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1800 ok(ret == 0, "got %u, expected 0\n", ret);
1802 ret = GetKerningPairsW(hdc, 100, NULL);
1803 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1805 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1806 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1808 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1809 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1811 matches = 0;
1813 for (n = 0; n < ret; n++)
1815 DWORD j;
1816 /* Disabled to limit console spam */
1817 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1818 trace("{'%c','%c',%d},\n",
1819 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1820 for (j = 0; j < kd[i].total_kern_pairs; j++)
1822 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1823 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1825 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1826 "pair %d:%d got %d, expected %d\n",
1827 kern_pair[n].wFirst, kern_pair[n].wSecond,
1828 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1829 matches++;
1834 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1835 matches, kd[i].total_kern_pairs);
1837 HeapFree(GetProcessHeap(), 0, kern_pair);
1839 SelectObject(hdc, hfont_old);
1840 DeleteObject(hfont);
1843 ReleaseDC(0, hdc);
1846 struct font_data
1848 const char face_name[LF_FACESIZE];
1849 int requested_height;
1850 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1851 BOOL exact;
1854 static void test_height( HDC hdc, const struct font_data *fd )
1856 LOGFONTA lf;
1857 HFONT hfont, old_hfont;
1858 TEXTMETRICA tm;
1859 INT ret, i;
1861 for (i = 0; fd[i].face_name[0]; i++)
1863 if (!is_truetype_font_installed(fd[i].face_name))
1865 skip("%s is not installed\n", fd[i].face_name);
1866 continue;
1869 memset(&lf, 0, sizeof(lf));
1870 lf.lfHeight = fd[i].requested_height;
1871 lf.lfWeight = fd[i].weight;
1872 strcpy(lf.lfFaceName, fd[i].face_name);
1874 hfont = CreateFontIndirectA(&lf);
1875 assert(hfont);
1877 old_hfont = SelectObject(hdc, hfont);
1878 ret = GetTextMetricsA(hdc, &tm);
1879 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1880 if(fd[i].dpi == tm.tmDigitizedAspectX)
1882 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);
1883 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);
1884 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);
1885 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);
1886 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);
1887 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);
1890 SelectObject(hdc, old_hfont);
1891 /* force GDI to use new font, otherwise Windows leaks the font reference */
1892 GetTextMetricsA(hdc, &tm);
1893 DeleteObject(hfont);
1897 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1899 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1900 DWORD *table = (DWORD *)ttf + 3;
1902 for (i = 0; i < num_tables; i++)
1904 if (table[0] == tag)
1905 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1906 table += 4;
1908 return NULL;
1911 static void test_height_selection_vdmx( HDC hdc )
1913 static const struct font_data charset_0[] = /* doesn't use VDMX */
1915 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1916 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1917 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1918 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1919 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1920 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1921 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1922 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1923 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1924 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1925 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1926 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1927 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1928 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1929 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1930 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1931 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1932 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1933 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1934 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1935 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1936 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1937 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1938 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1939 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1940 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1941 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1942 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1943 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1944 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1945 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1946 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1947 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1948 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1949 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1950 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1951 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1952 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1953 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1954 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1955 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1956 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1957 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1958 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1959 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1960 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1961 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1962 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1963 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1964 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1965 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1966 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1967 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1970 static const struct font_data charset_1[] = /* Uses VDMX */
1972 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1973 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1974 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1975 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1976 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1977 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1978 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1979 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1980 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1981 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1982 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1983 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
1984 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
1985 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1986 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
1987 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
1988 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
1989 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
1990 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
1991 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1992 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1993 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
1994 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
1995 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
1996 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
1997 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
1998 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1999 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2000 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2001 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2002 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2003 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2004 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2005 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2006 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2007 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2008 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2009 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2010 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2011 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2012 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2013 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2014 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2015 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2016 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2017 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2018 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2019 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2020 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2021 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2022 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2023 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2024 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2027 static const struct vdmx_data
2029 WORD version;
2030 BYTE bCharSet;
2031 const struct font_data *fd;
2032 } data[] =
2034 { 0, 0, charset_0 },
2035 { 0, 1, charset_1 },
2036 { 1, 0, charset_0 },
2037 { 1, 1, charset_1 }
2039 int i;
2040 DWORD size, num;
2041 WORD *vdmx_header;
2042 BYTE *ratio_rec;
2043 char ttf_name[MAX_PATH];
2044 void *res, *copy;
2045 BOOL ret;
2047 if (!pAddFontResourceExA)
2049 win_skip("AddFontResourceExA unavailable\n");
2050 return;
2053 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2055 res = get_res_data( "wine_vdmx.ttf", &size );
2057 copy = HeapAlloc( GetProcessHeap(), 0, size );
2058 memcpy( copy, res, size );
2059 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2060 vdmx_header[0] = GET_BE_WORD( data[i].version );
2061 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2062 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2063 ratio_rec = (BYTE *)&vdmx_header[3];
2064 ratio_rec[0] = data[i].bCharSet;
2066 write_tmp_file( copy, &size, ttf_name );
2067 HeapFree( GetProcessHeap(), 0, copy );
2069 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2070 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2071 if (!num) win_skip("Unable to add ttf font resource\n");
2072 else
2074 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2075 test_height( hdc, data[i].fd );
2076 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2078 ret = DeleteFileA( ttf_name );
2079 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2080 "DeleteFile error %d\n", GetLastError());
2084 static void test_height_selection(void)
2086 static const struct font_data tahoma[] =
2088 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2089 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2090 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2091 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2092 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2093 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2094 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2095 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2096 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2097 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2098 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2100 HDC hdc = CreateCompatibleDC(0);
2101 assert(hdc);
2103 test_height( hdc, tahoma );
2104 test_height_selection_vdmx( hdc );
2106 DeleteDC(hdc);
2109 static void test_GetOutlineTextMetrics(void)
2111 OUTLINETEXTMETRICA *otm;
2112 LOGFONTA lf;
2113 HFONT hfont, hfont_old;
2114 HDC hdc;
2115 DWORD ret, otm_size;
2116 LPSTR unset_ptr;
2118 if (!is_font_installed("Arial"))
2120 skip("Arial is not installed\n");
2121 return;
2124 hdc = GetDC(0);
2126 memset(&lf, 0, sizeof(lf));
2127 strcpy(lf.lfFaceName, "Arial");
2128 lf.lfHeight = -13;
2129 lf.lfWeight = FW_NORMAL;
2130 lf.lfPitchAndFamily = DEFAULT_PITCH;
2131 lf.lfQuality = PROOF_QUALITY;
2132 hfont = CreateFontIndirectA(&lf);
2133 assert(hfont != 0);
2135 hfont_old = SelectObject(hdc, hfont);
2136 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2137 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2139 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2141 memset(otm, 0xAA, otm_size);
2142 SetLastError(0xdeadbeef);
2143 otm->otmSize = sizeof(*otm); /* 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);
2153 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2156 memset(otm, 0xAA, otm_size);
2157 SetLastError(0xdeadbeef);
2158 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2159 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2160 ok(ret == 1 /* Win9x */ ||
2161 ret == otm->otmSize /* XP*/,
2162 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2163 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2165 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2166 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2167 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2168 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2171 /* ask about truncated data */
2172 memset(otm, 0xAA, otm_size);
2173 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2174 SetLastError(0xdeadbeef);
2175 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2176 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2177 ok(ret == 1 /* Win9x */ ||
2178 ret == otm->otmSize /* XP*/,
2179 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2180 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2182 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2183 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2184 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2186 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2188 /* check handling of NULL pointer */
2189 SetLastError(0xdeadbeef);
2190 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2191 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2193 HeapFree(GetProcessHeap(), 0, otm);
2195 SelectObject(hdc, hfont_old);
2196 DeleteObject(hfont);
2198 ReleaseDC(0, hdc);
2201 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2203 INT y,
2204 breakCount,
2205 areaWidth = clientArea->right - clientArea->left,
2206 nErrors = 0, e;
2207 const char *pFirstChar, *pLastChar;
2208 SIZE size;
2209 TEXTMETRICA tm;
2210 struct err
2212 const char *start;
2213 int len;
2214 int GetTextExtentExPointWWidth;
2215 } error[20];
2217 GetTextMetricsA(hdc, &tm);
2218 y = clientArea->top;
2219 do {
2220 breakCount = 0;
2221 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2222 pFirstChar = str;
2224 do {
2225 pLastChar = str;
2227 /* if not at the end of the string, ... */
2228 if (*str == '\0') break;
2229 /* ... add the next word to the current extent */
2230 while (*str != '\0' && *str++ != tm.tmBreakChar);
2231 breakCount++;
2232 SetTextJustification(hdc, 0, 0);
2233 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2234 } while ((int) size.cx < areaWidth);
2236 /* ignore trailing break chars */
2237 breakCount--;
2238 while (*(pLastChar - 1) == tm.tmBreakChar)
2240 pLastChar--;
2241 breakCount--;
2244 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2246 SetTextJustification(hdc, 0, 0);
2247 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2249 /* do not justify the last extent */
2250 if (*str != '\0' && breakCount > 0)
2252 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2253 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2254 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2256 error[nErrors].start = pFirstChar;
2257 error[nErrors].len = pLastChar - pFirstChar;
2258 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2259 nErrors++;
2263 y += size.cy;
2264 str = pLastChar;
2265 } while (*str && y < clientArea->bottom);
2267 for (e = 0; e < nErrors; e++)
2269 /* The width returned by GetTextExtentPoint32() is exactly the same
2270 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2271 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2272 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2273 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2277 static void test_SetTextJustification(void)
2279 HDC hdc;
2280 RECT clientArea;
2281 LOGFONTA lf;
2282 HFONT hfont;
2283 HWND hwnd;
2284 SIZE size, expect;
2285 int i;
2286 WORD indices[2];
2287 static const char testText[] =
2288 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2289 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2290 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2291 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2292 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2293 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2294 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2296 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2297 GetClientRect( hwnd, &clientArea );
2298 hdc = GetDC( hwnd );
2300 if (!is_font_installed("Times New Roman"))
2302 skip("Times New Roman is not installed\n");
2303 return;
2306 memset(&lf, 0, sizeof lf);
2307 lf.lfCharSet = ANSI_CHARSET;
2308 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2309 lf.lfWeight = FW_DONTCARE;
2310 lf.lfHeight = 20;
2311 lf.lfQuality = DEFAULT_QUALITY;
2312 lstrcpyA(lf.lfFaceName, "Times New Roman");
2313 hfont = create_font("Times New Roman", &lf);
2314 SelectObject(hdc, hfont);
2316 testJustification(hdc, testText, &clientArea);
2318 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2319 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2321 SetTextJustification(hdc, 0, 0);
2322 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2323 GetTextExtentPoint32A(hdc, " ", 3, &size);
2324 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2325 SetTextJustification(hdc, 4, 1);
2326 GetTextExtentPoint32A(hdc, " ", 1, &size);
2327 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2328 SetTextJustification(hdc, 9, 2);
2329 GetTextExtentPoint32A(hdc, " ", 2, &size);
2330 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2331 SetTextJustification(hdc, 7, 3);
2332 GetTextExtentPoint32A(hdc, " ", 3, &size);
2333 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2334 SetTextJustification(hdc, 7, 3);
2335 SetTextCharacterExtra(hdc, 2 );
2336 GetTextExtentPoint32A(hdc, " ", 3, &size);
2337 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2338 SetTextJustification(hdc, 0, 0);
2339 SetTextCharacterExtra(hdc, 0);
2340 size.cx = size.cy = 1234;
2341 GetTextExtentPoint32A(hdc, " ", 0, &size);
2342 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2343 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2344 SetTextJustification(hdc, 5, 1);
2345 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2346 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2347 SetTextJustification(hdc, 0, 0);
2349 SetMapMode( hdc, MM_ANISOTROPIC );
2350 SetWindowExtEx( hdc, 2, 2, NULL );
2351 GetClientRect( hwnd, &clientArea );
2352 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2353 testJustification(hdc, testText, &clientArea);
2355 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2356 for (i = 0; i < 10; i++)
2358 SetTextCharacterExtra(hdc, i);
2359 GetTextExtentPoint32A(hdc, "A", 1, &size);
2360 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2362 SetTextCharacterExtra(hdc, 0);
2363 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2364 for (i = 0; i < 10; i++)
2366 SetTextCharacterExtra(hdc, i);
2367 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2368 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2370 SetTextCharacterExtra(hdc, 0);
2372 SetViewportExtEx( hdc, 3, 3, NULL );
2373 GetClientRect( hwnd, &clientArea );
2374 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2375 testJustification(hdc, testText, &clientArea);
2377 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2378 for (i = 0; i < 10; i++)
2380 SetTextCharacterExtra(hdc, i);
2381 GetTextExtentPoint32A(hdc, "A", 1, &size);
2382 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2385 done:
2386 DeleteObject(hfont);
2387 ReleaseDC(hwnd, hdc);
2388 DestroyWindow(hwnd);
2391 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2393 HDC hdc;
2394 LOGFONTA lf;
2395 HFONT hfont, hfont_old;
2396 CHARSETINFO csi;
2397 FONTSIGNATURE fs;
2398 INT cs;
2399 DWORD i, ret;
2400 char name[64];
2402 assert(count <= 128);
2404 memset(&lf, 0, sizeof(lf));
2406 lf.lfCharSet = charset;
2407 lf.lfHeight = 10;
2408 lstrcpyA(lf.lfFaceName, "Arial");
2409 SetLastError(0xdeadbeef);
2410 hfont = CreateFontIndirectA(&lf);
2411 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2413 hdc = GetDC(0);
2414 hfont_old = SelectObject(hdc, hfont);
2416 cs = GetTextCharsetInfo(hdc, &fs, 0);
2417 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2419 SetLastError(0xdeadbeef);
2420 ret = GetTextFaceA(hdc, sizeof(name), name);
2421 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2423 if (charset == SYMBOL_CHARSET)
2425 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2426 ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n");
2428 else
2430 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2431 ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2434 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2436 trace("Can't find codepage for charset %d\n", cs);
2437 ReleaseDC(0, hdc);
2438 return FALSE;
2440 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2442 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2444 skip("Font code page %d, looking for code page %d\n",
2445 pGdiGetCodePage(hdc), code_page);
2446 ReleaseDC(0, hdc);
2447 return FALSE;
2450 if (unicode)
2452 char ansi_buf[128];
2453 WCHAR unicode_buf[128];
2455 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2457 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2459 SetLastError(0xdeadbeef);
2460 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2461 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2462 count, ret, GetLastError());
2464 else
2466 char ansi_buf[128];
2468 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2470 SetLastError(0xdeadbeef);
2471 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2472 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2473 count, ret, GetLastError());
2476 SelectObject(hdc, hfont_old);
2477 DeleteObject(hfont);
2479 ReleaseDC(0, hdc);
2481 return TRUE;
2484 static void test_font_charset(void)
2486 static struct charset_data
2488 INT charset;
2489 UINT code_page;
2490 WORD font_idxA[128], font_idxW[128];
2491 } cd[] =
2493 { ANSI_CHARSET, 1252 },
2494 { RUSSIAN_CHARSET, 1251 },
2495 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2497 int i;
2499 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2501 win_skip("Skipping the font charset test on a Win9x platform\n");
2502 return;
2505 if (!is_font_installed("Arial"))
2507 skip("Arial is not installed\n");
2508 return;
2511 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2513 if (cd[i].charset == SYMBOL_CHARSET)
2515 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2517 skip("Symbol or Wingdings is not installed\n");
2518 break;
2521 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2522 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2523 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2526 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2527 if (i > 2)
2529 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2530 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2532 else
2533 skip("Symbol or Wingdings is not installed\n");
2536 static void test_GdiGetCodePage(void)
2538 static const struct _matching_data
2540 UINT current_codepage;
2541 LPCSTR lfFaceName;
2542 UCHAR lfCharSet;
2543 UINT expected_codepage;
2544 } matching_data[] = {
2545 {1251, "Arial", ANSI_CHARSET, 1252},
2546 {1251, "Tahoma", ANSI_CHARSET, 1252},
2548 {1252, "Arial", ANSI_CHARSET, 1252},
2549 {1252, "Tahoma", ANSI_CHARSET, 1252},
2551 {1253, "Arial", ANSI_CHARSET, 1252},
2552 {1253, "Tahoma", ANSI_CHARSET, 1252},
2554 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2555 { 932, "Tahoma", ANSI_CHARSET, 1252},
2556 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2558 { 936, "Arial", ANSI_CHARSET, 936},
2559 { 936, "Tahoma", ANSI_CHARSET, 936},
2560 { 936, "Simsun", ANSI_CHARSET, 936},
2562 { 949, "Arial", ANSI_CHARSET, 949},
2563 { 949, "Tahoma", ANSI_CHARSET, 949},
2564 { 949, "Gulim", ANSI_CHARSET, 949},
2566 { 950, "Arial", ANSI_CHARSET, 950},
2567 { 950, "Tahoma", ANSI_CHARSET, 950},
2568 { 950, "PMingLiU", ANSI_CHARSET, 950},
2570 HDC hdc;
2571 LOGFONTA lf;
2572 HFONT hfont;
2573 UINT charset, acp;
2574 DWORD codepage;
2575 int i;
2577 if (!pGdiGetCodePage)
2579 skip("GdiGetCodePage not available on this platform\n");
2580 return;
2583 acp = GetACP();
2585 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2587 /* only test data matched current locale codepage */
2588 if (matching_data[i].current_codepage != acp)
2589 continue;
2591 if (!is_font_installed(matching_data[i].lfFaceName))
2593 skip("%s is not installed\n", matching_data[i].lfFaceName);
2594 continue;
2597 hdc = GetDC(0);
2599 memset(&lf, 0, sizeof(lf));
2600 lf.lfHeight = -16;
2601 lf.lfCharSet = matching_data[i].lfCharSet;
2602 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2603 hfont = CreateFontIndirectA(&lf);
2604 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2606 hfont = SelectObject(hdc, hfont);
2607 charset = GetTextCharset(hdc);
2608 codepage = pGdiGetCodePage(hdc);
2609 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2610 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2611 ok(codepage == matching_data[i].expected_codepage,
2612 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2614 hfont = SelectObject(hdc, hfont);
2615 DeleteObject(hfont);
2617 /* CLIP_DFA_DISABLE turns off the font association */
2618 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2619 hfont = CreateFontIndirectA(&lf);
2620 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2622 hfont = SelectObject(hdc, hfont);
2623 charset = GetTextCharset(hdc);
2624 codepage = pGdiGetCodePage(hdc);
2625 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2626 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2627 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2629 hfont = SelectObject(hdc, hfont);
2630 DeleteObject(hfont);
2632 ReleaseDC(NULL, hdc);
2636 static void test_GetFontUnicodeRanges(void)
2638 LOGFONTA lf;
2639 HDC hdc;
2640 HFONT hfont, hfont_old;
2641 DWORD size;
2642 GLYPHSET *gs;
2643 DWORD i;
2645 if (!pGetFontUnicodeRanges)
2647 win_skip("GetFontUnicodeRanges not available before W2K\n");
2648 return;
2651 memset(&lf, 0, sizeof(lf));
2652 lstrcpyA(lf.lfFaceName, "Arial");
2653 hfont = create_font("Arial", &lf);
2655 hdc = GetDC(0);
2656 hfont_old = SelectObject(hdc, hfont);
2658 size = pGetFontUnicodeRanges(NULL, NULL);
2659 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2661 size = pGetFontUnicodeRanges(hdc, NULL);
2662 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2664 gs = HeapAlloc(GetProcessHeap(), 0, size);
2666 size = pGetFontUnicodeRanges(hdc, gs);
2667 ok(size, "GetFontUnicodeRanges failed\n");
2669 if (0) /* Disabled to limit console spam */
2670 for (i = 0; i < gs->cRanges; i++)
2671 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2672 trace("found %u ranges\n", gs->cRanges);
2674 HeapFree(GetProcessHeap(), 0, gs);
2676 SelectObject(hdc, hfont_old);
2677 DeleteObject(hfont);
2678 ReleaseDC(NULL, hdc);
2681 #define MAX_ENUM_FONTS 4096
2683 struct enum_font_data
2685 int total;
2686 LOGFONTA lf[MAX_ENUM_FONTS];
2689 struct enum_fullname_data
2691 int total;
2692 ENUMLOGFONTA elf[MAX_ENUM_FONTS];
2695 struct enum_font_dataW
2697 int total;
2698 LOGFONTW lf[MAX_ENUM_FONTS];
2701 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2703 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2704 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2706 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2707 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2709 if (type != TRUETYPE_FONTTYPE) return 1;
2711 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2713 if (0) /* Disabled to limit console spam */
2714 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2715 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2716 if (efd->total < MAX_ENUM_FONTS)
2717 efd->lf[efd->total++] = *lf;
2718 else
2719 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2721 return 1;
2724 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2726 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2727 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2729 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2730 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2732 if (type != TRUETYPE_FONTTYPE) return 1;
2734 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2736 if (0) /* Disabled to limit console spam */
2737 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2738 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2739 if (efd->total < MAX_ENUM_FONTS)
2740 efd->lf[efd->total++] = *lf;
2741 else
2742 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2744 return 1;
2747 static void get_charset_stats(struct enum_font_data *efd,
2748 int *ansi_charset, int *symbol_charset,
2749 int *russian_charset)
2751 int i;
2753 *ansi_charset = 0;
2754 *symbol_charset = 0;
2755 *russian_charset = 0;
2757 for (i = 0; i < efd->total; i++)
2759 switch (efd->lf[i].lfCharSet)
2761 case ANSI_CHARSET:
2762 (*ansi_charset)++;
2763 break;
2764 case SYMBOL_CHARSET:
2765 (*symbol_charset)++;
2766 break;
2767 case RUSSIAN_CHARSET:
2768 (*russian_charset)++;
2769 break;
2774 static void get_charset_statsW(struct enum_font_dataW *efd,
2775 int *ansi_charset, int *symbol_charset,
2776 int *russian_charset)
2778 int i;
2780 *ansi_charset = 0;
2781 *symbol_charset = 0;
2782 *russian_charset = 0;
2784 for (i = 0; i < efd->total; i++)
2786 switch (efd->lf[i].lfCharSet)
2788 case ANSI_CHARSET:
2789 (*ansi_charset)++;
2790 break;
2791 case SYMBOL_CHARSET:
2792 (*symbol_charset)++;
2793 break;
2794 case RUSSIAN_CHARSET:
2795 (*russian_charset)++;
2796 break;
2801 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2803 struct enum_font_data efd;
2804 struct enum_font_dataW efdw;
2805 LOGFONTA lf;
2806 HDC hdc;
2807 int i, ret, ansi_charset, symbol_charset, russian_charset;
2809 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2811 if (*font_name && !is_truetype_font_installed(font_name))
2813 skip("%s is not installed\n", font_name);
2814 return;
2817 hdc = GetDC(0);
2819 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2820 * while EnumFontFamiliesEx doesn't.
2822 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2825 * Use EnumFontFamiliesW since win98 crashes when the
2826 * second parameter is NULL using EnumFontFamilies
2828 efdw.total = 0;
2829 SetLastError(0xdeadbeef);
2830 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2831 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2832 if(ret)
2834 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2835 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2836 ansi_charset, symbol_charset, russian_charset);
2837 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2838 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2839 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2840 ok(russian_charset > 0 ||
2841 broken(russian_charset == 0), /* NT4 */
2842 "NULL family should enumerate RUSSIAN_CHARSET\n");
2845 efdw.total = 0;
2846 SetLastError(0xdeadbeef);
2847 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2848 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2849 if(ret)
2851 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2852 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2853 ansi_charset, symbol_charset, russian_charset);
2854 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2855 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2856 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2857 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2861 efd.total = 0;
2862 SetLastError(0xdeadbeef);
2863 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2864 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2865 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2866 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2867 ansi_charset, symbol_charset, russian_charset,
2868 *font_name ? font_name : "<empty>");
2869 if (*font_name)
2870 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2871 else
2872 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2873 for (i = 0; i < efd.total; i++)
2875 /* FIXME: remove completely once Wine is fixed */
2876 if (efd.lf[i].lfCharSet != font_charset)
2878 todo_wine
2879 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2881 else
2882 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2883 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2884 font_name, efd.lf[i].lfFaceName);
2887 memset(&lf, 0, sizeof(lf));
2888 lf.lfCharSet = ANSI_CHARSET;
2889 strcpy(lf.lfFaceName, font_name);
2890 efd.total = 0;
2891 SetLastError(0xdeadbeef);
2892 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2893 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2894 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2895 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2896 ansi_charset, symbol_charset, russian_charset,
2897 *font_name ? font_name : "<empty>");
2898 if (font_charset == SYMBOL_CHARSET)
2900 if (*font_name)
2901 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2902 else
2903 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2905 else
2907 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2908 for (i = 0; i < efd.total; i++)
2910 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2911 if (*font_name)
2912 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2913 font_name, efd.lf[i].lfFaceName);
2917 /* DEFAULT_CHARSET should enumerate all available charsets */
2918 memset(&lf, 0, sizeof(lf));
2919 lf.lfCharSet = DEFAULT_CHARSET;
2920 strcpy(lf.lfFaceName, font_name);
2921 efd.total = 0;
2922 SetLastError(0xdeadbeef);
2923 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2924 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2925 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2926 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2927 ansi_charset, symbol_charset, russian_charset,
2928 *font_name ? font_name : "<empty>");
2929 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2930 for (i = 0; i < efd.total; i++)
2932 if (*font_name)
2933 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2934 font_name, efd.lf[i].lfFaceName);
2936 if (*font_name)
2938 switch (font_charset)
2940 case ANSI_CHARSET:
2941 ok(ansi_charset > 0,
2942 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2943 ok(!symbol_charset,
2944 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2945 ok(russian_charset > 0,
2946 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2947 break;
2948 case SYMBOL_CHARSET:
2949 ok(!ansi_charset,
2950 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2951 ok(symbol_charset,
2952 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2953 ok(!russian_charset,
2954 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2955 break;
2956 case DEFAULT_CHARSET:
2957 ok(ansi_charset > 0,
2958 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2959 ok(symbol_charset > 0,
2960 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2961 ok(russian_charset > 0,
2962 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2963 break;
2966 else
2968 ok(ansi_charset > 0,
2969 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2970 ok(symbol_charset > 0,
2971 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2972 ok(russian_charset > 0,
2973 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2976 memset(&lf, 0, sizeof(lf));
2977 lf.lfCharSet = SYMBOL_CHARSET;
2978 strcpy(lf.lfFaceName, font_name);
2979 efd.total = 0;
2980 SetLastError(0xdeadbeef);
2981 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2982 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2983 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2984 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2985 ansi_charset, symbol_charset, russian_charset,
2986 *font_name ? font_name : "<empty>");
2987 if (*font_name && font_charset == ANSI_CHARSET)
2988 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2989 else
2991 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2992 for (i = 0; i < efd.total; i++)
2994 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2995 if (*font_name)
2996 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2997 font_name, efd.lf[i].lfFaceName);
3000 ok(!ansi_charset,
3001 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3002 ok(symbol_charset > 0,
3003 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3004 ok(!russian_charset,
3005 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3008 ReleaseDC(0, hdc);
3011 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
3013 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
3014 LOGFONTA *target = (LOGFONTA *)lParam;
3015 const DWORD valid_bits = 0x003f01ff;
3016 CHARSETINFO csi;
3017 DWORD fs;
3019 if (type != TRUETYPE_FONTTYPE) return TRUE;
3021 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
3022 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
3023 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
3024 *target = *lf;
3025 return FALSE;
3029 return TRUE;
3032 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3034 struct enum_font_data *efd = (struct enum_font_data *)lParam;
3036 if (type != TRUETYPE_FONTTYPE) return 1;
3038 if (efd->total < MAX_ENUM_FONTS)
3039 efd->lf[efd->total++] = *lf;
3040 else
3041 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
3043 return 1;
3046 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3048 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3050 if (type != TRUETYPE_FONTTYPE) return 1;
3052 if (efnd->total < MAX_ENUM_FONTS)
3053 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3054 else
3055 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
3057 return 1;
3060 static void test_EnumFontFamiliesEx_default_charset(void)
3062 struct enum_font_data efd;
3063 LOGFONTA target, enum_font;
3064 UINT acp;
3065 HDC hdc;
3066 CHARSETINFO csi;
3068 acp = GetACP();
3069 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3070 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3071 return;
3074 hdc = GetDC(0);
3075 memset(&enum_font, 0, sizeof(enum_font));
3076 enum_font.lfCharSet = csi.ciCharset;
3077 target.lfFaceName[0] = '\0';
3078 target.lfCharSet = csi.ciCharset;
3079 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3080 if (target.lfFaceName[0] == '\0') {
3081 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3082 return;
3084 if (acp == 874 || acp == 1255 || acp == 1256) {
3085 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3086 target.lfCharSet = ANSI_CHARSET;
3089 efd.total = 0;
3090 memset(&enum_font, 0, sizeof(enum_font));
3091 strcpy(enum_font.lfFaceName, target.lfFaceName);
3092 enum_font.lfCharSet = DEFAULT_CHARSET;
3093 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3094 ReleaseDC(0, hdc);
3096 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3097 if (efd.total < 2) {
3098 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3099 return;
3102 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3103 "(%s) got charset %d expected %d\n",
3104 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3106 return;
3109 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3111 HFONT hfont, hfont_prev;
3112 DWORD ret;
3113 GLYPHMETRICS gm1, gm2;
3114 LOGFONTA lf2 = *lf;
3115 WORD idx;
3117 if(!pGetGlyphIndicesA)
3118 return;
3120 /* negative widths are handled just as positive ones */
3121 lf2.lfWidth = -lf->lfWidth;
3123 SetLastError(0xdeadbeef);
3124 hfont = CreateFontIndirectA(lf);
3125 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3126 check_font("original", lf, hfont);
3128 hfont_prev = SelectObject(hdc, hfont);
3130 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3131 if (ret == GDI_ERROR || idx == 0xffff)
3133 SelectObject(hdc, hfont_prev);
3134 DeleteObject(hfont);
3135 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3136 return;
3139 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3140 memset(&gm1, 0xab, sizeof(gm1));
3141 SetLastError(0xdeadbeef);
3142 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3143 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3145 SelectObject(hdc, hfont_prev);
3146 DeleteObject(hfont);
3148 SetLastError(0xdeadbeef);
3149 hfont = CreateFontIndirectA(&lf2);
3150 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3151 check_font("negative width", &lf2, hfont);
3153 hfont_prev = SelectObject(hdc, hfont);
3155 memset(&gm2, 0xbb, sizeof(gm2));
3156 SetLastError(0xdeadbeef);
3157 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3158 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3160 SelectObject(hdc, hfont_prev);
3161 DeleteObject(hfont);
3163 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3164 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3165 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3166 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3167 gm1.gmCellIncX == gm2.gmCellIncX &&
3168 gm1.gmCellIncY == gm2.gmCellIncY,
3169 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3170 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3171 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3172 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3173 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3176 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3177 #include "pshpack2.h"
3178 typedef struct
3180 USHORT version;
3181 SHORT xAvgCharWidth;
3182 USHORT usWeightClass;
3183 USHORT usWidthClass;
3184 SHORT fsType;
3185 SHORT ySubscriptXSize;
3186 SHORT ySubscriptYSize;
3187 SHORT ySubscriptXOffset;
3188 SHORT ySubscriptYOffset;
3189 SHORT ySuperscriptXSize;
3190 SHORT ySuperscriptYSize;
3191 SHORT ySuperscriptXOffset;
3192 SHORT ySuperscriptYOffset;
3193 SHORT yStrikeoutSize;
3194 SHORT yStrikeoutPosition;
3195 SHORT sFamilyClass;
3196 PANOSE panose;
3197 ULONG ulUnicodeRange1;
3198 ULONG ulUnicodeRange2;
3199 ULONG ulUnicodeRange3;
3200 ULONG ulUnicodeRange4;
3201 CHAR achVendID[4];
3202 USHORT fsSelection;
3203 USHORT usFirstCharIndex;
3204 USHORT usLastCharIndex;
3205 /* According to the Apple spec, original version didn't have the below fields,
3206 * version numbers were taken from the OpenType spec.
3208 /* version 0 (TrueType 1.5) */
3209 USHORT sTypoAscender;
3210 USHORT sTypoDescender;
3211 USHORT sTypoLineGap;
3212 USHORT usWinAscent;
3213 USHORT usWinDescent;
3214 /* version 1 (TrueType 1.66) */
3215 ULONG ulCodePageRange1;
3216 ULONG ulCodePageRange2;
3217 /* version 2 (OpenType 1.2) */
3218 SHORT sxHeight;
3219 SHORT sCapHeight;
3220 USHORT usDefaultChar;
3221 USHORT usBreakChar;
3222 USHORT usMaxContext;
3223 /* version 4 (OpenType 1.6) */
3224 USHORT usLowerOpticalPointSize;
3225 USHORT usUpperOpticalPointSize;
3226 } TT_OS2_V4;
3227 #include "poppack.h"
3229 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3231 typedef struct
3233 USHORT version;
3234 USHORT num_tables;
3235 } cmap_header;
3237 typedef struct
3239 USHORT plat_id;
3240 USHORT enc_id;
3241 ULONG offset;
3242 } cmap_encoding_record;
3244 typedef struct
3246 USHORT format;
3247 USHORT length;
3248 USHORT language;
3250 BYTE glyph_ids[256];
3251 } cmap_format_0;
3253 typedef struct
3255 USHORT format;
3256 USHORT length;
3257 USHORT language;
3259 USHORT seg_countx2;
3260 USHORT search_range;
3261 USHORT entry_selector;
3262 USHORT range_shift;
3264 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3265 /* Then follows:
3266 USHORT pad;
3267 USHORT start_count[seg_countx2 / 2];
3268 USHORT id_delta[seg_countx2 / 2];
3269 USHORT id_range_offset[seg_countx2 / 2];
3270 USHORT glyph_ids[];
3272 } cmap_format_4;
3274 typedef struct
3276 USHORT end_count;
3277 USHORT start_count;
3278 USHORT id_delta;
3279 USHORT id_range_offset;
3280 } cmap_format_4_seg;
3282 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V4 *os2, WORD family, const char *name)
3284 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3285 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3286 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3287 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3288 os2->panose.bWeight, os2->panose.bProportion);
3291 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3293 int i;
3294 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3296 *first = 256;
3298 for(i = 0; i < 256; i++)
3300 if(cmap->glyph_ids[i] == 0) continue;
3301 *last = i;
3302 if(*first == 256) *first = i;
3304 if(*first == 256) return FALSE;
3305 return TRUE;
3308 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3310 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3311 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3312 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3313 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3314 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3317 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3319 int i;
3320 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3321 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3323 *first = 0x10000;
3325 for(i = 0; i < seg_count; i++)
3327 cmap_format_4_seg seg;
3329 get_seg4(cmap, i, &seg);
3331 if(seg.start_count > 0xfffe) break;
3333 if(*first == 0x10000) *first = seg.start_count;
3335 *last = min(seg.end_count, 0xfffe);
3338 if(*first == 0x10000) return FALSE;
3339 return TRUE;
3342 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3344 USHORT i;
3345 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3347 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3349 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3350 return (BYTE *)header + GET_BE_DWORD(record->offset);
3351 record++;
3353 return NULL;
3356 typedef enum
3358 cmap_none,
3359 cmap_ms_unicode,
3360 cmap_ms_symbol
3361 } cmap_type;
3363 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3365 LONG size, ret;
3366 cmap_header *header;
3367 void *cmap;
3368 BOOL r = FALSE;
3369 WORD format;
3371 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3372 ok(size != GDI_ERROR, "no cmap table found\n");
3373 if(size == GDI_ERROR) return FALSE;
3375 header = HeapAlloc(GetProcessHeap(), 0, size);
3376 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3377 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3378 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3380 cmap = get_cmap(header, 3, 1);
3381 if(cmap)
3382 *cmap_type = cmap_ms_unicode;
3383 else
3385 cmap = get_cmap(header, 3, 0);
3386 if(cmap) *cmap_type = cmap_ms_symbol;
3388 if(!cmap)
3390 *cmap_type = cmap_none;
3391 goto end;
3394 format = GET_BE_WORD(*(WORD *)cmap);
3395 switch(format)
3397 case 0:
3398 r = get_first_last_from_cmap0(cmap, first, last);
3399 break;
3400 case 4:
3401 r = get_first_last_from_cmap4(cmap, first, last, size);
3402 break;
3403 default:
3404 trace("unhandled cmap format %d\n", format);
3405 break;
3408 end:
3409 HeapFree(GetProcessHeap(), 0, header);
3410 return r;
3413 #define TT_PLATFORM_APPLE_UNICODE 0
3414 #define TT_PLATFORM_MACINTOSH 1
3415 #define TT_PLATFORM_MICROSOFT 3
3416 #define TT_APPLE_ID_DEFAULT 0
3417 #define TT_APPLE_ID_ISO_10646 2
3418 #define TT_APPLE_ID_UNICODE_2_0 3
3419 #define TT_MS_ID_SYMBOL_CS 0
3420 #define TT_MS_ID_UNICODE_CS 1
3421 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3422 #define TT_NAME_ID_FONT_FAMILY 1
3423 #define TT_NAME_ID_FONT_SUBFAMILY 2
3424 #define TT_NAME_ID_UNIQUE_ID 3
3425 #define TT_NAME_ID_FULL_NAME 4
3426 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3428 typedef struct sfnt_name
3430 USHORT platform_id;
3431 USHORT encoding_id;
3432 USHORT language_id;
3433 USHORT name_id;
3434 USHORT length;
3435 USHORT offset;
3436 } sfnt_name;
3438 static const LANGID mac_langid_table[] =
3440 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3441 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3442 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3443 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3444 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3445 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3446 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3447 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3448 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3449 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3450 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3451 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3452 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3453 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3454 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3455 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3456 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3457 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3458 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3459 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3460 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3461 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3462 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3463 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3464 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3465 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3466 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3467 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3468 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3469 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3470 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3471 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3472 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3473 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3474 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3475 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3476 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3477 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3478 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3479 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3480 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3481 0, /* TT_MAC_LANGID_YIDDISH */
3482 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3483 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3484 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3485 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3486 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3487 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3488 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3489 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3490 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3491 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3492 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3493 0, /* TT_MAC_LANGID_MOLDAVIAN */
3494 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3495 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3496 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3497 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3498 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3499 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3500 0, /* TT_MAC_LANGID_KURDISH */
3501 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3502 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3503 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3504 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3505 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3506 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3507 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3508 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3509 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3510 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3511 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3512 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3513 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3514 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3515 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3516 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3517 0, /* TT_MAC_LANGID_BURMESE */
3518 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3519 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3520 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3521 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3522 0, /* TT_MAC_LANGID_TAGALOG */
3523 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3524 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3525 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3526 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3527 0, /* TT_MAC_LANGID_GALLA */
3528 0, /* TT_MAC_LANGID_SOMALI */
3529 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3530 0, /* TT_MAC_LANGID_RUANDA */
3531 0, /* TT_MAC_LANGID_RUNDI */
3532 0, /* TT_MAC_LANGID_CHEWA */
3533 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3534 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3535 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3536 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3537 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3538 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3539 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3540 0, /* TT_MAC_LANGID_LATIN */
3541 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3542 0, /* TT_MAC_LANGID_GUARANI */
3543 0, /* TT_MAC_LANGID_AYMARA */
3544 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3545 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3546 0, /* TT_MAC_LANGID_DZONGKHA */
3547 0, /* TT_MAC_LANGID_JAVANESE */
3548 0, /* TT_MAC_LANGID_SUNDANESE */
3549 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3550 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3551 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3552 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3553 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3554 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3555 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3556 0, /* TT_MAC_LANGID_TONGAN */
3557 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3558 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3559 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3562 static inline WORD get_mac_code_page( const sfnt_name *name )
3564 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3565 return 10000 + GET_BE_WORD(name->encoding_id);
3568 static int match_name_table_language( const sfnt_name *name, LANGID lang )
3570 LANGID name_lang;
3571 int res = 0;
3573 switch (GET_BE_WORD(name->platform_id))
3575 case TT_PLATFORM_MICROSOFT:
3576 res += 5; /* prefer the Microsoft name */
3577 switch (GET_BE_WORD(name->encoding_id))
3579 case TT_MS_ID_UNICODE_CS:
3580 case TT_MS_ID_SYMBOL_CS:
3581 name_lang = GET_BE_WORD(name->language_id);
3582 break;
3583 default:
3584 return 0;
3586 break;
3587 case TT_PLATFORM_MACINTOSH:
3588 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3589 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3590 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3591 break;
3592 case TT_PLATFORM_APPLE_UNICODE:
3593 res += 2; /* prefer Unicode encodings */
3594 switch (GET_BE_WORD(name->encoding_id))
3596 case TT_APPLE_ID_DEFAULT:
3597 case TT_APPLE_ID_ISO_10646:
3598 case TT_APPLE_ID_UNICODE_2_0:
3599 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3600 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3601 break;
3602 default:
3603 return 0;
3605 break;
3606 default:
3607 return 0;
3609 if (name_lang == lang) res += 30;
3610 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3611 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3612 return res;
3615 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3617 struct sfnt_name_header
3619 USHORT format;
3620 USHORT number_of_record;
3621 USHORT storage_offset;
3622 } *header;
3623 sfnt_name *entry;
3624 BOOL r = FALSE;
3625 LONG size, offset, length;
3626 LONG c, ret;
3627 WCHAR *name;
3628 BYTE *data;
3629 USHORT i;
3630 int res, best_lang = 0, best_index = -1;
3632 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3633 ok(size != GDI_ERROR, "no name table found\n");
3634 if(size == GDI_ERROR) return FALSE;
3636 data = HeapAlloc(GetProcessHeap(), 0, size);
3637 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3638 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3640 header = (void *)data;
3641 header->format = GET_BE_WORD(header->format);
3642 header->number_of_record = GET_BE_WORD(header->number_of_record);
3643 header->storage_offset = GET_BE_WORD(header->storage_offset);
3644 if (header->format != 0)
3646 trace("got format %u\n", header->format);
3647 goto out;
3649 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3651 trace("number records out of range: %d\n", header->number_of_record);
3652 goto out;
3654 if (header->storage_offset >= size)
3656 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3657 goto out;
3660 entry = (void *)&header[1];
3661 for (i = 0; i < header->number_of_record; i++)
3663 if (GET_BE_WORD(entry[i].name_id) != name_id) continue;
3664 res = match_name_table_language( &entry[i], language_id);
3665 if (res > best_lang)
3667 best_lang = res;
3668 best_index = i;
3672 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset);
3673 length = GET_BE_WORD(entry[best_index].length);
3674 if (offset + length > size)
3676 trace("entry %d is out of range\n", best_index);
3677 goto out;
3679 if (length >= out_size)
3681 trace("buffer too small for entry %d\n", best_index);
3682 goto out;
3685 name = (WCHAR *)(data + offset);
3686 for (c = 0; c < length / 2; c++)
3687 out_buf[c] = GET_BE_WORD(name[c]);
3688 out_buf[c] = 0;
3690 r = TRUE;
3692 out:
3693 HeapFree(GetProcessHeap(), 0, data);
3694 return r;
3697 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3699 HDC hdc;
3700 HFONT hfont, hfont_old;
3701 TEXTMETRICA tmA;
3702 TT_OS2_V4 tt_os2;
3703 LONG size, ret;
3704 const char *font_name = lf->lfFaceName;
3705 DWORD cmap_first = 0, cmap_last = 0;
3706 UINT ascent, descent, cell_height;
3707 cmap_type cmap_type;
3708 BOOL sys_lang_non_english;
3710 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3711 hdc = GetDC(0);
3713 SetLastError(0xdeadbeef);
3714 hfont = CreateFontIndirectA(lf);
3715 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3717 hfont_old = SelectObject(hdc, hfont);
3719 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3720 if (size == GDI_ERROR)
3722 trace("OS/2 chunk was not found\n");
3723 goto end_of_test;
3725 if (size > sizeof(tt_os2))
3727 trace("got too large OS/2 chunk of size %u\n", size);
3728 size = sizeof(tt_os2);
3731 memset(&tt_os2, 0, sizeof(tt_os2));
3732 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3733 ok(ret >= TT_OS2_V0_SIZE && ret <= size, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE,
3734 size, ret);
3736 SetLastError(0xdeadbeef);
3737 ret = GetTextMetricsA(hdc, &tmA);
3738 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3740 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3742 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3744 else
3746 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3747 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3748 UINT os2_first_char, os2_last_char, default_char, break_char;
3749 USHORT version;
3750 TEXTMETRICW tmW;
3752 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3753 descent = abs((SHORT)GET_BE_WORD(tt_os2.usWinDescent));
3754 cell_height = ascent + descent;
3755 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3756 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3758 version = GET_BE_WORD(tt_os2.version);
3760 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3761 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3762 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3763 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3765 if (winetest_debug > 1)
3766 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3767 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3768 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3770 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3772 expect_first_W = 0;
3773 switch(GetACP())
3775 case 1255: /* Hebrew */
3776 expect_last_W = 0xf896;
3777 break;
3778 case 1257: /* Baltic */
3779 expect_last_W = 0xf8fd;
3780 break;
3781 default:
3782 expect_last_W = 0xf0ff;
3784 expect_break_W = 0x20;
3785 expect_default_W = expect_break_W - 1;
3786 expect_first_A = 0x1e;
3787 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3789 else
3791 expect_first_W = cmap_first;
3792 expect_last_W = cmap_last;
3793 if(os2_first_char <= 1)
3794 expect_break_W = os2_first_char + 2;
3795 else if(os2_first_char > 0xff)
3796 expect_break_W = 0x20;
3797 else
3798 expect_break_W = os2_first_char;
3799 expect_default_W = expect_break_W - 1;
3800 expect_first_A = expect_default_W - 1;
3801 expect_last_A = min(expect_last_W, 0xff);
3803 expect_break_A = expect_break_W;
3804 expect_default_A = expect_default_W;
3806 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3807 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3808 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3809 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3810 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3811 else
3812 ok(tmA.tmFirstChar == expect_first_A ||
3813 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3814 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3815 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3816 ok(tmA.tmLastChar == expect_last_A ||
3817 tmA.tmLastChar == 0xff /* win9x */,
3818 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3819 else
3820 skip("tmLastChar is DBCS lead byte\n");
3821 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3822 font_name, tmA.tmBreakChar, expect_break_A);
3823 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3824 "A: tmDefaultChar for %s got %02x expected %02x\n",
3825 font_name, tmA.tmDefaultChar, expect_default_A);
3828 SetLastError(0xdeadbeef);
3829 ret = GetTextMetricsW(hdc, &tmW);
3830 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3831 "GetTextMetricsW error %u\n", GetLastError());
3832 if (ret)
3834 /* Wine uses the os2 first char */
3835 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3836 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3837 font_name, tmW.tmFirstChar, expect_first_W);
3838 else
3839 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3840 font_name, tmW.tmFirstChar, expect_first_W);
3842 /* Wine uses the os2 last char */
3843 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3844 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3845 font_name, tmW.tmLastChar, expect_last_W);
3846 else
3847 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3848 font_name, tmW.tmLastChar, expect_last_W);
3849 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3850 font_name, tmW.tmBreakChar, expect_break_W);
3851 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3852 "W: tmDefaultChar for %s got %02x expected %02x\n",
3853 font_name, tmW.tmDefaultChar, expect_default_W);
3855 /* Test the aspect ratio while we have tmW */
3856 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3857 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3858 tmW.tmDigitizedAspectX, ret);
3859 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3860 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3861 tmW.tmDigitizedAspectX, ret);
3865 /* test FF_ values */
3866 switch(tt_os2.panose.bFamilyType)
3868 case PAN_ANY:
3869 case PAN_NO_FIT:
3870 case PAN_FAMILY_TEXT_DISPLAY:
3871 case PAN_FAMILY_PICTORIAL:
3872 default:
3873 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3874 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3876 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3877 break;
3879 switch(tt_os2.panose.bSerifStyle)
3881 case PAN_ANY:
3882 case PAN_NO_FIT:
3883 default:
3884 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3885 break;
3887 case PAN_SERIF_COVE:
3888 case PAN_SERIF_OBTUSE_COVE:
3889 case PAN_SERIF_SQUARE_COVE:
3890 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3891 case PAN_SERIF_SQUARE:
3892 case PAN_SERIF_THIN:
3893 case PAN_SERIF_BONE:
3894 case PAN_SERIF_EXAGGERATED:
3895 case PAN_SERIF_TRIANGLE:
3896 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3897 break;
3899 case PAN_SERIF_NORMAL_SANS:
3900 case PAN_SERIF_OBTUSE_SANS:
3901 case PAN_SERIF_PERP_SANS:
3902 case PAN_SERIF_FLARED:
3903 case PAN_SERIF_ROUNDED:
3904 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3905 break;
3907 break;
3909 case PAN_FAMILY_SCRIPT:
3910 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3911 break;
3913 case PAN_FAMILY_DECORATIVE:
3914 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3915 break;
3918 test_negative_width(hdc, lf);
3920 end_of_test:
3921 SelectObject(hdc, hfont_old);
3922 DeleteObject(hfont);
3924 ReleaseDC(0, hdc);
3927 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3929 INT *enumed = (INT *)lParam;
3931 if (type == TRUETYPE_FONTTYPE)
3933 (*enumed)++;
3934 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
3936 return 1;
3939 static void test_GetTextMetrics(void)
3941 LOGFONTA lf;
3942 HDC hdc;
3943 INT enumed;
3945 /* Report only once */
3946 if(!pGetGlyphIndicesA)
3947 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3949 hdc = GetDC(0);
3951 memset(&lf, 0, sizeof(lf));
3952 lf.lfCharSet = DEFAULT_CHARSET;
3953 enumed = 0;
3954 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3955 trace("Tested metrics of %d truetype fonts\n", enumed);
3957 ReleaseDC(0, hdc);
3960 static void test_nonexistent_font(void)
3962 static const struct
3964 const char *name;
3965 int charset;
3966 } font_subst[] =
3968 { "Times New Roman Baltic", 186 },
3969 { "Times New Roman CE", 238 },
3970 { "Times New Roman CYR", 204 },
3971 { "Times New Roman Greek", 161 },
3972 { "Times New Roman TUR", 162 }
3974 static const struct
3976 const char *name;
3977 int charset;
3978 } shell_subst[] =
3980 { "MS Shell Dlg", 186 },
3981 { "MS Shell Dlg", 238 },
3982 { "MS Shell Dlg", 204 },
3983 { "MS Shell Dlg", 161 },
3984 { "MS Shell Dlg", 162 }
3986 LOGFONTA lf;
3987 HDC hdc;
3988 HFONT hfont;
3989 CHARSETINFO csi;
3990 INT cs, expected_cs, i, ret;
3991 char buf[LF_FACESIZE];
3993 expected_cs = GetACP();
3994 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3996 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3997 return;
3999 expected_cs = csi.ciCharset;
4000 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
4002 hdc = CreateCompatibleDC(0);
4004 for (i = 0; i < sizeof(shell_subst)/sizeof(shell_subst[0]); i++)
4006 ret = is_font_installed(shell_subst[i].name);
4007 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4008 ret = is_truetype_font_installed(shell_subst[i].name);
4009 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4011 memset(&lf, 0, sizeof(lf));
4012 lf.lfHeight = -13;
4013 lf.lfWeight = FW_REGULAR;
4014 strcpy(lf.lfFaceName, shell_subst[i].name);
4015 hfont = CreateFontIndirectA(&lf);
4016 hfont = SelectObject(hdc, hfont);
4017 GetTextFaceA(hdc, sizeof(buf), buf);
4018 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4019 cs = GetTextCharset(hdc);
4020 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name);
4022 DeleteObject(SelectObject(hdc, hfont));
4024 memset(&lf, 0, sizeof(lf));
4025 lf.lfHeight = -13;
4026 lf.lfWeight = FW_DONTCARE;
4027 strcpy(lf.lfFaceName, shell_subst[i].name);
4028 hfont = CreateFontIndirectA(&lf);
4029 hfont = SelectObject(hdc, hfont);
4030 GetTextFaceA(hdc, sizeof(buf), buf);
4031 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4032 cs = GetTextCharset(hdc);
4033 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name);
4034 DeleteObject(SelectObject(hdc, hfont));
4037 if (!is_truetype_font_installed("Arial") ||
4038 !is_truetype_font_installed("Times New Roman"))
4040 DeleteDC(hdc);
4041 skip("Arial or Times New Roman not installed\n");
4042 return;
4045 memset(&lf, 0, sizeof(lf));
4046 lf.lfHeight = 100;
4047 lf.lfWeight = FW_REGULAR;
4048 lf.lfCharSet = ANSI_CHARSET;
4049 lf.lfPitchAndFamily = FF_SWISS;
4050 strcpy(lf.lfFaceName, "Nonexistent font");
4051 hfont = CreateFontIndirectA(&lf);
4052 hfont = SelectObject(hdc, hfont);
4053 GetTextFaceA(hdc, sizeof(buf), buf);
4054 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4055 cs = GetTextCharset(hdc);
4056 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4057 DeleteObject(SelectObject(hdc, hfont));
4059 memset(&lf, 0, sizeof(lf));
4060 lf.lfHeight = -13;
4061 lf.lfWeight = FW_DONTCARE;
4062 strcpy(lf.lfFaceName, "Nonexistent font");
4063 hfont = CreateFontIndirectA(&lf);
4064 hfont = SelectObject(hdc, hfont);
4065 GetTextFaceA(hdc, sizeof(buf), buf);
4066 todo_wine /* Wine uses Arial for all substitutions */
4067 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
4068 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
4069 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4070 "Got %s\n", buf);
4071 cs = GetTextCharset(hdc);
4072 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
4073 DeleteObject(SelectObject(hdc, hfont));
4075 memset(&lf, 0, sizeof(lf));
4076 lf.lfHeight = -13;
4077 lf.lfWeight = FW_REGULAR;
4078 strcpy(lf.lfFaceName, "Nonexistent font");
4079 hfont = CreateFontIndirectA(&lf);
4080 hfont = SelectObject(hdc, hfont);
4081 GetTextFaceA(hdc, sizeof(buf), buf);
4082 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4083 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
4084 cs = GetTextCharset(hdc);
4085 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4086 DeleteObject(SelectObject(hdc, hfont));
4088 memset(&lf, 0, sizeof(lf));
4089 lf.lfHeight = -13;
4090 lf.lfWeight = FW_DONTCARE;
4091 strcpy(lf.lfFaceName, "Times New Roman");
4092 hfont = CreateFontIndirectA(&lf);
4093 hfont = SelectObject(hdc, hfont);
4094 GetTextFaceA(hdc, sizeof(buf), buf);
4095 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
4096 cs = GetTextCharset(hdc);
4097 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4098 DeleteObject(SelectObject(hdc, hfont));
4100 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
4102 ret = is_font_installed(font_subst[i].name);
4103 todo_wine
4104 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4105 "%s should be enumerated\n", font_subst[i].name);
4106 ret = is_truetype_font_installed(font_subst[i].name);
4107 todo_wine
4108 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4109 "%s should be enumerated\n", font_subst[i].name);
4111 memset(&lf, 0, sizeof(lf));
4112 lf.lfHeight = -13;
4113 lf.lfWeight = FW_REGULAR;
4114 strcpy(lf.lfFaceName, font_subst[i].name);
4115 hfont = CreateFontIndirectA(&lf);
4116 hfont = SelectObject(hdc, hfont);
4117 cs = GetTextCharset(hdc);
4118 if (font_subst[i].charset == expected_cs)
4120 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4121 GetTextFaceA(hdc, sizeof(buf), buf);
4122 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
4124 else
4126 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
4127 GetTextFaceA(hdc, sizeof(buf), buf);
4128 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4129 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
4131 DeleteObject(SelectObject(hdc, hfont));
4133 memset(&lf, 0, sizeof(lf));
4134 lf.lfHeight = -13;
4135 lf.lfWeight = FW_DONTCARE;
4136 strcpy(lf.lfFaceName, font_subst[i].name);
4137 hfont = CreateFontIndirectA(&lf);
4138 hfont = SelectObject(hdc, hfont);
4139 GetTextFaceA(hdc, sizeof(buf), buf);
4140 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
4141 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
4142 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
4143 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4144 "got %s for font %s\n", buf, font_subst[i].name);
4145 cs = GetTextCharset(hdc);
4146 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4147 DeleteObject(SelectObject(hdc, hfont));
4150 DeleteDC(hdc);
4153 static void test_RealizationInfo(void)
4155 struct font_realization_info {
4156 DWORD size;
4157 DWORD flags;
4158 DWORD cache_num;
4159 DWORD instance_id;
4160 DWORD unk;
4161 WORD face_index;
4162 WORD simulations;
4165 struct realization_info_t
4167 DWORD flags;
4168 DWORD cache_num;
4169 DWORD instance_id;
4172 HDC hdc;
4173 DWORD info[4], info2[10];
4174 BOOL r, have_file = FALSE;
4175 HFONT hfont, hfont_old;
4176 LOGFONTA lf;
4177 DWORD needed, read;
4178 HANDLE h;
4179 BYTE file[16], data[14];
4180 struct file_info
4182 FILETIME time;
4183 LARGE_INTEGER size;
4184 WCHAR path[MAX_PATH];
4185 } file_info;
4186 FILETIME time;
4187 LARGE_INTEGER size;
4189 if(!pGdiRealizationInfo)
4191 win_skip("GdiRealizationInfo not available\n");
4192 return;
4195 hdc = GetDC(0);
4197 memset(info, 0xcc, sizeof(info));
4198 r = pGdiRealizationInfo(hdc, info);
4199 ok(r != 0, "ret 0\n");
4200 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
4201 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4203 if (!is_truetype_font_installed("Tahoma"))
4205 skip("skipping GdiRealizationInfo with truetype font\n");
4206 goto end;
4209 memset(&lf, 0, sizeof(lf));
4210 strcpy(lf.lfFaceName, "Tahoma");
4211 lf.lfHeight = 20;
4212 lf.lfWeight = FW_BOLD;
4213 lf.lfItalic = 1;
4214 hfont = CreateFontIndirectA(&lf);
4215 hfont_old = SelectObject(hdc, hfont);
4217 memset(info, 0xcc, sizeof(info));
4218 r = pGdiRealizationInfo(hdc, info);
4219 ok(r != 0, "ret 0\n");
4220 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
4221 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4223 if (pGetFontRealizationInfo)
4225 struct font_realization_info *fri = (struct font_realization_info*)info2;
4226 struct realization_info_t *ri = (struct realization_info_t*)info;
4228 /* The first DWORD represents a struct size. On a
4229 newly rebooted system setting this to < 16 results
4230 in GetFontRealizationInfo failing. However there
4231 appears to be some caching going on which results
4232 in calls after a successful call also succeeding even
4233 if the size < 16. This means we can't reliably test
4234 this behaviour. */
4236 memset(info2, 0xcc, sizeof(info2));
4237 info2[0] = 16;
4238 r = pGetFontRealizationInfo(hdc, info2);
4239 ok(r != 0, "ret 0\n");
4240 /* We may get the '24' version here if that has been previously
4241 requested. */
4242 ok(fri->size == 16 || fri->size == 24, "got %d\n", info2[0]);
4243 ok(fri->flags == ri->flags, "flags mismatch\n");
4244 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4245 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4246 ok(info2[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2[6]);
4248 memset(info2, 0xcc, sizeof(info2));
4249 info2[0] = 28;
4250 r = pGetFontRealizationInfo(hdc, info2);
4251 ok(r == FALSE, "got %d\n", r);
4253 memset(info2, 0xcc, sizeof(info2));
4254 info2[0] = 24;
4255 r = pGetFontRealizationInfo(hdc, info2);
4256 ok(r != 0, "ret 0\n");
4257 ok(fri->size == 24, "got %d\n", fri->size);
4258 ok(fri->flags == ri->flags, "flags mismatch\n");
4259 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4260 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4261 ok(fri->simulations == 0x2, "got simulations flags 0x%04x\n", fri->simulations);
4262 ok(fri->face_index == 0, "got wrong face index %u\n", fri->face_index);
4263 ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4265 /* Test GetFontFileInfo() */
4266 /* invalid font id */
4267 SetLastError(0xdeadbeef);
4268 r = pGetFontFileInfo(0xabababab, 0, &file_info, sizeof(file_info), &needed);
4269 ok(r == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "ret %d gle %d\n", r, GetLastError());
4271 needed = 0;
4272 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed);
4273 ok(r != 0 || GetLastError() == ERROR_NOACCESS, "ret %d gle %d\n", r, GetLastError());
4275 if (r)
4277 ok(needed > 0 && needed < sizeof(file_info), "got needed size %u\n", needed);
4279 h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
4280 ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError());
4282 GetFileTime(h, NULL, NULL, &time);
4283 ok(!CompareFileTime(&file_info.time, &time), "time mismatch\n");
4284 GetFileSizeEx(h, &size);
4285 ok(file_info.size.QuadPart == size.QuadPart, "size mismatch\n");
4287 /* Read first 16 bytes from the file */
4288 ReadFile(h, file, sizeof(file), &read, NULL);
4289 CloseHandle(h);
4290 have_file = TRUE;
4292 /* shorter buffer */
4293 SetLastError(0xdeadbeef);
4294 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, needed - 1, &needed);
4295 ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %d\n", r, GetLastError());
4298 if (pGetFontFileData) {
4299 /* Get bytes 2 - 16 using GetFontFileData */
4300 r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data));
4301 ok(r != 0, "ret 0 gle %d\n", GetLastError());
4303 if (have_file)
4304 ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n");
4305 else
4306 win_skip("GetFontFileInfo() failed, skipping\n");
4310 DeleteObject(SelectObject(hdc, hfont_old));
4312 end:
4313 ReleaseDC(0, hdc);
4316 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4317 the nul in the count of characters copied when the face name buffer is not
4318 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4319 always includes it. */
4320 static void test_GetTextFace(void)
4322 static const char faceA[] = "Tahoma";
4323 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
4324 LOGFONTA fA = {0};
4325 LOGFONTW fW = {0};
4326 char bufA[LF_FACESIZE];
4327 WCHAR bufW[LF_FACESIZE];
4328 HFONT f, g;
4329 HDC dc;
4330 int n;
4332 if(!is_font_installed("Tahoma"))
4334 skip("Tahoma is not installed so skipping this test\n");
4335 return;
4338 /* 'A' case. */
4339 memcpy(fA.lfFaceName, faceA, sizeof faceA);
4340 f = CreateFontIndirectA(&fA);
4341 ok(f != NULL, "CreateFontIndirectA failed\n");
4343 dc = GetDC(NULL);
4344 g = SelectObject(dc, f);
4345 n = GetTextFaceA(dc, sizeof bufA, bufA);
4346 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
4347 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
4349 /* Play with the count arg. */
4350 bufA[0] = 'x';
4351 n = GetTextFaceA(dc, 0, bufA);
4352 ok(n == 0, "GetTextFaceA returned %d\n", n);
4353 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4355 bufA[0] = 'x';
4356 n = GetTextFaceA(dc, 1, bufA);
4357 ok(n == 0, "GetTextFaceA returned %d\n", n);
4358 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4360 bufA[0] = 'x'; bufA[1] = 'y';
4361 n = GetTextFaceA(dc, 2, bufA);
4362 ok(n == 1, "GetTextFaceA returned %d\n", n);
4363 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
4365 n = GetTextFaceA(dc, 0, NULL);
4366 ok(n == sizeof faceA ||
4367 broken(n == 0), /* win98, winMe */
4368 "GetTextFaceA returned %d\n", n);
4370 DeleteObject(SelectObject(dc, g));
4371 ReleaseDC(NULL, dc);
4373 /* 'W' case. */
4374 memcpy(fW.lfFaceName, faceW, sizeof faceW);
4375 SetLastError(0xdeadbeef);
4376 f = CreateFontIndirectW(&fW);
4377 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
4379 win_skip("CreateFontIndirectW is not implemented\n");
4380 return;
4382 ok(f != NULL, "CreateFontIndirectW failed\n");
4384 dc = GetDC(NULL);
4385 g = SelectObject(dc, f);
4386 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
4387 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4388 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
4390 /* Play with the count arg. */
4391 bufW[0] = 'x';
4392 n = GetTextFaceW(dc, 0, bufW);
4393 ok(n == 0, "GetTextFaceW returned %d\n", n);
4394 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4396 bufW[0] = 'x';
4397 n = GetTextFaceW(dc, 1, bufW);
4398 ok(n == 1, "GetTextFaceW returned %d\n", n);
4399 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4401 bufW[0] = 'x'; bufW[1] = 'y';
4402 n = GetTextFaceW(dc, 2, bufW);
4403 ok(n == 2, "GetTextFaceW returned %d\n", n);
4404 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4406 n = GetTextFaceW(dc, 0, NULL);
4407 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4409 DeleteObject(SelectObject(dc, g));
4410 ReleaseDC(NULL, dc);
4413 static void test_orientation(void)
4415 static const char test_str[11] = "Test String";
4416 HDC hdc;
4417 LOGFONTA lf;
4418 HFONT hfont, old_hfont;
4419 SIZE size;
4421 if (!is_truetype_font_installed("Arial"))
4423 skip("Arial is not installed\n");
4424 return;
4427 hdc = CreateCompatibleDC(0);
4428 memset(&lf, 0, sizeof(lf));
4429 lstrcpyA(lf.lfFaceName, "Arial");
4430 lf.lfHeight = 72;
4431 lf.lfOrientation = lf.lfEscapement = 900;
4432 hfont = create_font("orientation", &lf);
4433 old_hfont = SelectObject(hdc, hfont);
4434 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4435 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4436 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4437 SelectObject(hdc, old_hfont);
4438 DeleteObject(hfont);
4439 DeleteDC(hdc);
4442 static void test_oemcharset(void)
4444 HDC hdc;
4445 LOGFONTA lf, clf;
4446 HFONT hfont, old_hfont;
4447 int charset;
4449 hdc = CreateCompatibleDC(0);
4450 ZeroMemory(&lf, sizeof(lf));
4451 lf.lfHeight = 12;
4452 lf.lfCharSet = OEM_CHARSET;
4453 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4454 lstrcpyA(lf.lfFaceName, "Terminal");
4455 hfont = CreateFontIndirectA(&lf);
4456 old_hfont = SelectObject(hdc, hfont);
4457 charset = GetTextCharset(hdc);
4458 todo_wine
4459 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4460 hfont = SelectObject(hdc, old_hfont);
4461 GetObjectA(hfont, sizeof(clf), &clf);
4462 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4463 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4464 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4465 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4466 DeleteObject(hfont);
4467 DeleteDC(hdc);
4470 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4471 const TEXTMETRICA *lpntme,
4472 DWORD FontType, LPARAM lParam)
4474 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4475 CHARSETINFO csi;
4476 LOGFONTA lf = *lpelfe;
4477 HFONT hfont;
4478 DWORD found_subset;
4480 /* skip bitmap, proportional or vertical font */
4481 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4482 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4483 lf.lfFaceName[0] == '@')
4484 return 1;
4486 /* skip linked font */
4487 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4488 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4489 return 1;
4491 /* skip linked font, like SimSun-ExtB */
4492 switch (lpelfe->lfCharSet) {
4493 case SHIFTJIS_CHARSET:
4494 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4495 break;
4496 case GB2312_CHARSET:
4497 case CHINESEBIG5_CHARSET:
4498 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4499 break;
4500 case HANGEUL_CHARSET:
4501 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4502 break;
4503 default:
4504 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4505 break;
4507 if (!found_subset)
4508 return 1;
4510 /* test with an odd height */
4511 lf.lfHeight = -19;
4512 lf.lfWidth = 0;
4513 hfont = CreateFontIndirectA(&lf);
4514 if (hfont)
4516 *(HFONT *)lParam = hfont;
4517 return 0;
4519 return 1;
4522 static void test_GetGlyphOutline(void)
4524 HDC hdc;
4525 GLYPHMETRICS gm, gm2;
4526 LOGFONTA lf;
4527 HFONT hfont, old_hfont;
4528 INT ret, ret2;
4529 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4530 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4531 static const struct
4533 UINT cs;
4534 UINT a;
4535 UINT w;
4536 } c[] =
4538 {ANSI_CHARSET, 0x30, 0x30},
4539 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4540 {HANGEUL_CHARSET, 0x8141, 0xac02},
4541 {GB2312_CHARSET, 0x8141, 0x4e04},
4542 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4544 UINT i;
4546 if (!is_truetype_font_installed("Tahoma"))
4548 skip("Tahoma is not installed\n");
4549 return;
4552 hdc = CreateCompatibleDC(0);
4553 memset(&lf, 0, sizeof(lf));
4554 lf.lfHeight = 72;
4555 lstrcpyA(lf.lfFaceName, "Tahoma");
4556 SetLastError(0xdeadbeef);
4557 hfont = CreateFontIndirectA(&lf);
4558 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4559 old_hfont = SelectObject(hdc, hfont);
4561 memset(&gm, 0, sizeof(gm));
4562 SetLastError(0xdeadbeef);
4563 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4564 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4566 memset(&gm, 0, sizeof(gm));
4567 SetLastError(0xdeadbeef);
4568 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4569 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4570 ok(GetLastError() == 0xdeadbeef ||
4571 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4572 "expected 0xdeadbeef, got %u\n", GetLastError());
4574 memset(&gm, 0, sizeof(gm));
4575 SetLastError(0xdeadbeef);
4576 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4577 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4578 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4580 memset(&gm, 0, sizeof(gm));
4581 SetLastError(0xdeadbeef);
4582 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4583 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4585 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4586 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4589 /* test for needed buffer size request on space char */
4590 memset(&gm, 0, sizeof(gm));
4591 SetLastError(0xdeadbeef);
4592 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4593 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4595 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4596 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX);
4597 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY);
4600 /* requesting buffer size for space char + error */
4601 memset(&gm, 0, sizeof(gm));
4602 SetLastError(0xdeadbeef);
4603 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4604 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4606 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4607 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4608 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX);
4609 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY);
4612 /* test GetGlyphOutline with a buffer too small */
4613 SetLastError(0xdeadbeef);
4614 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat);
4615 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4616 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4618 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4620 DWORD dummy;
4622 memset(&gm, 0xab, sizeof(gm));
4623 SetLastError(0xdeadbeef);
4624 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4625 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4627 if (fmt[i] == GGO_METRICS)
4628 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4629 else
4630 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4631 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4632 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4635 memset(&gm, 0xab, sizeof(gm));
4636 SetLastError(0xdeadbeef);
4637 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4638 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4640 if (fmt[i] == GGO_METRICS)
4641 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4642 else
4643 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4644 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4645 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4648 memset(&gm, 0xab, sizeof(gm));
4649 SetLastError(0xdeadbeef);
4650 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4651 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4653 if (fmt[i] == GGO_METRICS)
4654 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4655 else
4656 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4657 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4658 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4661 memset(&gm, 0xab, sizeof(gm));
4662 SetLastError(0xdeadbeef);
4663 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4664 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4666 if (fmt[i] == GGO_METRICS) {
4667 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4668 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4669 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4671 else
4673 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4674 memset(&gm2, 0xab, sizeof(gm2));
4675 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4676 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4681 SelectObject(hdc, old_hfont);
4682 DeleteObject(hfont);
4684 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4686 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4687 TEXTMETRICA tm;
4689 lf.lfFaceName[0] = '\0';
4690 lf.lfCharSet = c[i].cs;
4691 lf.lfPitchAndFamily = 0;
4692 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4694 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4695 continue;
4698 old_hfont = SelectObject(hdc, hfont);
4700 /* expected to ignore superfluous bytes (sigle-byte character) */
4701 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4702 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4703 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4705 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4706 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4707 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4709 /* expected to ignore superfluous bytes (double-byte character) */
4710 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4711 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4712 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4713 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4715 /* expected to match wide-char version results */
4716 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4717 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4719 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4721 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4722 continue;
4724 DeleteObject(SelectObject(hdc, hfont));
4725 if (c[i].a <= 0xff)
4727 DeleteObject(SelectObject(hdc, old_hfont));
4728 continue;
4731 ret = GetObjectA(hfont, sizeof lf, &lf);
4732 ok(ret > 0, "GetObject error %u\n", GetLastError());
4734 ret = GetTextMetricsA(hdc, &tm);
4735 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4736 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4737 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4738 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4739 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4740 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4741 "expected %d, got %d (%s:%d)\n",
4742 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4744 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4745 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4746 ok(gm2.gmCellIncY == -lf.lfHeight,
4747 "expected %d, got %d (%s:%d)\n",
4748 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4750 lf.lfItalic = TRUE;
4751 hfont = CreateFontIndirectA(&lf);
4752 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4753 DeleteObject(SelectObject(hdc, hfont));
4754 ret = GetTextMetricsA(hdc, &tm);
4755 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4756 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4757 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4758 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4759 "expected %d, got %d (%s:%d)\n",
4760 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4762 lf.lfItalic = FALSE;
4763 lf.lfEscapement = lf.lfOrientation = 2700;
4764 hfont = CreateFontIndirectA(&lf);
4765 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4766 DeleteObject(SelectObject(hdc, hfont));
4767 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4768 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4769 ok(gm2.gmCellIncY == -lf.lfHeight,
4770 "expected %d, got %d (%s:%d)\n",
4771 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4773 hfont = SelectObject(hdc, old_hfont);
4774 DeleteObject(hfont);
4777 DeleteDC(hdc);
4780 /* bug #9995: there is a limit to the character width that can be specified */
4781 static void test_GetTextMetrics2(const char *fontname, int font_height)
4783 HFONT of, hf;
4784 HDC hdc;
4785 TEXTMETRICA tm;
4786 BOOL ret;
4787 int ave_width, height, width, ratio, scale;
4789 if (!is_truetype_font_installed( fontname)) {
4790 skip("%s is not installed\n", fontname);
4791 return;
4793 hdc = CreateCompatibleDC(0);
4794 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4795 /* select width = 0 */
4796 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4797 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4798 DEFAULT_QUALITY, VARIABLE_PITCH,
4799 fontname);
4800 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4801 of = SelectObject( hdc, hf);
4802 ret = GetTextMetricsA( hdc, &tm);
4803 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4804 height = tm.tmHeight;
4805 ave_width = tm.tmAveCharWidth;
4806 SelectObject( hdc, of);
4807 DeleteObject( hf);
4809 trace("height %d, ave width %d\n", height, ave_width);
4811 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4813 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4814 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4815 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4816 ok(hf != 0, "CreateFont failed\n");
4817 of = SelectObject(hdc, hf);
4818 ret = GetTextMetricsA(hdc, &tm);
4819 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4820 SelectObject(hdc, of);
4821 DeleteObject(hf);
4823 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4824 break;
4827 DeleteDC(hdc);
4829 ratio = width / height;
4830 scale = width / ave_width;
4832 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4833 width, height, ratio, width, ave_width, scale);
4835 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4838 static void test_CreateFontIndirect(void)
4840 LOGFONTA lf, getobj_lf;
4841 int ret, i;
4842 HFONT hfont;
4843 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4845 memset(&lf, 0, sizeof(lf));
4846 lf.lfCharSet = ANSI_CHARSET;
4847 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4848 lf.lfHeight = 16;
4849 lf.lfWidth = 16;
4850 lf.lfQuality = DEFAULT_QUALITY;
4851 lf.lfItalic = FALSE;
4852 lf.lfWeight = FW_DONTCARE;
4854 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4856 lstrcpyA(lf.lfFaceName, TestName[i]);
4857 hfont = CreateFontIndirectA(&lf);
4858 ok(hfont != 0, "CreateFontIndirectA failed\n");
4859 SetLastError(0xdeadbeef);
4860 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4861 ok(ret, "GetObject failed: %d\n", GetLastError());
4862 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4863 ok(lf.lfWeight == getobj_lf.lfWeight ||
4864 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4865 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4866 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4867 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4868 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4869 DeleteObject(hfont);
4873 static void test_CreateFontIndirectEx(void)
4875 ENUMLOGFONTEXDVA lfex;
4876 HFONT hfont;
4878 if (!pCreateFontIndirectExA)
4880 win_skip("CreateFontIndirectExA is not available\n");
4881 return;
4884 if (!is_truetype_font_installed("Arial"))
4886 skip("Arial is not installed\n");
4887 return;
4890 SetLastError(0xdeadbeef);
4891 hfont = pCreateFontIndirectExA(NULL);
4892 ok(hfont == NULL, "got %p\n", hfont);
4893 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4895 memset(&lfex, 0, sizeof(lfex));
4896 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
4897 hfont = pCreateFontIndirectExA(&lfex);
4898 ok(hfont != 0, "CreateFontIndirectEx failed\n");
4899 if (hfont)
4900 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
4901 DeleteObject(hfont);
4904 static void free_font(void *font)
4906 UnmapViewOfFile(font);
4909 static void *load_font(const char *font_name, DWORD *font_size)
4911 char file_name[MAX_PATH];
4912 HANDLE file, mapping;
4913 void *font;
4915 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
4916 strcat(file_name, "\\fonts\\");
4917 strcat(file_name, font_name);
4919 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4920 if (file == INVALID_HANDLE_VALUE) return NULL;
4922 *font_size = GetFileSize(file, NULL);
4924 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4925 if (!mapping)
4927 CloseHandle(file);
4928 return NULL;
4931 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4933 CloseHandle(file);
4934 CloseHandle(mapping);
4935 return font;
4938 static void test_AddFontMemResource(void)
4940 void *font;
4941 DWORD font_size, num_fonts;
4942 HANDLE ret;
4943 BOOL bRet;
4945 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4947 win_skip("AddFontMemResourceEx is not available on this platform\n");
4948 return;
4951 font = load_font("sserife.fon", &font_size);
4952 if (!font)
4954 skip("Unable to locate and load font sserife.fon\n");
4955 return;
4958 SetLastError(0xdeadbeef);
4959 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4960 ok(!ret, "AddFontMemResourceEx should fail\n");
4961 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4962 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4963 GetLastError());
4965 SetLastError(0xdeadbeef);
4966 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4967 ok(!ret, "AddFontMemResourceEx should fail\n");
4968 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4969 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4970 GetLastError());
4972 SetLastError(0xdeadbeef);
4973 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4974 ok(!ret, "AddFontMemResourceEx should fail\n");
4975 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4976 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4977 GetLastError());
4979 SetLastError(0xdeadbeef);
4980 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4981 ok(!ret, "AddFontMemResourceEx should fail\n");
4982 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4983 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4984 GetLastError());
4986 SetLastError(0xdeadbeef);
4987 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4988 ok(!ret, "AddFontMemResourceEx should fail\n");
4989 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4990 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4991 GetLastError());
4993 SetLastError(0xdeadbeef);
4994 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4995 ok(!ret, "AddFontMemResourceEx should fail\n");
4996 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4997 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4998 GetLastError());
5000 num_fonts = 0xdeadbeef;
5001 SetLastError(0xdeadbeef);
5002 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
5003 ok(!ret, "AddFontMemResourceEx should fail\n");
5004 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5005 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5006 GetLastError());
5007 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5009 if (0) /* hangs under windows 2000 */
5011 num_fonts = 0xdeadbeef;
5012 SetLastError(0xdeadbeef);
5013 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
5014 ok(!ret, "AddFontMemResourceEx should fail\n");
5015 ok(GetLastError() == 0xdeadbeef,
5016 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5017 GetLastError());
5018 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5021 num_fonts = 0xdeadbeef;
5022 SetLastError(0xdeadbeef);
5023 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
5024 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
5025 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5026 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
5028 free_font(font);
5030 SetLastError(0xdeadbeef);
5031 bRet = pRemoveFontMemResourceEx(ret);
5032 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
5034 /* test invalid pointer to number of loaded fonts */
5035 font = load_font("sserife.fon", &font_size);
5036 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
5038 SetLastError(0xdeadbeef);
5039 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
5040 ok(!ret, "AddFontMemResourceEx should fail\n");
5041 ok(GetLastError() == 0xdeadbeef,
5042 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5043 GetLastError());
5045 SetLastError(0xdeadbeef);
5046 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
5047 ok(!ret, "AddFontMemResourceEx should fail\n");
5048 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5049 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5050 GetLastError());
5052 free_font(font);
5055 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5057 LOGFONTA *lf;
5059 if (type != TRUETYPE_FONTTYPE) return 1;
5061 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5063 lf = (LOGFONTA *)lparam;
5064 *lf = *elf;
5065 return 0;
5068 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5070 int ret;
5071 LOGFONTA *lf;
5073 if (type != TRUETYPE_FONTTYPE) return 1;
5075 lf = (LOGFONTA *)lparam;
5076 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
5077 if(ret == 0)
5079 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5080 *lf = *elf;
5081 return 0;
5083 return 1;
5086 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5088 return lparam;
5091 static void test_EnumFonts(void)
5093 int ret;
5094 LOGFONTA lf;
5095 HDC hdc;
5097 if (!is_truetype_font_installed("Arial"))
5099 skip("Arial is not installed\n");
5100 return;
5103 /* Windows uses localized font face names, so Arial Bold won't be found */
5104 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
5106 skip("User locale is not English, skipping the test\n");
5107 return;
5110 hdc = CreateCompatibleDC(0);
5112 /* check that the enumproc's retval is returned */
5113 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
5114 ok(ret == 0xcafe, "got %08x\n", ret);
5116 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
5117 ok(!ret, "font Arial is not enumerated\n");
5118 ret = strcmp(lf.lfFaceName, "Arial");
5119 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5120 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5122 strcpy(lf.lfFaceName, "Arial");
5123 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5124 ok(!ret, "font Arial is not enumerated\n");
5125 ret = strcmp(lf.lfFaceName, "Arial");
5126 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5127 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5129 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
5130 ok(!ret, "font Arial Bold is not enumerated\n");
5131 ret = strcmp(lf.lfFaceName, "Arial");
5132 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5133 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5135 strcpy(lf.lfFaceName, "Arial Bold");
5136 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5137 ok(ret, "font Arial Bold should not be enumerated\n");
5139 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
5140 ok(!ret, "font Arial Bold Italic is not enumerated\n");
5141 ret = strcmp(lf.lfFaceName, "Arial");
5142 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5143 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5145 strcpy(lf.lfFaceName, "Arial Bold Italic");
5146 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5147 ok(ret, "font Arial Bold Italic should not be enumerated\n");
5149 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
5150 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5152 strcpy(lf.lfFaceName, "Arial Italic Bold");
5153 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5154 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5156 DeleteDC(hdc);
5159 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5161 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5163 if (0) /* Disabled to limit console spam */
5164 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5165 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5167 if (type != TRUETYPE_FONTTYPE) return 1;
5168 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1;
5170 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5171 return 0;
5174 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5176 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5178 if (0) /* Disabled to limit console spam */
5179 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5180 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5182 if (type != TRUETYPE_FONTTYPE) return 1;
5183 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1;
5185 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5186 return 0;
5189 static void test_EnumFonts_subst(void)
5191 int ret;
5192 LOGFONTA lf;
5193 HDC hdc;
5194 struct enum_fullname_data efnd;
5196 ret = is_font_installed("MS Shell Dlg");
5197 ok(ret, "MS Shell Dlg should be enumerated\n");
5198 ret = is_truetype_font_installed("MS Shell Dlg");
5199 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n");
5201 ret = is_font_installed("MS Shell Dlg 2");
5202 ok(ret, "MS Shell Dlg 2 should be enumerated\n");
5203 ret = is_truetype_font_installed("MS Shell Dlg 2");
5204 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5206 hdc = CreateCompatibleDC(0);
5208 memset(&efnd, 0, sizeof(efnd));
5209 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5210 ok(ret, "MS Shell Dlg should not be enumerated\n");
5211 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n");
5213 memset(&lf, 0, sizeof(lf));
5214 lf.lfCharSet = DEFAULT_CHARSET;
5216 memset(&efnd, 0, sizeof(efnd));
5217 strcpy(lf.lfFaceName, "MS Shell Dlg");
5218 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5219 ok(!ret, "MS Shell Dlg should be enumerated\n");
5220 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n");
5221 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
5222 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5223 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg");
5224 ok(ret, "did not expect MS Shell Dlg\n");
5226 memset(&efnd, 0, sizeof(efnd));
5227 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5228 ok(ret, "MS Shell Dlg 2 should not be enumerated\n");
5229 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n");
5231 memset(&efnd, 0, sizeof(efnd));
5232 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
5233 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5234 ok(!ret, "MS Shell Dlg 2 should be enumerated\n");
5235 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n");
5236 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
5237 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5238 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
5239 ok(ret, "did not expect MS Shell Dlg 2\n");
5241 DeleteDC(hdc);
5244 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5246 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
5247 const char *fullname = (const char *)lParam;
5249 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
5251 return 1;
5254 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
5256 HDC hdc = GetDC(0);
5257 BOOL ret = FALSE;
5259 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
5260 ret = TRUE;
5262 ReleaseDC(0, hdc);
5263 return ret;
5266 static void test_fullname(void)
5268 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5269 WCHAR bufW[LF_FULLFACESIZE];
5270 char bufA[LF_FULLFACESIZE];
5271 HFONT hfont, of;
5272 LOGFONTA lf;
5273 HDC hdc;
5274 int i;
5275 DWORD ret;
5277 hdc = CreateCompatibleDC(0);
5278 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5280 memset(&lf, 0, sizeof(lf));
5281 lf.lfCharSet = ANSI_CHARSET;
5282 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5283 lf.lfHeight = 16;
5284 lf.lfWidth = 16;
5285 lf.lfQuality = DEFAULT_QUALITY;
5286 lf.lfItalic = FALSE;
5287 lf.lfWeight = FW_DONTCARE;
5289 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
5291 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
5293 skip("%s is not installed\n", TestName[i]);
5294 continue;
5297 lstrcpyA(lf.lfFaceName, TestName[i]);
5298 hfont = CreateFontIndirectA(&lf);
5299 ok(hfont != 0, "CreateFontIndirectA failed\n");
5301 of = SelectObject(hdc, hfont);
5302 bufW[0] = 0;
5303 bufA[0] = 0;
5304 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
5305 ok(ret, "face full name could not be read\n");
5306 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
5307 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
5308 SelectObject(hdc, of);
5309 DeleteObject(hfont);
5311 DeleteDC(hdc);
5314 static WCHAR *prepend_at(WCHAR *family)
5316 if (!family)
5317 return NULL;
5319 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
5320 family[0] = '@';
5321 return family;
5324 static void test_fullname2_helper(const char *Family)
5326 char *FamilyName, *FaceName, *StyleName, *otmStr;
5327 struct enum_fullname_data efnd;
5328 WCHAR *bufW;
5329 char *bufA;
5330 HFONT hfont, of;
5331 LOGFONTA lf;
5332 HDC hdc;
5333 int i;
5334 DWORD otm_size, ret, buf_size;
5335 OUTLINETEXTMETRICA *otm;
5336 BOOL want_vertical, get_vertical;
5337 want_vertical = ( Family[0] == '@' );
5339 hdc = CreateCompatibleDC(0);
5340 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5342 memset(&lf, 0, sizeof(lf));
5343 lf.lfCharSet = DEFAULT_CHARSET;
5344 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5345 lf.lfHeight = 16;
5346 lf.lfWidth = 16;
5347 lf.lfQuality = DEFAULT_QUALITY;
5348 lf.lfItalic = FALSE;
5349 lf.lfWeight = FW_DONTCARE;
5350 strcpy(lf.lfFaceName, Family);
5351 efnd.total = 0;
5352 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
5353 if (efnd.total == 0)
5354 skip("%s is not installed\n", lf.lfFaceName);
5356 for (i = 0; i < efnd.total; i++)
5358 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
5359 FaceName = (char *)efnd.elf[i].elfFullName;
5360 StyleName = (char *)efnd.elf[i].elfStyle;
5362 get_vertical = ( FamilyName[0] == '@' );
5363 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
5365 lstrcpyA(lf.lfFaceName, FaceName);
5366 hfont = CreateFontIndirectA(&lf);
5367 ok(hfont != 0, "CreateFontIndirectA failed\n");
5369 of = SelectObject(hdc, hfont);
5370 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
5371 ok(buf_size != GDI_ERROR, "no name table found\n");
5372 if (buf_size == GDI_ERROR) continue;
5374 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
5375 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
5377 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5378 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5379 memset(otm, 0, otm_size);
5380 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
5381 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
5382 if (ret == 0) continue;
5384 bufW[0] = 0;
5385 bufA[0] = 0;
5386 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
5387 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5388 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
5389 if (want_vertical) bufW = prepend_at(bufW);
5390 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5391 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
5392 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
5393 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
5395 bufW[0] = 0;
5396 bufA[0] = 0;
5397 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
5398 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5399 ok(ret, "FULL_NAME (face name) could not be read\n");
5400 if (want_vertical) bufW = prepend_at(bufW);
5401 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5402 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
5403 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
5404 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
5406 bufW[0] = 0;
5407 bufA[0] = 0;
5408 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
5409 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5410 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
5411 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5412 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
5413 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
5414 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
5416 bufW[0] = 0;
5417 bufA[0] = 0;
5418 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
5419 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5420 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
5421 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5422 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
5423 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
5425 SelectObject(hdc, of);
5426 DeleteObject(hfont);
5428 HeapFree(GetProcessHeap(), 0, otm);
5429 HeapFree(GetProcessHeap(), 0, bufW);
5430 HeapFree(GetProcessHeap(), 0, bufA);
5432 DeleteDC(hdc);
5435 static void test_fullname2(void)
5437 test_fullname2_helper("Arial");
5438 test_fullname2_helper("DejaVu Sans");
5439 test_fullname2_helper("Lucida Sans");
5440 test_fullname2_helper("Tahoma");
5441 test_fullname2_helper("Webdings");
5442 test_fullname2_helper("Wingdings");
5443 test_fullname2_helper("SimSun");
5444 test_fullname2_helper("NSimSun");
5445 test_fullname2_helper("MingLiu");
5446 test_fullname2_helper("PMingLiu");
5447 test_fullname2_helper("WenQuanYi Micro Hei");
5448 test_fullname2_helper("MS UI Gothic");
5449 test_fullname2_helper("Ume UI Gothic");
5450 test_fullname2_helper("MS Gothic");
5451 test_fullname2_helper("Ume Gothic");
5452 test_fullname2_helper("MS PGothic");
5453 test_fullname2_helper("Ume P Gothic");
5454 test_fullname2_helper("Gulim");
5455 test_fullname2_helper("Batang");
5456 test_fullname2_helper("UnBatang");
5457 test_fullname2_helper("UnDotum");
5458 test_fullname2_helper("@SimSun");
5459 test_fullname2_helper("@NSimSun");
5460 test_fullname2_helper("@MingLiu");
5461 test_fullname2_helper("@PMingLiu");
5462 test_fullname2_helper("@WenQuanYi Micro Hei");
5463 test_fullname2_helper("@MS UI Gothic");
5464 test_fullname2_helper("@Ume UI Gothic");
5465 test_fullname2_helper("@MS Gothic");
5466 test_fullname2_helper("@Ume Gothic");
5467 test_fullname2_helper("@MS PGothic");
5468 test_fullname2_helper("@Ume P Gothic");
5469 test_fullname2_helper("@Gulim");
5470 test_fullname2_helper("@Batang");
5471 test_fullname2_helper("@UnBatang");
5472 test_fullname2_helper("@UnDotum");
5476 static void test_GetGlyphOutline_empty_contour(void)
5478 HDC hdc;
5479 LOGFONTA lf;
5480 HFONT hfont, hfont_prev;
5481 TTPOLYGONHEADER *header;
5482 GLYPHMETRICS gm;
5483 char buf[1024];
5484 DWORD ret;
5486 memset(&lf, 0, sizeof(lf));
5487 lf.lfHeight = 72;
5488 lstrcpyA(lf.lfFaceName, "wine_test");
5490 hfont = CreateFontIndirectA(&lf);
5491 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5493 hdc = GetDC(NULL);
5495 hfont_prev = SelectObject(hdc, hfont);
5496 ok(hfont_prev != NULL, "SelectObject failed\n");
5498 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5499 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5501 header = (TTPOLYGONHEADER*)buf;
5502 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5503 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5504 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5505 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5506 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5507 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5508 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5509 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5511 SelectObject(hdc, hfont_prev);
5512 DeleteObject(hfont);
5513 ReleaseDC(NULL, hdc);
5516 static void test_GetGlyphOutline_metric_clipping(void)
5518 HDC hdc;
5519 LOGFONTA lf;
5520 HFONT hfont, hfont_prev;
5521 GLYPHMETRICS gm;
5522 TEXTMETRICA tm;
5523 TEXTMETRICW tmW;
5524 DWORD ret;
5526 memset(&lf, 0, sizeof(lf));
5527 lf.lfHeight = 72;
5528 lstrcpyA(lf.lfFaceName, "wine_test");
5530 SetLastError(0xdeadbeef);
5531 hfont = CreateFontIndirectA(&lf);
5532 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5534 hdc = GetDC(NULL);
5536 hfont_prev = SelectObject(hdc, hfont);
5537 ok(hfont_prev != NULL, "SelectObject failed\n");
5539 SetLastError(0xdeadbeef);
5540 ret = GetTextMetricsA(hdc, &tm);
5541 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5543 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5544 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5545 "Glyph top(%d) exceeds ascent(%d)\n",
5546 gm.gmptGlyphOrigin.y, tm.tmAscent);
5547 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5548 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5549 "Glyph bottom(%d) exceeds descent(%d)\n",
5550 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5552 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5553 GetTextMetricsW(hdc, &tmW);
5554 todo_wine
5555 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5557 SelectObject(hdc, hfont_prev);
5558 DeleteObject(hfont);
5559 ReleaseDC(NULL, hdc);
5562 static void test_CreateScalableFontResource(void)
5564 char ttf_name[MAX_PATH];
5565 char tmp_path[MAX_PATH];
5566 char fot_name[MAX_PATH];
5567 char *file_part;
5568 DWORD ret;
5569 int i;
5571 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5573 win_skip("AddFontResourceExA is not available on this platform\n");
5574 return;
5577 if (!write_ttf_file("wine_test.ttf", ttf_name))
5579 skip("Failed to create ttf file for testing\n");
5580 return;
5583 trace("created %s\n", ttf_name);
5585 ret = is_truetype_font_installed("wine_test");
5586 ok(!ret, "font wine_test should not be enumerated\n");
5588 ret = GetTempPathA(MAX_PATH, tmp_path);
5589 ok(ret, "GetTempPath() error %d\n", GetLastError());
5590 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5591 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5593 ret = GetFileAttributesA(fot_name);
5594 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5596 SetLastError(0xdeadbeef);
5597 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5598 ok(!ret, "CreateScalableFontResource() should fail\n");
5599 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5601 SetLastError(0xdeadbeef);
5602 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5603 ok(!ret, "CreateScalableFontResource() should fail\n");
5604 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5606 file_part = strrchr(ttf_name, '\\');
5607 SetLastError(0xdeadbeef);
5608 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5609 ok(!ret, "CreateScalableFontResource() should fail\n");
5610 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5612 SetLastError(0xdeadbeef);
5613 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5614 ok(!ret, "CreateScalableFontResource() should fail\n");
5615 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5617 SetLastError(0xdeadbeef);
5618 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5619 ok(!ret, "CreateScalableFontResource() should fail\n");
5620 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5622 ret = DeleteFileA(fot_name);
5623 ok(ret, "DeleteFile() error %d\n", GetLastError());
5625 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5626 ok(!ret, "RemoveFontResourceEx() should fail\n");
5628 /* test public font resource */
5629 SetLastError(0xdeadbeef);
5630 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5631 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5633 ret = is_truetype_font_installed("wine_test");
5634 ok(!ret, "font wine_test should not be enumerated\n");
5636 SetLastError(0xdeadbeef);
5637 ret = pAddFontResourceExA(fot_name, 0, 0);
5638 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5640 ret = is_truetype_font_installed("wine_test");
5641 ok(ret, "font wine_test should be enumerated\n");
5643 test_GetGlyphOutline_empty_contour();
5644 test_GetGlyphOutline_metric_clipping();
5646 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5647 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5649 SetLastError(0xdeadbeef);
5650 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5651 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5653 ret = is_truetype_font_installed("wine_test");
5654 ok(!ret, "font wine_test should not be enumerated\n");
5656 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5657 ok(!ret, "RemoveFontResourceEx() should fail\n");
5659 /* test refcounting */
5660 for (i = 0; i < 5; i++)
5662 SetLastError(0xdeadbeef);
5663 ret = pAddFontResourceExA(fot_name, 0, 0);
5664 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5666 for (i = 0; i < 5; i++)
5668 SetLastError(0xdeadbeef);
5669 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5670 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5672 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5673 ok(!ret, "RemoveFontResourceEx() should fail\n");
5675 DeleteFileA(fot_name);
5677 /* test hidden font resource */
5678 SetLastError(0xdeadbeef);
5679 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5680 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5682 ret = is_truetype_font_installed("wine_test");
5683 ok(!ret, "font wine_test should not be enumerated\n");
5685 SetLastError(0xdeadbeef);
5686 ret = pAddFontResourceExA(fot_name, 0, 0);
5687 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5689 ret = is_truetype_font_installed("wine_test");
5690 todo_wine
5691 ok(!ret, "font wine_test should not be enumerated\n");
5693 /* XP allows removing a private font added with 0 flags */
5694 SetLastError(0xdeadbeef);
5695 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5696 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5698 ret = is_truetype_font_installed("wine_test");
5699 ok(!ret, "font wine_test should not be enumerated\n");
5701 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5702 ok(!ret, "RemoveFontResourceEx() should fail\n");
5704 DeleteFileA(fot_name);
5705 DeleteFileA(ttf_name);
5708 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5710 LOGFONTA lf;
5711 HFONT hfont, hfont_prev;
5712 HDC hdc;
5713 char facename[100];
5714 DWORD ret;
5715 static const WCHAR str[] = { 0x2025 };
5717 *installed = is_truetype_font_installed(name);
5719 lf.lfHeight = -18;
5720 lf.lfWidth = 0;
5721 lf.lfEscapement = 0;
5722 lf.lfOrientation = 0;
5723 lf.lfWeight = FW_DONTCARE;
5724 lf.lfItalic = 0;
5725 lf.lfUnderline = 0;
5726 lf.lfStrikeOut = 0;
5727 lf.lfCharSet = DEFAULT_CHARSET;
5728 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5729 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5730 lf.lfQuality = DEFAULT_QUALITY;
5731 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5732 strcpy(lf.lfFaceName, name);
5734 hfont = CreateFontIndirectA(&lf);
5735 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5737 hdc = GetDC(NULL);
5739 hfont_prev = SelectObject(hdc, hfont);
5740 ok(hfont_prev != NULL, "SelectObject failed\n");
5742 ret = GetTextFaceA(hdc, sizeof facename, facename);
5743 ok(ret, "GetTextFaceA failed\n");
5744 *selected = !strcmp(facename, name);
5746 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5747 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5748 if (!*selected)
5749 memset(gm, 0, sizeof *gm);
5751 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5752 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5754 SelectObject(hdc, hfont_prev);
5755 DeleteObject(hfont);
5756 ReleaseDC(NULL, hdc);
5759 static void check_vertical_metrics(const char *face)
5761 LOGFONTA lf;
5762 HFONT hfont, hfont_prev;
5763 HDC hdc;
5764 DWORD ret;
5765 GLYPHMETRICS rgm, vgm;
5766 const UINT code = 0x5EAD, height = 1000;
5767 WORD idx;
5768 ABC abc;
5769 OUTLINETEXTMETRICA otm;
5770 USHORT numOfLongVerMetrics;
5772 hdc = GetDC(NULL);
5774 memset(&lf, 0, sizeof(lf));
5775 strcpy(lf.lfFaceName, face);
5776 lf.lfHeight = -height;
5777 lf.lfCharSet = DEFAULT_CHARSET;
5778 lf.lfEscapement = lf.lfOrientation = 900;
5779 hfont = CreateFontIndirectA(&lf);
5780 hfont_prev = SelectObject(hdc, hfont);
5781 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5782 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5783 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5784 ok(ret, "GetCharABCWidthsW failed\n");
5785 DeleteObject(SelectObject(hdc, hfont_prev));
5787 memset(&lf, 0, sizeof(lf));
5788 strcpy(lf.lfFaceName, "@");
5789 strcat(lf.lfFaceName, face);
5790 lf.lfHeight = -height;
5791 lf.lfCharSet = DEFAULT_CHARSET;
5792 hfont = CreateFontIndirectA(&lf);
5793 hfont_prev = SelectObject(hdc, hfont);
5794 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5795 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5797 memset(&otm, 0, sizeof(otm));
5798 otm.otmSize = sizeof(otm);
5799 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5800 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5802 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5803 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5804 int offset;
5805 SHORT topSideBearing;
5807 if (!pGetGlyphIndicesW) {
5808 win_skip("GetGlyphIndices is not available on this platform\n");
5810 else {
5811 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5812 ok(ret != 0, "GetGlyphIndicesW failed\n");
5813 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5814 if (numOfLongVerMetrics > idx)
5815 offset = idx * 2 + 1;
5816 else
5817 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5818 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5819 &topSideBearing, sizeof(SHORT));
5820 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5821 topSideBearing = GET_BE_WORD(topSideBearing);
5822 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5823 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5824 "expected %d, got %d\n",
5825 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5828 else
5830 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5831 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5832 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5835 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
5836 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
5837 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5838 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
5840 DeleteObject(SelectObject(hdc, hfont_prev));
5841 ReleaseDC(NULL, hdc);
5844 static void test_vertical_font(void)
5846 char ttf_name[MAX_PATH];
5847 int num, i;
5848 BOOL ret, installed, selected;
5849 GLYPHMETRICS gm;
5850 WORD hgi, vgi;
5851 const char* face_list[] = {
5852 "@WineTestVertical", /* has vmtx table */
5853 "@Ume Gothic", /* doesn't have vmtx table */
5854 "@MS UI Gothic", /* has vmtx table, available on native */
5857 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
5859 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5860 return;
5863 if (!write_ttf_file("vertical.ttf", ttf_name))
5865 skip("Failed to create ttf file for testing\n");
5866 return;
5869 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
5870 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5872 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
5873 ok(installed, "WineTestVertical is not installed\n");
5874 ok(selected, "WineTestVertical is not selected\n");
5875 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5876 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5877 gm.gmBlackBoxX, gm.gmBlackBoxY);
5879 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
5880 ok(installed, "@WineTestVertical is not installed\n");
5881 ok(selected, "@WineTestVertical is not selected\n");
5882 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
5883 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5884 gm.gmBlackBoxX, gm.gmBlackBoxY);
5886 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
5888 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
5889 const char* face = face_list[i];
5890 if (!is_truetype_font_installed(face)) {
5891 skip("%s is not installed\n", face);
5892 continue;
5894 trace("Testing %s...\n", face);
5895 check_vertical_metrics(&face[1]);
5898 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
5899 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5901 DeleteFileA(ttf_name);
5904 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
5905 DWORD type, LPARAM lParam)
5907 if (lf->lfFaceName[0] == '@') {
5908 return 0;
5910 return 1;
5913 static void test_east_asian_font_selection(void)
5915 HDC hdc;
5916 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
5917 GB2312_CHARSET, CHINESEBIG5_CHARSET };
5918 size_t i;
5920 hdc = GetDC(NULL);
5922 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
5924 LOGFONTA lf;
5925 HFONT hfont;
5926 char face_name[LF_FACESIZE];
5927 int ret;
5929 memset(&lf, 0, sizeof lf);
5930 lf.lfFaceName[0] = '\0';
5931 lf.lfCharSet = charset[i];
5933 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
5935 skip("Vertical font for charset %u is not installed\n", charset[i]);
5936 continue;
5939 hfont = CreateFontIndirectA(&lf);
5940 hfont = SelectObject(hdc, hfont);
5941 memset(face_name, 0, sizeof face_name);
5942 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5943 ok(ret && face_name[0] != '@',
5944 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
5945 DeleteObject(SelectObject(hdc, hfont));
5947 memset(&lf, 0, sizeof lf);
5948 strcpy(lf.lfFaceName, "@");
5949 lf.lfCharSet = charset[i];
5950 hfont = CreateFontIndirectA(&lf);
5951 hfont = SelectObject(hdc, hfont);
5952 memset(face_name, 0, sizeof face_name);
5953 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
5954 ok(ret && face_name[0] == '@',
5955 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
5956 DeleteObject(SelectObject(hdc, hfont));
5958 ReleaseDC(NULL, hdc);
5961 static int get_font_dpi(const LOGFONTA *lf, int *height)
5963 HDC hdc = CreateCompatibleDC(0);
5964 HFONT hfont;
5965 TEXTMETRICA tm;
5966 int ret;
5968 hfont = CreateFontIndirectA(lf);
5969 ok(hfont != 0, "CreateFontIndirect failed\n");
5971 SelectObject(hdc, hfont);
5972 ret = GetTextMetricsA(hdc, &tm);
5973 ok(ret, "GetTextMetrics failed\n");
5974 ret = tm.tmDigitizedAspectX;
5975 if (height) *height = tm.tmHeight;
5977 DeleteDC(hdc);
5978 DeleteObject(hfont);
5980 return ret;
5983 static void test_stock_fonts(void)
5985 static const int font[] =
5987 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
5988 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5990 static const struct test_data
5992 int charset, weight, height, height_pixels, dpi;
5993 const char face_name[LF_FACESIZE];
5994 WORD lang_id;
5995 } td[][12] =
5997 { /* ANSI_FIXED_FONT */
5998 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
5999 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_HEBREW},
6000 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
6001 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
6002 { 0 }
6004 { /* ANSI_VAR_FONT */
6005 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
6006 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
6007 { 0 }
6009 { /* SYSTEM_FONT */
6010 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6011 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6012 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6013 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6014 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6015 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6016 { 0 }
6018 { /* DEVICE_DEFAULT_FONT */
6019 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6020 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6021 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6022 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6023 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6024 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6025 { 0 }
6027 { /* DEFAULT_GUI_FONT */
6028 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6029 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
6030 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
6031 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
6032 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
6033 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
6034 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
6035 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
6036 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
6037 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6038 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6039 { 0 }
6042 int i, j;
6044 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
6046 HFONT hfont;
6047 LOGFONTA lf;
6048 int ret, height;
6050 hfont = GetStockObject(font[i]);
6051 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
6053 ret = GetObjectA(hfont, sizeof(lf), &lf);
6054 if (ret != sizeof(lf))
6056 /* NT4 */
6057 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
6058 continue;
6061 for (j = 0; td[i][j].face_name[0] != 0; j++)
6063 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) ||
6064 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) ||
6065 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name)))
6067 continue;
6070 ret = get_font_dpi(&lf, &height);
6071 if (ret != td[i][j].dpi)
6073 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6074 i, j, lf.lfFaceName, ret, td[i][j].dpi);
6075 continue;
6078 /* FIXME: Remove once Wine is fixed */
6079 if (td[i][j].dpi != 96 &&
6080 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6081 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
6082 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6083 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
6084 todo_wine
6085 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6086 else
6087 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6089 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
6090 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
6091 if (td[i][j].face_name[0] == '?')
6093 /* Wine doesn't have this font, skip this case for now.
6094 Actually, the face name is localized on Windows and varies
6095 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6096 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
6098 else
6100 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);
6102 break;
6107 static void test_max_height(void)
6109 HDC hdc;
6110 LOGFONTA lf;
6111 HFONT hfont, hfont_old;
6112 TEXTMETRICA tm1, tm;
6113 BOOL r;
6114 LONG invalid_height[] = { -65536, -123456, 123456 };
6115 size_t i;
6117 memset(&tm1, 0, sizeof(tm1));
6118 memset(&lf, 0, sizeof(lf));
6119 strcpy(lf.lfFaceName, "Tahoma");
6120 lf.lfHeight = -1;
6122 hdc = GetDC(NULL);
6124 /* get 1 ppem value */
6125 hfont = CreateFontIndirectA(&lf);
6126 hfont_old = SelectObject(hdc, hfont);
6127 r = GetTextMetricsA(hdc, &tm1);
6128 ok(r, "GetTextMetrics failed\n");
6129 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6130 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6131 DeleteObject(SelectObject(hdc, hfont_old));
6133 /* test the largest value */
6134 lf.lfHeight = -((1 << 16) - 1);
6135 hfont = CreateFontIndirectA(&lf);
6136 hfont_old = SelectObject(hdc, hfont);
6137 memset(&tm, 0, sizeof(tm));
6138 r = GetTextMetricsA(hdc, &tm);
6139 ok(r, "GetTextMetrics failed\n");
6140 ok(tm.tmHeight > tm1.tmHeight,
6141 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6142 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
6143 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6144 DeleteObject(SelectObject(hdc, hfont_old));
6146 /* test an invalid value */
6147 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
6148 lf.lfHeight = invalid_height[i];
6149 hfont = CreateFontIndirectA(&lf);
6150 hfont_old = SelectObject(hdc, hfont);
6151 memset(&tm, 0, sizeof(tm));
6152 r = GetTextMetricsA(hdc, &tm);
6153 ok(r, "GetTextMetrics failed\n");
6154 ok(tm.tmHeight == tm1.tmHeight,
6155 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6156 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
6157 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6158 DeleteObject(SelectObject(hdc, hfont_old));
6161 ReleaseDC(NULL, hdc);
6162 return;
6165 static void test_vertical_order(void)
6167 struct enum_font_data efd;
6168 LOGFONTA lf;
6169 HDC hdc;
6170 int i, j;
6172 hdc = CreateCompatibleDC(0);
6173 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6175 memset(&lf, 0, sizeof(lf));
6176 lf.lfCharSet = DEFAULT_CHARSET;
6177 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6178 lf.lfHeight = 16;
6179 lf.lfWidth = 16;
6180 lf.lfQuality = DEFAULT_QUALITY;
6181 lf.lfItalic = FALSE;
6182 lf.lfWeight = FW_DONTCARE;
6183 efd.total = 0;
6184 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
6185 for (i = 0; i < efd.total; i++)
6187 if (efd.lf[i].lfFaceName[0] != '@') continue;
6188 for (j = 0; j < efd.total; j++)
6190 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
6192 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
6193 break;
6197 DeleteDC( hdc );
6200 static void test_GetCharWidth32(void)
6202 BOOL ret;
6203 HDC hdc;
6204 LOGFONTA lf;
6205 HFONT hfont;
6206 INT bufferA;
6207 INT bufferW;
6208 HWND hwnd;
6210 if (!pGetCharWidth32A || !pGetCharWidth32W)
6212 win_skip("GetCharWidth32A/W not available on this platform\n");
6213 return;
6216 memset(&lf, 0, sizeof(lf));
6217 strcpy(lf.lfFaceName, "System");
6218 lf.lfHeight = 20;
6220 hfont = CreateFontIndirectA(&lf);
6221 hdc = GetDC(0);
6222 hfont = SelectObject(hdc, hfont);
6224 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6225 ok(ret, "GetCharWidth32W should have succeeded\n");
6226 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
6227 ok(ret, "GetCharWidth32A should have succeeded\n");
6228 ok (bufferA == bufferW, "Widths should be the same\n");
6229 ok (bufferA > 0," Width should be greater than zero\n");
6231 hfont = SelectObject(hdc, hfont);
6232 DeleteObject(hfont);
6233 ReleaseDC(NULL, hdc);
6235 memset(&lf, 0, sizeof(lf));
6236 strcpy(lf.lfFaceName, "Tahoma");
6237 lf.lfHeight = 20;
6239 hfont = CreateFontIndirectA(&lf);
6240 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
6241 0, 0, 0, NULL);
6242 hdc = GetDC(hwnd);
6243 SetMapMode( hdc, MM_ANISOTROPIC );
6244 SelectObject(hdc, hfont);
6246 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6247 ok(ret, "GetCharWidth32W should have succeeded\n");
6248 ok (bufferW > 0," Width should be greater than zero\n");
6249 SetWindowExtEx(hdc, -1,-1,NULL);
6250 SetGraphicsMode(hdc, GM_COMPATIBLE);
6251 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6252 ok(ret, "GetCharWidth32W should have succeeded\n");
6253 ok (bufferW > 0," Width should be greater than zero\n");
6254 SetGraphicsMode(hdc, GM_ADVANCED);
6255 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6256 ok(ret, "GetCharWidth32W should have succeeded\n");
6257 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6258 SetWindowExtEx(hdc, 1,1,NULL);
6259 SetGraphicsMode(hdc, GM_COMPATIBLE);
6260 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6261 ok(ret, "GetCharWidth32W should have succeeded\n");
6262 ok (bufferW > 0," Width should be greater than zero\n");
6263 SetGraphicsMode(hdc, GM_ADVANCED);
6264 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6265 ok(ret, "GetCharWidth32W should have succeeded\n");
6266 ok (bufferW > 0," Width should be greater than zero\n");
6268 ReleaseDC(hwnd, hdc);
6269 DestroyWindow(hwnd);
6271 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
6272 0, 0, 0, NULL);
6273 hdc = GetDC(hwnd);
6274 SetMapMode( hdc, MM_ANISOTROPIC );
6275 SelectObject(hdc, hfont);
6277 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6278 ok(ret, "GetCharWidth32W should have succeeded\n");
6279 ok (bufferW > 0," Width should be greater than zero\n");
6280 SetWindowExtEx(hdc, -1,-1,NULL);
6281 SetGraphicsMode(hdc, GM_COMPATIBLE);
6282 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6283 ok(ret, "GetCharWidth32W should have succeeded\n");
6284 ok (bufferW > 0," Width should be greater than zero\n");
6285 SetGraphicsMode(hdc, GM_ADVANCED);
6286 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6287 ok(ret, "GetCharWidth32W should have succeeded\n");
6288 ok (bufferW > 0," Width should be greater than zero\n");
6289 SetWindowExtEx(hdc, 1,1,NULL);
6290 SetGraphicsMode(hdc, GM_COMPATIBLE);
6291 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6292 ok(ret, "GetCharWidth32W should have succeeded\n");
6293 ok (bufferW > 0," Width should be greater than zero\n");
6294 SetGraphicsMode(hdc, GM_ADVANCED);
6295 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6296 ok(ret, "GetCharWidth32W should have succeeded\n");
6297 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6299 ReleaseDC(hwnd, hdc);
6300 DestroyWindow(hwnd);
6301 DeleteObject(hfont);
6304 static void test_fake_bold_font(void)
6306 HDC hdc;
6307 HFONT hfont, hfont_old;
6308 LOGFONTA lf;
6309 BOOL ret;
6310 TEXTMETRICA tm[2];
6311 ABC abc[2];
6312 INT w[2];
6314 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
6315 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6316 return;
6319 /* Test outline font */
6320 memset(&lf, 0, sizeof(lf));
6321 strcpy(lf.lfFaceName, "Wingdings");
6322 lf.lfWeight = FW_NORMAL;
6323 lf.lfCharSet = SYMBOL_CHARSET;
6324 hfont = CreateFontIndirectA(&lf);
6326 hdc = GetDC(NULL);
6327 hfont_old = SelectObject(hdc, hfont);
6329 /* base metrics */
6330 ret = GetTextMetricsA(hdc, &tm[0]);
6331 ok(ret, "got %d\n", ret);
6332 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[0]);
6333 ok(ret, "got %d\n", ret);
6335 lf.lfWeight = FW_BOLD;
6336 hfont = CreateFontIndirectA(&lf);
6337 DeleteObject(SelectObject(hdc, hfont));
6339 /* bold metrics */
6340 ret = GetTextMetricsA(hdc, &tm[1]);
6341 ok(ret, "got %d\n", ret);
6342 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &abc[1]);
6343 ok(ret, "got %d\n", ret);
6345 DeleteObject(SelectObject(hdc, hfont_old));
6346 ReleaseDC(NULL, hdc);
6348 /* compare results (outline) */
6349 ok(tm[0].tmHeight == tm[1].tmHeight, "expected %d, got %d\n", tm[0].tmHeight, tm[1].tmHeight);
6350 ok(tm[0].tmAscent == tm[1].tmAscent, "expected %d, got %d\n", tm[0].tmAscent, tm[1].tmAscent);
6351 ok(tm[0].tmDescent == tm[1].tmDescent, "expected %d, got %d\n", tm[0].tmDescent, tm[1].tmDescent);
6352 ok((tm[0].tmAveCharWidth + 1) == tm[1].tmAveCharWidth,
6353 "expected %d, got %d\n", tm[0].tmAveCharWidth + 1, tm[1].tmAveCharWidth);
6354 ok((tm[0].tmMaxCharWidth + 1) == tm[1].tmMaxCharWidth,
6355 "expected %d, got %d\n", tm[0].tmMaxCharWidth + 1, tm[1].tmMaxCharWidth);
6356 ok(tm[0].tmOverhang == tm[1].tmOverhang, "expected %d, got %d\n", tm[0].tmOverhang, tm[1].tmOverhang);
6357 w[0] = abc[0].abcA + abc[0].abcB + abc[0].abcC;
6358 w[1] = abc[1].abcA + abc[1].abcB + abc[1].abcC;
6359 ok((w[0] + 1) == w[1], "expected %d, got %d\n", w[0] + 1, w[1]);
6363 static void test_bitmap_font_glyph_index(void)
6365 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
6366 const struct {
6367 LPCSTR face;
6368 BYTE charset;
6369 } bitmap_font_list[] = {
6370 { "Courier", ANSI_CHARSET },
6371 { "Small Fonts", ANSI_CHARSET },
6372 { "Fixedsys", DEFAULT_CHARSET },
6373 { "System", DEFAULT_CHARSET }
6375 HDC hdc;
6376 LOGFONTA lf;
6377 HFONT hFont;
6378 CHAR facename[LF_FACESIZE];
6379 BITMAPINFO bmi;
6380 HBITMAP hBmp[2];
6381 void *pixels[2];
6382 int i, j;
6383 DWORD ret;
6384 BITMAP bmp;
6385 TEXTMETRICA tm;
6386 CHARSETINFO ci;
6387 BYTE chr = '\xA9';
6389 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
6390 win_skip("GetGlyphIndices is unavailable\n");
6391 return;
6394 hdc = CreateCompatibleDC(0);
6395 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6397 memset(&bmi, 0, sizeof(bmi));
6398 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
6399 bmi.bmiHeader.biBitCount = 32;
6400 bmi.bmiHeader.biPlanes = 1;
6401 bmi.bmiHeader.biWidth = 128;
6402 bmi.bmiHeader.biHeight = 32;
6403 bmi.bmiHeader.biCompression = BI_RGB;
6405 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
6406 memset(&lf, 0, sizeof(lf));
6407 lf.lfCharSet = bitmap_font_list[i].charset;
6408 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
6409 hFont = CreateFontIndirectA(&lf);
6410 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
6411 hFont = SelectObject(hdc, hFont);
6412 ret = GetTextMetricsA(hdc, &tm);
6413 ok(ret, "GetTextMetric failed\n");
6414 ret = GetTextFaceA(hdc, sizeof(facename), facename);
6415 ok(ret, "GetTextFace failed\n");
6416 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
6417 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
6418 continue;
6420 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
6421 skip("expected %s, got %s\n", lf.lfFaceName, facename);
6422 continue;
6425 for (j = 0; j < 2; j++) {
6426 HBITMAP hBmpPrev;
6427 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
6428 ok(hBmp[j] != NULL, "Can't create DIB\n");
6429 hBmpPrev = SelectObject(hdc, hBmp[j]);
6430 switch (j) {
6431 case 0:
6432 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
6433 break;
6434 case 1:
6436 int len = lstrlenW(text);
6437 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
6438 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
6439 ok(ret, "GetGlyphIndices failed\n");
6440 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
6441 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
6442 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
6443 HeapFree(GetProcessHeap(), 0, indices);
6444 break;
6447 ok(ret, "ExtTextOutW failed\n");
6448 SelectObject(hdc, hBmpPrev);
6451 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
6452 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6453 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6455 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
6456 if (!ret) {
6457 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6458 goto next;
6460 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
6461 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
6462 goto next;
6465 for (j = 0; j < 2; j++) {
6466 HBITMAP hBmpPrev;
6467 WORD code;
6468 hBmpPrev = SelectObject(hdc, hBmp[j]);
6469 switch (j) {
6470 case 0:
6471 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6472 break;
6473 case 1:
6474 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6475 ok(ret, "GetGlyphIndices failed\n");
6476 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6477 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6478 break;
6480 ok(ret, "ExtTextOutA failed\n");
6481 SelectObject(hdc, hBmpPrev);
6484 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6485 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6486 next:
6487 for (j = 0; j < 2; j++)
6488 DeleteObject(hBmp[j]);
6489 hFont = SelectObject(hdc, hFont);
6490 DeleteObject(hFont);
6493 DeleteDC(hdc);
6496 START_TEST(font)
6498 init();
6500 test_stock_fonts();
6501 test_logfont();
6502 test_bitmap_font();
6503 test_outline_font();
6504 test_bitmap_font_metrics();
6505 test_GdiGetCharDimensions();
6506 test_GetCharABCWidths();
6507 test_text_extents();
6508 test_GetGlyphIndices();
6509 test_GetKerningPairs();
6510 test_GetOutlineTextMetrics();
6511 test_SetTextJustification();
6512 test_font_charset();
6513 test_GdiGetCodePage();
6514 test_GetFontUnicodeRanges();
6515 test_nonexistent_font();
6516 test_orientation();
6517 test_height_selection();
6518 test_AddFontMemResource();
6519 test_EnumFonts();
6520 test_EnumFonts_subst();
6522 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6523 * I'd like to avoid them in this test.
6525 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6526 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6527 if (is_truetype_font_installed("Arial Black") &&
6528 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6530 test_EnumFontFamilies("", ANSI_CHARSET);
6531 test_EnumFontFamilies("", SYMBOL_CHARSET);
6532 test_EnumFontFamilies("", DEFAULT_CHARSET);
6534 else
6535 skip("Arial Black or Symbol/Wingdings is not installed\n");
6536 test_EnumFontFamiliesEx_default_charset();
6537 test_GetTextMetrics();
6538 test_RealizationInfo();
6539 test_GetTextFace();
6540 test_GetGlyphOutline();
6541 test_GetTextMetrics2("Tahoma", -11);
6542 test_GetTextMetrics2("Tahoma", -55);
6543 test_GetTextMetrics2("Tahoma", -110);
6544 test_GetTextMetrics2("Arial", -11);
6545 test_GetTextMetrics2("Arial", -55);
6546 test_GetTextMetrics2("Arial", -110);
6547 test_CreateFontIndirect();
6548 test_CreateFontIndirectEx();
6549 test_oemcharset();
6550 test_fullname();
6551 test_fullname2();
6552 test_east_asian_font_selection();
6553 test_max_height();
6554 test_vertical_order();
6555 test_GetCharWidth32();
6556 test_fake_bold_font();
6557 test_bitmap_font_glyph_index();
6559 /* These tests should be last test until RemoveFontResource
6560 * is properly implemented.
6562 test_vertical_font();
6563 test_CreateScalableFontResource();