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