win32u: Choose a smaller ppem to avoid exceeding the requested font height.
[wine.git] / dlls / gdi32 / tests / font.c
blob12a5bff59694be6ce0df145edb5eba81208ece13
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 <stdio.h>
24 #include <assert.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
32 #include "wine/heap.h"
33 #include "wine/test.h"
35 static inline BOOL match_off_by_n(int a, int b, unsigned int n)
37 return abs(a - b) <= n;
39 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
40 #define near_match(a, b) match_off_by_n((a), (b), 6)
41 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
43 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
44 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
45 static BOOL (WINAPI *pGetCharWidthInfo)(HDC hdc, void *);
46 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
47 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
48 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, SIZE_T, SIZE_T *);
49 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, UINT64, void *, DWORD);
51 static HMODULE hgdi32 = 0;
52 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
53 static WORD system_lang_id;
55 #ifdef WORDS_BIGENDIAN
56 #define GET_BE_WORD(x) (x)
57 #define GET_BE_DWORD(x) (x)
58 #else
59 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
60 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
61 #endif
63 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
64 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
65 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
66 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
67 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
68 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
70 static void init(void)
72 hgdi32 = GetModuleHandleA("gdi32.dll");
74 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
75 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
76 pGetCharWidthInfo = (void *)GetProcAddress(hgdi32, "GetCharWidthInfo");
77 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
78 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
79 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
80 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
82 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
85 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
87 if (type != TRUETYPE_FONTTYPE) return 1;
89 return 0;
92 static BOOL is_truetype_font_installed(const char *name)
94 HDC hdc = GetDC(0);
95 BOOL ret = FALSE;
97 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
98 ret = TRUE;
100 ReleaseDC(0, hdc);
101 return ret;
104 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
106 return 0;
109 static BOOL is_font_installed(const char *name)
111 HDC hdc = GetDC(0);
112 BOOL ret = FALSE;
114 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
115 ret = TRUE;
117 ReleaseDC(0, hdc);
118 return ret;
121 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
123 HRSRC rsrc;
124 void *rsrc_data;
126 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
127 if (!rsrc) return NULL;
129 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
130 if (!rsrc_data) return NULL;
132 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
133 if (!*rsrc_size) return NULL;
135 return rsrc_data;
138 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
140 char tmp_path[MAX_PATH];
141 HANDLE hfile;
142 BOOL ret;
144 GetTempPathA(MAX_PATH, tmp_path);
145 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
147 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
148 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
150 ret = WriteFile(hfile, data, *size, size, NULL);
152 CloseHandle(hfile);
153 return ret;
156 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
158 void *rsrc_data;
159 DWORD rsrc_size;
161 rsrc_data = get_res_data( fontname, &rsrc_size );
162 if (!rsrc_data) return FALSE;
164 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
167 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
169 LOGFONTA getobj_lf;
170 int ret;
172 if (!hfont)
173 return;
175 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
176 ok(ret == sizeof(LOGFONTA), "%s: GetObject returned %d\n", test, ret);
177 ok(lf->lfHeight == getobj_lf.lfHeight, "lfHeight: expect %08lx got %08lx\n", lf->lfHeight, getobj_lf.lfHeight);
178 ok(lf->lfWidth == getobj_lf.lfWidth, "lfWidth: expect %08lx got %08lx\n", lf->lfWidth, getobj_lf.lfWidth);
179 ok(lf->lfEscapement == getobj_lf.lfEscapement, "lfEscapement: expect %08lx got %08lx\n", lf->lfEscapement, getobj_lf.lfEscapement);
180 ok(lf->lfOrientation == getobj_lf.lfOrientation, "lfOrientation: expect %08lx got %08lx\n", lf->lfOrientation, getobj_lf.lfOrientation);
181 ok(lf->lfWeight == getobj_lf.lfWeight, "lfWeight: expect %08lx got %08lx\n", lf->lfWeight, getobj_lf.lfWeight);
182 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
183 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
184 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
185 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
186 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
187 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
188 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
189 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
190 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName), "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
193 static HFONT create_font(const char* test, const LOGFONTA* lf)
195 HFONT hfont = CreateFontIndirectA(lf);
196 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
197 if (hfont)
198 check_font(test, lf, hfont);
199 return hfont;
202 static void test_logfont(void)
204 LOGFONTA lf;
205 HFONT hfont;
207 memset(&lf, 0, sizeof lf);
209 lf.lfCharSet = ANSI_CHARSET;
210 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
211 lf.lfWeight = FW_DONTCARE;
212 lf.lfHeight = 16;
213 lf.lfWidth = 16;
214 lf.lfQuality = DEFAULT_QUALITY;
216 lstrcpyA(lf.lfFaceName, "Arial");
217 hfont = create_font("Arial", &lf);
218 DeleteObject(hfont);
220 memset(&lf, 'A', sizeof(lf));
221 hfont = CreateFontIndirectA(&lf);
222 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
224 lf.lfFaceName[LF_FACESIZE - 1] = 0;
225 check_font("AAA...", &lf, hfont);
226 DeleteObject(hfont);
229 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
231 if (type & RASTER_FONTTYPE)
233 LOGFONTA *lf = (LOGFONTA *)lParam;
234 *lf = *elf;
235 return 0; /* stop enumeration */
238 return 1; /* continue enumeration */
241 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
243 ok(tm->tmHeight == otm->tmHeight, "tmHeight %ld != %ld\n", tm->tmHeight, otm->tmHeight);
244 ok(tm->tmAscent == otm->tmAscent, "tmAscent %ld != %ld\n", tm->tmAscent, otm->tmAscent);
245 ok(tm->tmDescent == otm->tmDescent, "tmDescent %ld != %ld\n", tm->tmDescent, otm->tmDescent);
246 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %ld != %ld\n", tm->tmInternalLeading, otm->tmInternalLeading);
247 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %ld != %ld\n", tm->tmExternalLeading, otm->tmExternalLeading);
248 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %ld != %ld\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
249 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %ld != %ld\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
250 ok(tm->tmWeight == otm->tmWeight, "tmWeight %ld != %ld\n", tm->tmWeight, otm->tmWeight);
251 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %ld != %ld\n", tm->tmOverhang, otm->tmOverhang);
252 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %ld != %ld\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
253 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %ld != %ld\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
254 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
255 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
256 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
257 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
258 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
259 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
260 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
261 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
262 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
265 static void test_font_metrics(const char *context,
266 HDC hdc, HFONT hfont, LONG lfHeight,
267 LONG lfWidth, const char *test_str,
268 INT test_str_len, const TEXTMETRICA *tm_orig,
269 const SIZE *size_orig, INT width_of_A_orig,
270 INT scale_x, INT scale_y)
272 LOGFONTA lf;
273 OUTLINETEXTMETRICA otm;
274 TEXTMETRICA tm;
275 SIZE size;
276 INT width_of_A, cx, cy;
277 UINT ret;
279 if (!hfont)
280 return;
282 if (context) winetest_push_context("%s", context);
283 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
285 GetObjectA(hfont, sizeof(lf), &lf);
287 if (GetOutlineTextMetricsA(hdc, 0, NULL))
289 otm.otmSize = sizeof(otm) / 2;
290 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
291 ok(ret == sizeof(otm)/2, "expected sizeof(otm)/2, got %u\n", ret);
293 memset(&otm, 0x1, sizeof(otm));
294 otm.otmSize = sizeof(otm);
295 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
296 ok(ret == sizeof(otm), "expected sizeof(otm), got %u\n", ret);
298 memset(&tm, 0x2, sizeof(tm));
299 ret = GetTextMetricsA(hdc, &tm);
300 ok(ret, "GetTextMetricsA failed\n");
301 /* the structure size is aligned */
302 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
304 ok(0, "tm != otm\n");
305 compare_tm(&tm, &otm.otmTextMetrics);
308 tm = otm.otmTextMetrics;
309 if (0) /* these metrics are scaled too, but with rounding errors */
311 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %ld\n", otm.otmAscent, tm.tmAscent);
312 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %ld\n", otm.otmDescent, -tm.tmDescent);
314 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %ld\n", otm.otmMacAscent, tm.tmAscent);
315 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
316 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
317 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
318 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %ld\n", otm.otmMacDescent, -tm.tmDescent);
319 if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)
320 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
322 else
324 ret = GetTextMetricsA(hdc, &tm);
325 ok(ret, "GetTextMetricsA failed\n");
328 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
329 cy = tm.tmHeight / tm_orig->tmHeight;
330 ok(cx == scale_x && cy == scale_y, "height %ld: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
331 lfHeight, scale_x, scale_y, cx, cy);
332 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %ld != %ld\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
333 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %ld != %ld\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
334 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %ld != %ld\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
335 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %ld != %ld\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
336 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %ld != %ld\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
338 ok(lf.lfHeight == lfHeight, "lfHeight %ld != %ld\n", lf.lfHeight, lfHeight);
339 if (lf.lfHeight)
341 if (lf.lfWidth)
342 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %ld != tm %ld\n", lf.lfWidth, tm.tmAveCharWidth);
344 else
345 ok(lf.lfWidth == lfWidth, "lfWidth %ld != %ld\n", lf.lfWidth, lfWidth);
347 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
349 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %ld != %ld\n", size.cx, size_orig->cx * scale_x);
350 ok(size.cy == size_orig->cy * scale_y, "cy %ld != %ld\n", size.cy, size_orig->cy * scale_y);
352 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
354 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);
355 if (context) winetest_pop_context();
358 /* Test how GDI scales bitmap font metrics */
359 static void test_bitmap_font(void)
361 static const char test_str[11] = "Test String";
362 HDC hdc;
363 LOGFONTA bitmap_lf;
364 HFONT hfont, old_hfont;
365 TEXTMETRICA tm_orig;
366 SIZE size_orig;
367 INT ret, i, width_orig, height_orig, scale, lfWidth;
369 hdc = CreateCompatibleDC(0);
371 /* "System" has only 1 pixel size defined, otherwise the test breaks */
372 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
373 if (ret)
375 ReleaseDC(0, hdc);
376 skip("no bitmap fonts were found, skipping the test\n");
377 return;
380 trace("found bitmap font %s, height %ld\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
382 height_orig = bitmap_lf.lfHeight;
383 lfWidth = bitmap_lf.lfWidth;
385 hfont = create_font("bitmap", &bitmap_lf);
386 old_hfont = SelectObject(hdc, hfont);
387 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
388 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
389 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
390 SelectObject(hdc, old_hfont);
391 DeleteObject(hfont);
393 bitmap_lf.lfHeight = 0;
394 bitmap_lf.lfWidth = 4;
395 hfont = create_font("bitmap", &bitmap_lf);
396 old_hfont = SelectObject(hdc, hfont);
397 test_font_metrics("bitmap", hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
398 SelectObject(hdc, old_hfont);
399 DeleteObject(hfont);
401 bitmap_lf.lfHeight = height_orig;
402 bitmap_lf.lfWidth = lfWidth;
404 /* test fractional scaling */
405 for (i = 1; i <= height_orig * 6; i++)
407 INT nearest_height;
409 bitmap_lf.lfHeight = i;
410 hfont = create_font("fractional", &bitmap_lf);
411 scale = (i + height_orig - 1) / height_orig;
412 nearest_height = scale * height_orig;
413 /* Only jump to the next height if the difference <= 25% original height */
414 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
415 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
416 so we'll not test this particular height. */
417 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
418 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
419 old_hfont = SelectObject(hdc, hfont);
420 winetest_push_context("height %i", i);
421 test_font_metrics(NULL, hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
422 winetest_pop_context();
423 SelectObject(hdc, old_hfont);
424 DeleteObject(hfont);
427 /* test integer scaling 3x2 */
428 bitmap_lf.lfHeight = height_orig * 2;
429 bitmap_lf.lfWidth *= 3;
430 hfont = create_font("3x2", &bitmap_lf);
431 old_hfont = SelectObject(hdc, hfont);
432 test_font_metrics("bitmap 3x2", hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
433 SelectObject(hdc, old_hfont);
434 DeleteObject(hfont);
436 /* test integer scaling 3x3 */
437 bitmap_lf.lfHeight = height_orig * 3;
438 bitmap_lf.lfWidth = 0;
439 hfont = create_font("3x3", &bitmap_lf);
440 old_hfont = SelectObject(hdc, hfont);
441 test_font_metrics("bitmap 3x3", hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
442 SelectObject(hdc, old_hfont);
443 DeleteObject(hfont);
445 DeleteDC(hdc);
448 /* Test how GDI scales outline font metrics */
449 static void test_outline_font(void)
451 static const char test_str[11] = "Test String";
452 HDC hdc, hdc_2;
453 LOGFONTA lf;
454 HFONT hfont, old_hfont, old_hfont_2;
455 OUTLINETEXTMETRICA otm;
456 SIZE size_orig;
457 INT width_orig, height_orig, lfWidth;
458 XFORM xform;
459 GLYPHMETRICS gm;
460 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
461 POINT pt;
462 INT ret;
464 if (!is_truetype_font_installed("Arial"))
466 skip("Arial is not installed\n");
467 return;
470 hdc = CreateCompatibleDC(0);
472 memset(&lf, 0, sizeof(lf));
473 strcpy(lf.lfFaceName, "Arial");
474 lf.lfHeight = 72;
475 hfont = create_font("outline", &lf);
476 old_hfont = SelectObject(hdc, hfont);
477 otm.otmSize = sizeof(otm);
478 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
479 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
480 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
482 test_font_metrics("outline", hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
483 SelectObject(hdc, old_hfont);
484 DeleteObject(hfont);
486 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
487 lf.lfHeight = otm.otmEMSquare;
488 lf.lfHeight = -lf.lfHeight;
489 hfont = create_font("outline", &lf);
490 old_hfont = SelectObject(hdc, hfont);
491 otm.otmSize = sizeof(otm);
492 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
493 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
494 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
495 SelectObject(hdc, old_hfont);
496 DeleteObject(hfont);
498 height_orig = otm.otmTextMetrics.tmHeight;
499 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
501 /* test integer scaling 3x2 */
502 lf.lfHeight = height_orig * 2;
503 lf.lfWidth = lfWidth * 3;
504 hfont = create_font("3x2", &lf);
505 old_hfont = SelectObject(hdc, hfont);
506 test_font_metrics("outline 3x2", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
507 SelectObject(hdc, old_hfont);
508 DeleteObject(hfont);
510 /* test integer scaling 3x3 */
511 lf.lfHeight = height_orig * 3;
512 lf.lfWidth = lfWidth * 3;
513 hfont = create_font("3x3", &lf);
514 old_hfont = SelectObject(hdc, hfont);
515 test_font_metrics("outline 3x3", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
516 SelectObject(hdc, old_hfont);
517 DeleteObject(hfont);
519 /* test integer scaling 1x1 */
520 lf.lfHeight = height_orig * 1;
521 lf.lfWidth = lfWidth * 1;
522 hfont = create_font("1x1", &lf);
523 old_hfont = SelectObject(hdc, hfont);
524 test_font_metrics("outline 1x1", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 SelectObject(hdc, old_hfont);
526 DeleteObject(hfont);
528 /* test integer scaling 1x1 */
529 lf.lfHeight = height_orig;
530 lf.lfWidth = 0;
531 hfont = create_font("1x1", &lf);
532 old_hfont = SelectObject(hdc, hfont);
533 test_font_metrics("outline 1x0", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
535 /* with an identity matrix */
536 memset(&gm, 0, sizeof(gm));
537 SetLastError(0xdeadbeef);
538 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
539 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
540 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
541 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
542 /* with a custom matrix */
543 memset(&gm, 0, sizeof(gm));
544 SetLastError(0xdeadbeef);
545 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
546 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
547 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
548 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
550 /* Test that changing the DC transformation affects only the font
551 * selected on this DC and doesn't affect the same font selected on
552 * another DC.
554 hdc_2 = CreateCompatibleDC(0);
555 old_hfont_2 = SelectObject(hdc_2, hfont);
556 test_font_metrics("dc2.base", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
558 SetMapMode(hdc, MM_ANISOTROPIC);
560 /* font metrics on another DC should be unchanged */
561 test_font_metrics("dc2.aniso", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
563 /* test restrictions of compatibility mode GM_COMPATIBLE */
564 /* part 1: rescaling only X should not change font scaling on screen.
565 So compressing the X axis by 2 is not done, and this
566 appears as X scaling of 2 that no one requested. */
567 SetWindowExtEx(hdc, 100, 100, NULL);
568 SetViewportExtEx(hdc, 50, 100, NULL);
569 test_font_metrics("xscaling", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
570 /* font metrics on another DC should be unchanged */
571 test_font_metrics("dc2.xscaling", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
573 /* part 2: rescaling only Y should change font scaling.
574 As also X is scaled by a factor of 2, but this is not
575 requested by the DC transformation, we get a scaling factor
576 of 2 in the X coordinate. */
577 SetViewportExtEx(hdc, 100, 200, NULL);
578 test_font_metrics("yscaling", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
579 /* font metrics on another DC should be unchanged */
580 test_font_metrics("dc2.yscaling", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
582 /* restore scaling */
583 SetMapMode(hdc, MM_TEXT);
585 /* font metrics on another DC should be unchanged */
586 test_font_metrics("dc2.text", hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
588 SelectObject(hdc_2, old_hfont_2);
589 DeleteDC(hdc_2);
591 if (!SetGraphicsMode(hdc, GM_ADVANCED))
593 SelectObject(hdc, old_hfont);
594 DeleteObject(hfont);
595 DeleteDC(hdc);
596 skip("GM_ADVANCED is not supported on this platform\n");
597 return;
600 xform.eM11 = 20.0f;
601 xform.eM12 = 0.0f;
602 xform.eM21 = 0.0f;
603 xform.eM22 = 20.0f;
604 xform.eDx = 0.0f;
605 xform.eDy = 0.0f;
607 SetLastError(0xdeadbeef);
608 ret = SetWorldTransform(hdc, &xform);
609 ok(ret, "SetWorldTransform error %lu\n", GetLastError());
611 test_font_metrics("xform", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
613 /* with an identity matrix */
614 memset(&gm, 0, sizeof(gm));
615 SetLastError(0xdeadbeef);
616 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
617 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
618 pt.x = width_orig; pt.y = 0;
619 LPtoDP(hdc, &pt, 1);
620 ok(gm.gmCellIncX == pt.x, "incX %d != %ld\n", gm.gmCellIncX, pt.x);
621 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
622 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
623 /* with a custom matrix */
624 memset(&gm, 0, sizeof(gm));
625 SetLastError(0xdeadbeef);
626 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
627 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
628 pt.x = width_orig; pt.y = 0;
629 LPtoDP(hdc, &pt, 1);
630 ok(gm.gmCellIncX == pt.x/2, "incX %d != %ld\n", gm.gmCellIncX, pt.x/2);
631 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
632 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
634 SetLastError(0xdeadbeef);
635 ret = SetMapMode(hdc, MM_LOMETRIC);
636 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %lu\n", ret, GetLastError());
638 test_font_metrics("lometric", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
640 /* with an identity matrix */
641 memset(&gm, 0, sizeof(gm));
642 SetLastError(0xdeadbeef);
643 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
644 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
645 pt.x = width_orig; pt.y = 0;
646 LPtoDP(hdc, &pt, 1);
647 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %ld\n", gm.gmCellIncX, pt.x);
648 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
649 /* with a custom matrix */
650 memset(&gm, 0, sizeof(gm));
651 SetLastError(0xdeadbeef);
652 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
653 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
654 pt.x = width_orig; pt.y = 0;
655 LPtoDP(hdc, &pt, 1);
656 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %ld\n", gm.gmCellIncX, (pt.x + 1)/2);
657 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
659 SetLastError(0xdeadbeef);
660 ret = SetMapMode(hdc, MM_TEXT);
661 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %lu\n", ret, GetLastError());
663 test_font_metrics("text", hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
665 /* with an identity matrix */
666 memset(&gm, 0, sizeof(gm));
667 SetLastError(0xdeadbeef);
668 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
669 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
670 pt.x = width_orig; pt.y = 0;
671 LPtoDP(hdc, &pt, 1);
672 ok(gm.gmCellIncX == pt.x, "incX %d != %ld\n", gm.gmCellIncX, pt.x);
673 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
674 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
675 /* with a custom matrix */
676 memset(&gm, 0, sizeof(gm));
677 SetLastError(0xdeadbeef);
678 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
679 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %ld\n", GetLastError());
680 pt.x = width_orig; pt.y = 0;
681 LPtoDP(hdc, &pt, 1);
682 ok(gm.gmCellIncX == pt.x/2, "incX %d != %ld\n", gm.gmCellIncX, pt.x/2);
683 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
684 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
686 SelectObject(hdc, old_hfont);
687 DeleteObject(hfont);
688 DeleteDC(hdc);
691 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
693 LOGFONTA *lf = (LOGFONTA *)lParam;
695 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
697 *lf = *elf;
698 return 0; /* stop enumeration */
700 return 1; /* continue enumeration */
703 static BOOL is_CJK(void)
705 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
708 #define FH_SCALE 0x80000000
709 static void test_bitmap_font_metrics(void)
711 static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
712 static const struct font_data
714 const char face_name[LF_FACESIZE];
715 int weight, height, ascent, descent, int_leading, ext_leading;
716 int ave_char_width, max_char_width, dpi;
717 BYTE first_char, last_char, def_char, break_char;
718 DWORD ansi_bitfield;
719 const WORD *skip_lang_id;
720 int scaled_height;
721 } fd[] =
723 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
724 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
725 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
726 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
727 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
728 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
729 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 13 },
730 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
731 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl, 16 },
732 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
734 { "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 },
735 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
736 { "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 },
737 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
738 { "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 },
739 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
740 { "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 },
741 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
742 { "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 },
743 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
745 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
746 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
747 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
748 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
749 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
750 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
751 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
752 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
753 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
754 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
755 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
756 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
757 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
758 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
759 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
760 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
762 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
763 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
764 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
765 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
766 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
767 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
768 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
769 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
770 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
771 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
772 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
773 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
775 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
776 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
777 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
778 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
779 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
780 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
781 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
782 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
783 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
784 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
785 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
786 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
787 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
788 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
789 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
790 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
791 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
793 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
794 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
795 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
796 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
797 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
798 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
799 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
800 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
801 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
802 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
803 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
805 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
806 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
807 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
809 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
810 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
811 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
813 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
814 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
815 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
817 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
818 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
820 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
821 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
822 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
823 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
824 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
825 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
826 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
827 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
828 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
829 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
830 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
831 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
832 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
833 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
834 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
835 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
836 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
837 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
838 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
839 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
840 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
842 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
843 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
844 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
845 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
846 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
847 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
848 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
849 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
850 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
851 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
852 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
853 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
855 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
856 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
857 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
859 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
861 /* FIXME: add "Terminal" */
863 static const int font_log_pixels[] = { 96, 120 };
864 HDC hdc;
865 LOGFONTA lf;
866 HFONT hfont, old_hfont;
867 TEXTMETRICA tm;
868 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
869 char face_name[LF_FACESIZE];
870 CHARSETINFO csi;
872 trace("system language id %04x\n", system_lang_id);
874 expected_cs = GetACP();
875 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
877 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
878 return;
880 expected_cs = csi.ciCharset;
881 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
883 hdc = CreateCompatibleDC(0);
884 ok(hdc != NULL, "failed to create hdc\n");
886 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
887 GetDeviceCaps(hdc, LOGPIXELSY));
889 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
890 diff = 32768;
891 font_res = 0;
892 for (i = 0; i < ARRAY_SIZE(font_log_pixels); i++)
894 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
895 if (new_diff < diff)
897 diff = new_diff;
898 font_res = font_log_pixels[i];
901 trace("best font resolution is %d\n", font_res);
903 for (i = 0; i < ARRAY_SIZE(fd); i++)
905 int bit, height;
907 memset(&lf, 0, sizeof(lf));
909 height = fd[i].height & ~FH_SCALE;
910 lf.lfHeight = height;
911 strcpy(lf.lfFaceName, fd[i].face_name);
913 for(bit = 0; bit < 32; bit++)
915 GLYPHMETRICS gm;
916 DWORD fs[2];
917 BOOL bRet;
919 fs[0] = 1L << bit;
920 fs[1] = 0;
921 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
922 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
924 lf.lfCharSet = csi.ciCharset;
925 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
926 if (fd[i].height & FH_SCALE)
927 ok(ret, "scaled font height %d should not be enumerated\n", height);
928 else
930 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
932 todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */
933 ok(!ret, "%s height %ld charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
936 if (ret && !(fd[i].height & FH_SCALE))
937 continue;
939 hfont = create_font(lf.lfFaceName, &lf);
940 old_hfont = SelectObject(hdc, hfont);
942 SetLastError(0xdeadbeef);
943 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
944 ok(ret, "GetTextFace error %lu\n", GetLastError());
946 if (strcmp(face_name, fd[i].face_name) != 0)
948 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
949 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
950 SelectObject(hdc, old_hfont);
951 DeleteObject(hfont);
952 continue;
955 memset(&gm, 0, sizeof(gm));
956 SetLastError(0xdeadbeef);
957 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
958 todo_wine
959 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
960 ret = GetLastError();
961 ok(ret == ERROR_CAN_NOT_COMPLETE || ret == 0xdeadbeef /* Win10 */, "Unexpected error %d.\n", ret);
963 bRet = GetTextMetricsA(hdc, &tm);
964 ok(bRet, "GetTextMetrics error %ld\n", GetLastError());
966 SetLastError(0xdeadbeef);
967 ret = GetTextCharset(hdc);
968 if ((is_CJK() || expected_cs == 254) && lf.lfCharSet == ANSI_CHARSET)
969 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
970 else
971 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
973 if(fd[i].dpi == tm.tmDigitizedAspectX)
975 int skipme = 0;
976 if (fd[i].skip_lang_id)
978 int si = 0;
979 skipme = 0;
980 while(!skipme && fd[i].skip_lang_id[si])
981 if (fd[i].skip_lang_id[si++] == system_lang_id)
982 skipme = 1;
984 if (!skipme)
986 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %ld != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
987 if (fd[i].height & FH_SCALE)
988 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %ld != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
989 else
990 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
991 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %ld != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
992 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %ld != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
993 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %ld != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
994 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
995 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %ld != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
996 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
997 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
998 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
999 make default char test fail */
1000 if (tm.tmCharSet == lf.lfCharSet)
1001 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1002 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1003 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);
1005 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1006 that make the max width bigger */
1007 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1008 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %ld != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
1010 else
1011 skip("Skipping font metrics test for system langid 0x%x\n",
1012 system_lang_id);
1014 SelectObject(hdc, old_hfont);
1015 DeleteObject(hfont);
1019 DeleteDC(hdc);
1022 static void test_GdiGetCharDimensions(void)
1024 HDC hdc;
1025 TEXTMETRICW tm;
1026 LONG ret;
1027 SIZE size;
1028 LONG avgwidth, height;
1029 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1031 if (!pGdiGetCharDimensions)
1033 win_skip("GdiGetCharDimensions not available on this platform\n");
1034 return;
1037 hdc = CreateCompatibleDC(NULL);
1039 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1040 avgwidth = ((size.cx / 26) + 1) / 2;
1042 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1043 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
1044 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm.tmHeight, height);
1046 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1047 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
1049 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1050 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
1052 height = 0;
1053 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1054 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
1055 ok(height == size.cy, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size.cy, height);
1057 DeleteDC(hdc);
1060 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1061 const TEXTMETRICA *lpntme,
1062 DWORD FontType, LPARAM lParam)
1064 if (FontType & TRUETYPE_FONTTYPE)
1066 HFONT hfont;
1068 hfont = CreateFontIndirectA(lpelfe);
1069 if (hfont)
1071 *(HFONT *)lParam = hfont;
1072 return 0;
1076 return 1;
1079 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, const ABC *base_abci, const ABC *base_abcw, const ABCFLOAT *base_abcf)
1081 ABC abc[1];
1082 ABCFLOAT abcf[1];
1083 BOOL ret = FALSE;
1085 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1086 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1087 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1088 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1089 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1091 ret = GetCharABCWidthsI(hdc, glyphs[0], 1, NULL, abc);
1092 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1093 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1094 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1095 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1097 ret = GetCharABCWidthsW(hdc, 'i', 'i', abc);
1098 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1099 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1100 ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1101 ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1103 ret = GetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1104 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1105 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1106 ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1107 ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1110 static void test_GetCharABCWidths(void)
1112 BOOL ret;
1113 HDC hdc;
1114 LOGFONTA lf;
1115 HFONT hfont;
1116 ABC abc[1];
1117 ABC abcw[1];
1118 ABCFLOAT abcf[1];
1119 WORD glyphs[1];
1120 DWORD nb;
1121 HWND hwnd;
1122 static const struct
1124 UINT first;
1125 UINT last;
1126 } range[] =
1128 {0xff, 0xff},
1129 {0x100, 0x100},
1130 {0xff, 0x100},
1131 {0x1ff, 0xff00},
1132 {0xffff, 0xffff},
1133 {0x10000, 0x10000},
1134 {0xffff, 0x10000},
1135 {0xffffff, 0xffffff},
1136 {0x1000000, 0x1000000},
1137 {0xffffff, 0x1000000},
1138 {0xffffffff, 0xffffffff},
1139 {0x00, 0xff}
1141 static const struct
1143 UINT cs;
1144 UINT a;
1145 UINT w;
1146 BOOL r[ARRAY_SIZE(range)];
1147 } c[] =
1149 {ANSI_CHARSET, 0x30, 0x30,
1150 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1151 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1152 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1153 {HANGEUL_CHARSET, 0x8141, 0xac02,
1154 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1155 {GB2312_CHARSET, 0x8141, 0x4e04,
1156 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1157 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1158 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1160 UINT i;
1162 memset(&lf, 0, sizeof(lf));
1163 strcpy(lf.lfFaceName, "System");
1164 lf.lfHeight = 20;
1166 hfont = CreateFontIndirectA(&lf);
1167 hdc = GetDC(0);
1168 hfont = SelectObject(hdc, hfont);
1170 nb = GetGlyphIndicesW(hdc, L"i", 1, glyphs, 0);
1171 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1173 ret = GetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1174 ok(!ret, "GetCharABCWidthsI should have failed\n");
1176 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1177 ok(!ret, "GetCharABCWidthsI should have failed\n");
1179 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1180 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1182 ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
1183 ok(!ret, "GetCharABCWidthsW should have failed\n");
1185 ret = GetCharABCWidthsW(hdc, 'a', 'a', NULL);
1186 ok(!ret, "GetCharABCWidthsW should have failed\n");
1188 ret = GetCharABCWidthsW(hdc, 'a', 'a', abc);
1189 ok(!ret, "GetCharABCWidthsW should have failed\n");
1191 ret = GetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1192 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1194 ret = GetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1195 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1197 ret = GetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1198 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1200 hfont = SelectObject(hdc, hfont);
1201 DeleteObject(hfont);
1203 for (i = 0; i < ARRAY_SIZE(c); ++i)
1205 ABC a[2], w[2];
1206 ABC full[256];
1207 UINT code = 0x41, j;
1209 lf.lfFaceName[0] = '\0';
1210 lf.lfCharSet = c[i].cs;
1211 lf.lfPitchAndFamily = 0;
1212 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1214 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1215 continue;
1218 memset(a, 0, sizeof a);
1219 memset(w, 0, sizeof w);
1220 hfont = SelectObject(hdc, hfont);
1221 ok(GetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) && GetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w)
1222 && !memcmp(a, w, sizeof(a)),
1223 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1225 memset(a, 0xbb, sizeof a);
1226 ret = GetCharABCWidthsA(hdc, code, code, a);
1227 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1228 memset(full, 0xcc, sizeof full);
1229 ret = GetCharABCWidthsA(hdc, 0x00, code, full);
1230 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1231 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1232 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1234 for (j = 0; j < ARRAY_SIZE(range); ++j)
1236 memset(full, 0xdd, sizeof full);
1237 ret = GetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1238 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1239 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1240 if (ret)
1242 UINT last = range[j].last - range[j].first;
1243 ret = GetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1244 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1245 "GetCharABCWidthsA %x should match. codepage = %u\n",
1246 range[j].last, c[i].cs);
1250 hfont = SelectObject(hdc, hfont);
1251 DeleteObject(hfont);
1254 memset(&lf, 0, sizeof(lf));
1255 strcpy(lf.lfFaceName, "Tahoma");
1256 lf.lfHeight = 200;
1257 hfont = CreateFontIndirectA(&lf);
1259 /* test empty glyph's metrics */
1260 hfont = SelectObject(hdc, hfont);
1261 ret = GetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1262 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1263 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1264 ret = GetCharABCWidthsW(hdc, ' ', ' ', abcw);
1265 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1266 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1268 /* 1) prepare unrotated font metrics */
1269 ret = GetCharABCWidthsW(hdc, 'a', 'a', abcw);
1270 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1271 DeleteObject(SelectObject(hdc, hfont));
1273 /* 2) get rotated font metrics */
1274 lf.lfEscapement = lf.lfOrientation = 900;
1275 hfont = CreateFontIndirectA(&lf);
1276 hfont = SelectObject(hdc, hfont);
1277 ret = GetCharABCWidthsW(hdc, 'a', 'a', abc);
1278 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1280 /* 3) compare ABC results */
1281 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1282 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1283 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1284 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1285 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1286 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1288 DeleteObject(SelectObject(hdc, hfont));
1290 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1291 in various widths. */
1292 for (i = 1; i <= 2; i++)
1294 UINT j;
1295 UINT code;
1297 memset(&lf, 0, sizeof(lf));
1298 lf.lfHeight = 20;
1299 if (i == 1)
1301 strcpy(lf.lfFaceName, "Tahoma");
1302 code = 'a';
1304 else
1306 strcpy(lf.lfFaceName, "Times New Roman");
1307 lf.lfItalic = TRUE;
1308 code = 'f';
1310 if (!is_truetype_font_installed(lf.lfFaceName))
1312 skip("%s is not installed\n", lf.lfFaceName);
1313 continue;
1315 for (j = 1; j <= 80; j++)
1317 GLYPHMETRICS gm;
1319 lf.lfWidth = j;
1320 hfont = CreateFontIndirectA(&lf);
1321 hfont = SelectObject(hdc, hfont);
1323 nb = GetGlyphOutlineA(hdc, code, GGO_METRICS, &gm, 0, NULL, &mat);
1324 ok(nb, "GetGlyphOutlineA should have succeeded at width %d\n", i);
1326 ret = GetCharABCWidthsA(hdc, code, code, abc);
1327 ok(ret, "GetCharABCWidthsA should have succeeded at width %d\n", i);
1329 ok(abc[0].abcA == gm.gmptGlyphOrigin.x,
1330 "abcA(%d) and gmptGlyphOrigin.x(%ld) values are different at width %d\n",
1331 abc[0].abcA, gm.gmptGlyphOrigin.x, i);
1332 ok(abc[0].abcB == gm.gmBlackBoxX,
1333 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1334 abc[0].abcB, gm.gmBlackBoxX, i);
1335 DeleteObject(SelectObject(hdc, hfont));
1338 ReleaseDC(NULL, hdc);
1340 /* ABC sign test for a variety of transforms */
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 = GetGlyphIndicesW(hdc, L"i", 1, glyphs, 0);
1352 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1354 ret = GetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1355 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1356 ret = GetCharABCWidthsW(hdc, 'i', 'i', abcw);
1357 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1358 ret = GetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1359 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1361 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf);
1362 SetWindowExtEx(hdc, -1, -1, NULL);
1363 SetGraphicsMode(hdc, GM_COMPATIBLE);
1364 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf);
1365 SetGraphicsMode(hdc, GM_ADVANCED);
1366 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf);
1367 SetWindowExtEx(hdc, 1, 1, NULL);
1368 SetGraphicsMode(hdc, GM_COMPATIBLE);
1369 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf);
1370 SetGraphicsMode(hdc, GM_ADVANCED);
1371 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf);
1373 ReleaseDC(hwnd, hdc);
1374 DestroyWindow(hwnd);
1376 /* RTL layout */
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);
1384 SetWindowExtEx(hdc, -1, -1, NULL);
1385 SetGraphicsMode(hdc, GM_COMPATIBLE);
1386 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf);
1387 SetGraphicsMode(hdc, GM_ADVANCED);
1388 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf);
1389 SetWindowExtEx(hdc, 1, 1, NULL);
1390 SetGraphicsMode(hdc, GM_COMPATIBLE);
1391 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf);
1392 SetGraphicsMode(hdc, GM_ADVANCED);
1393 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf);
1395 ReleaseDC(hwnd, hdc);
1396 DestroyWindow(hwnd);
1397 DeleteObject(hfont);
1400 static void test_text_extents(void)
1402 static const WCHAR wt[] = L"One\ntwo 3";
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 ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1422 ok(ret, "got %d\n", ret);
1423 ok(sz.cy == tm.tmHeight, "cy %ld tmHeight %ld\n", sz.cy, tm.tmHeight);
1425 memset(&sz, 0xcc, sizeof(sz));
1426 ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1427 ok(ret, "got %d\n", ret);
1428 ok(sz.cx == 0 && sz.cy == 0, "cx %ld, cy %ld\n", sz.cx, sz.cy);
1430 memset(&sz, 0xcc, sizeof(sz));
1431 ret = GetTextExtentPointA(hdc, "", 0, &sz);
1432 ok(ret, "got %d\n", ret);
1433 ok(sz.cx == 0 && sz.cy == 0, "cx %ld, cy %ld\n", sz.cx, sz.cy);
1435 memset(&sz, 0xcc, sizeof(sz));
1436 ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1437 ok(ret, "got %d\n", ret);
1438 ok(sz.cx == 0 && sz.cy == 0, "cx %ld, cy %ld\n", sz.cx, sz.cy);
1440 memset(&sz, 0xcc, sizeof(sz));
1441 ret = GetTextExtentPointW(hdc, L"", 0, &sz);
1442 ok(ret, "got %d\n", ret);
1443 ok(sz.cx == 0 && sz.cy == 0, "cx %ld, cy %ld\n", sz.cx, sz.cy);
1445 len = lstrlenW(wt);
1446 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1447 extents[0] = 1; /* So that the increasing sequence test will fail
1448 if the extents array is untouched. */
1449 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1450 GetTextExtentPointW(hdc, wt, len, &sz2);
1451 ok(sz1.cy == sz2.cy,
1452 "cy from GetTextExtentExPointW (%ld) and GetTextExtentPointW (%ld) differ\n", sz1.cy, sz2.cy);
1453 /* Because of the '\n' in the string GetTextExtentExPoint and
1454 GetTextExtentPoint return different widths under Win2k, but
1455 under WinXP they return the same width. So we don't test that
1456 here. */
1458 for (i = 1; i < len; ++i)
1459 ok(extents[i-1] <= extents[i],
1460 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1462 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1463 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1464 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1465 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1466 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1467 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1468 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1469 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1470 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1471 ok(extents[0] == extents[2] && extents[1] == extents[3],
1472 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1473 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1474 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1475 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1477 /* extents functions fail with -ve counts (the interesting case being -1) */
1478 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1479 ok(ret == FALSE, "got %d\n", ret);
1480 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1481 ok(ret == FALSE, "got %d\n", ret);
1482 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1483 ok(ret == FALSE, "got %d\n", ret);
1485 /* max_extent = 0 succeeds and returns zero */
1486 fit1 = fit2 = -215;
1487 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1488 ok(ret == TRUE, "got %d\n", ret);
1489 ok(fit1 == 0, "fit = %d\n", fit1);
1490 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1491 ok(ret == TRUE, "got %d\n", ret);
1492 ok(fit2 == 0, "fit = %d\n", fit2);
1494 /* max_extent = -1 is interpreted as a very large width that will
1495 * definitely fit our three characters */
1496 fit1 = fit2 = -215;
1497 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1498 ok(ret == TRUE, "got %d\n", ret);
1499 ok(fit1 == 3, "fit = %d\n", fit1);
1500 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1501 ok(ret == TRUE, "got %d\n", ret);
1502 ok(fit2 == 3, "fit = %d\n", fit2);
1504 /* max_extent = -2 is interpreted similarly, but the Ansi version
1505 * rejects it while the Unicode one accepts it */
1506 fit1 = fit2 = -215;
1507 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1508 ok(ret == FALSE, "got %d\n", ret);
1509 ok(fit1 == -215, "fit = %d\n", fit1);
1510 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1511 ok(ret == TRUE, "got %d\n", ret);
1512 ok(fit2 == 3, "fit = %d\n", fit2);
1514 hfont = SelectObject(hdc, hfont);
1515 DeleteObject(hfont);
1517 /* non-MM_TEXT mapping mode */
1518 lf.lfHeight = 2000;
1519 hfont = CreateFontIndirectA(&lf);
1520 hfont = SelectObject(hdc, hfont);
1522 SetMapMode( hdc, MM_HIMETRIC );
1523 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1524 ok(ret, "got %d\n", ret);
1525 ok(sz.cx == extents[2], "got %ld vs %d\n", sz.cx, extents[2]);
1527 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1528 ok(ret, "got %d\n", ret);
1529 ok(fit1 == 2, "got %d\n", fit1);
1530 ok(sz2.cx == sz.cx, "got %ld vs %ld\n", sz2.cx, sz.cx);
1531 for(i = 0; i < 2; i++)
1532 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1534 hfont = SelectObject(hdc, hfont);
1535 DeleteObject(hfont);
1536 HeapFree(GetProcessHeap(), 0, extents);
1537 ReleaseDC(NULL, hdc);
1540 static void free_font(void *font)
1542 UnmapViewOfFile(font);
1545 static void *load_font(const char *font_name, DWORD *font_size)
1547 char file_name[MAX_PATH];
1548 HANDLE file, mapping;
1549 void *font;
1551 if (font_name[1] == ':')
1552 strcpy(file_name, font_name);
1553 else
1555 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
1556 strcat(file_name, "\\fonts\\");
1557 strcat(file_name, font_name);
1560 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
1561 if (file == INVALID_HANDLE_VALUE) return NULL;
1563 *font_size = GetFileSize(file, NULL);
1565 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
1566 if (!mapping)
1568 CloseHandle(file);
1569 return NULL;
1572 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
1574 CloseHandle(file);
1575 CloseHandle(mapping);
1576 return font;
1579 static void test_GetGlyphIndices(void)
1581 HDC hdc;
1582 HFONT hfont;
1583 DWORD charcount;
1584 LOGFONTA lf;
1585 DWORD flags = 0;
1586 WCHAR testtext[] = L"Test\xffff";
1587 WCHAR c[] = { 0x25bc /* Black Down-Pointing Triangle */, 0x212a /* Kelvin Sign */ };
1588 WORD glyphs[(sizeof(testtext)/2)-1];
1589 TEXTMETRICA textm;
1590 HFONT hOldFont;
1591 HANDLE rsrc;
1592 DWORD ret, font_size, num_fonts;
1593 void *font;
1594 char ttf_name[MAX_PATH];
1596 hdc = GetDC(0);
1598 memset(&lf, 0, sizeof(lf));
1599 strcpy(lf.lfFaceName, "System");
1600 lf.lfHeight = 16;
1601 lf.lfCharSet = ANSI_CHARSET;
1603 hfont = CreateFontIndirectA(&lf);
1604 ok(hfont != 0, "CreateFontIndirect failed\n");
1605 hOldFont = SelectObject(hdc, hfont);
1606 ok(GetTextMetricsA(hdc, &textm), "GetTextMetrics failed\n");
1607 if (textm.tmCharSet == ANSI_CHARSET)
1609 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1610 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1611 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount);
1612 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1613 flags = 0;
1614 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1615 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount);
1616 ok(glyphs[4] == textm.tmDefaultChar || glyphs[4] == 0x20 /* CJK Windows */,
1617 "GetGlyphIndicesW should have returned a %04x not %04x\n", textm.tmDefaultChar, glyphs[4]);
1619 else
1620 /* FIXME: Write tests for non-ANSI charsets. */
1621 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1623 DeleteObject(SelectObject(hdc, hOldFont));
1625 memset(&lf, 0, sizeof(lf));
1626 strcpy(lf.lfFaceName, "MS Sans Serif");
1627 lf.lfHeight = -13;
1628 lf.lfCharSet = DEFAULT_CHARSET;
1629 hfont = CreateFontIndirectA(&lf);
1630 ok(hfont != 0, "CreateFontIndirect failed\n");
1631 hOldFont = SelectObject(hdc, hfont);
1632 ok(GetTextMetricsA(hdc, &textm), "GetTextMetrics failed\n");
1634 glyphs[0] = glyphs[1] = 0;
1635 charcount = GetGlyphIndicesW(hdc, c, ARRAY_SIZE(c), glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1636 ok(charcount == ARRAY_SIZE(c), "got %lu\n", charcount);
1637 ok(glyphs[0] == 0x001f || glyphs[0] == 0xffff /* Vista */, "got %#x\n", glyphs[0]);
1638 ok(glyphs[1] == 0x001f || glyphs[1] == 0xffff /* Vista */, "got %#x\n", glyphs[1]);
1640 glyphs[0] = glyphs[1] = 0;
1641 charcount = GetGlyphIndicesW(hdc, c, ARRAY_SIZE(c), glyphs, 0);
1642 ok(charcount == ARRAY_SIZE(c), "got %lu\n", charcount);
1643 ok(glyphs[0] == textm.tmDefaultChar || glyphs[0] == 0x20 /* CJK Windows */, "got %#x\n", glyphs[0]);
1644 ok(glyphs[1] == textm.tmDefaultChar || glyphs[1] == 0x20 /* CJK Windows */, "got %#x\n", glyphs[1]);
1646 DeleteObject(SelectObject(hdc, hOldFont));
1648 if(!is_font_installed("Tahoma"))
1650 skip("Tahoma is not installed so skipping this test\n");
1651 ReleaseDC(0, hdc);
1652 return;
1654 memset(&lf, 0, sizeof(lf));
1655 strcpy(lf.lfFaceName, "Tahoma");
1656 lf.lfHeight = 20;
1658 hfont = CreateFontIndirectA(&lf);
1659 hOldFont = SelectObject(hdc, hfont);
1660 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1661 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1662 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1663 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount);
1664 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1665 flags = 0;
1666 testtext[0] = textm.tmDefaultChar;
1667 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1668 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount);
1669 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1670 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1671 DeleteObject(SelectObject(hdc, hOldFont));
1673 ret = write_ttf_file("wine_nul.ttf", ttf_name);
1674 ok(ret, "Failed to create test font file.\n");
1675 font = load_font(ttf_name, &font_size);
1676 ok(font != NULL, "Failed to map font file.\n");
1677 num_fonts = 0;
1678 rsrc = AddFontMemResourceEx(font, font_size, NULL, &num_fonts);
1679 ok(ret != 0, "Failed to add resource, %ld.\n", GetLastError());
1680 ok(num_fonts == 1, "Unexpected number of fonts %lu.\n", num_fonts);
1682 memset(&lf, 0, sizeof(lf));
1683 strcpy(lf.lfFaceName, "wine_nul");
1684 lf.lfHeight = 20;
1685 flags = 0;
1686 hfont = CreateFontIndirectA(&lf);
1687 hOldFont = SelectObject(hdc, hfont);
1688 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1689 testtext[0] = 'T';
1690 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1691 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount);
1692 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1693 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1694 DeleteObject(SelectObject(hdc, hOldFont));
1696 ReleaseDC(0, hdc);
1698 ret = RemoveFontMemResourceEx(rsrc);
1699 ok(ret, "RemoveFontMemResourceEx error %ld\n", GetLastError());
1700 free_font(font);
1701 ret = DeleteFileA(ttf_name);
1702 ok(ret, "Failed to delete font file, %ld.\n", GetLastError());
1705 static void test_GetKerningPairs(void)
1707 static const struct kerning_data
1709 const char face_name[LF_FACESIZE];
1710 LONG height;
1711 /* some interesting fields from OUTLINETEXTMETRIC */
1712 LONG tmHeight, tmAscent, tmDescent;
1713 UINT otmEMSquare;
1714 INT otmAscent;
1715 INT otmDescent;
1716 UINT otmLineGap;
1717 UINT otmsCapEmHeight;
1718 UINT otmsXHeight;
1719 INT otmMacAscent;
1720 INT otmMacDescent;
1721 UINT otmMacLineGap;
1722 UINT otmusMinimumPPEM;
1723 /* small subset of kerning pairs to test */
1724 DWORD total_kern_pairs;
1725 const KERNINGPAIR kern_pair[26];
1726 } kd[] =
1728 {"Arial", 12, 12, 9, 3,
1729 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1732 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1733 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1734 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1735 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1736 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1737 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1738 {933,970,+1},{933,972,-1}
1741 {"Arial", -34, 39, 32, 7,
1742 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1745 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1746 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1747 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1748 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1749 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1750 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1751 {933,970,+2},{933,972,-3}
1754 { "Arial", 120, 120, 97, 23,
1755 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1758 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1759 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1760 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1761 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1762 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1763 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1764 {933,970,+6},{933,972,-10}
1767 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1768 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1769 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1772 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1773 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1774 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1775 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1776 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1777 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1778 {933,970,+54},{933,972,-83}
1781 #endif
1783 LOGFONTA lf;
1784 HFONT hfont, hfont_old;
1785 KERNINGPAIR *kern_pair;
1786 HDC hdc;
1787 DWORD total_kern_pairs, ret, i, n, matches;
1789 hdc = GetDC(0);
1791 for (i = 0; i < ARRAY_SIZE(kd); i++)
1793 OUTLINETEXTMETRICW otm;
1794 UINT uiRet;
1796 if (!is_font_installed(kd[i].face_name))
1798 skip("%s is not installed so skipping this test\n", kd[i].face_name);
1799 continue;
1802 memset(&lf, 0, sizeof(lf));
1803 strcpy(lf.lfFaceName, kd[i].face_name);
1804 lf.lfHeight = kd[i].height;
1805 hfont = CreateFontIndirectA(&lf);
1806 ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name);
1808 hfont_old = SelectObject(hdc, hfont);
1810 SetLastError(0xdeadbeef);
1811 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1812 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %ld\n", GetLastError());
1814 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %ld, got %ld\n",
1815 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1816 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %ld, got %ld\n",
1817 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1818 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %ld, got %ld\n",
1819 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1821 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1822 kd[i].otmEMSquare, otm.otmEMSquare);
1823 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1824 kd[i].otmAscent, otm.otmAscent);
1825 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1826 kd[i].otmDescent, otm.otmDescent);
1827 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1828 kd[i].otmLineGap, otm.otmLineGap);
1829 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1830 kd[i].otmMacDescent, otm.otmMacDescent);
1831 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1832 kd[i].otmMacAscent, otm.otmMacAscent);
1833 todo_wine
1834 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1835 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1836 todo_wine
1837 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1838 kd[i].otmsXHeight, otm.otmsXHeight);
1839 ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1840 kd[i].otmMacLineGap, otm.otmMacLineGap);
1841 todo_wine
1842 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1843 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1845 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1846 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1848 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1849 * passes on XP.
1851 SetLastError(0xdeadbeef);
1852 ret = GetKerningPairsW(hdc, 0, kern_pair);
1853 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1854 "got error %lu, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1855 ok(ret == 0, "got %lu, expected 0\n", ret);
1857 ret = GetKerningPairsW(hdc, 100, NULL);
1858 ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
1860 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1861 ok(ret == total_kern_pairs/2, "got %lu, expected %lu\n", ret, total_kern_pairs/2);
1863 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1864 ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
1866 matches = 0;
1868 for (n = 0; n < ret; n++)
1870 DWORD j;
1872 for (j = 0; j < kd[i].total_kern_pairs; j++)
1874 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1875 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1877 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1878 "pair %d:%d got %d, expected %d\n",
1879 kern_pair[n].wFirst, kern_pair[n].wSecond,
1880 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1881 matches++;
1886 ok(matches == kd[i].total_kern_pairs, "got matches %lu, expected %lu\n",
1887 matches, kd[i].total_kern_pairs);
1889 HeapFree(GetProcessHeap(), 0, kern_pair);
1891 SelectObject(hdc, hfont_old);
1892 DeleteObject(hfont);
1895 ReleaseDC(0, hdc);
1898 struct font_data
1900 const char face_name[LF_FACESIZE];
1901 int requested_height;
1902 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1903 BOOL exact;
1906 static void test_height( HDC hdc, const struct font_data *fd )
1908 LOGFONTA lf;
1909 HFONT hfont, old_hfont;
1910 TEXTMETRICA tm;
1911 INT ret, i;
1913 for (i = 0; fd[i].face_name[0]; i++)
1915 if (!is_truetype_font_installed(fd[i].face_name))
1917 skip("%s is not installed\n", fd[i].face_name);
1918 continue;
1921 memset(&lf, 0, sizeof(lf));
1922 lf.lfHeight = fd[i].requested_height;
1923 lf.lfWeight = fd[i].weight;
1924 strcpy(lf.lfFaceName, fd[i].face_name);
1926 hfont = CreateFontIndirectA(&lf);
1927 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
1929 old_hfont = SelectObject(hdc, hfont);
1930 ret = GetTextMetricsA(hdc, &tm);
1931 ok(ret, "GetTextMetrics error %ld\n", GetLastError());
1932 if(fd[i].dpi == tm.tmDigitizedAspectX)
1934 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %ld != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1935 ok(match_off_by_1(tm.tmHeight, fd[i].height, fd[i].exact), "%s(%d): tm.tmHeight %ld != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1936 ok(match_off_by_1(tm.tmAscent, fd[i].ascent, fd[i].exact), "%s(%d): tm.tmAscent %ld != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1937 ok(match_off_by_1(tm.tmDescent, fd[i].descent, fd[i].exact), "%s(%d): tm.tmDescent %ld != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1938 ok(match_off_by_1(tm.tmInternalLeading, fd[i].int_leading, fd[i].exact), "%s(%d): tm.tmInternalLeading %ld != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1939 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1942 SelectObject(hdc, old_hfont);
1943 /* force GDI to use new font, otherwise Windows leaks the font reference */
1944 GetTextMetricsA(hdc, &tm);
1945 DeleteObject(hfont);
1949 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1951 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1952 DWORD *table = (DWORD *)ttf + 3;
1954 for (i = 0; i < num_tables; i++)
1956 if (table[0] == tag)
1957 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1958 table += 4;
1960 return NULL;
1963 static void test_height_selection_vdmx( HDC hdc )
1965 static const struct font_data charset_0[] = /* doesn't use VDMX */
1967 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1968 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1969 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1970 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1971 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1972 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1973 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1974 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1975 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1976 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1977 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1978 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1979 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1980 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1981 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1982 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1983 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1984 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1985 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1986 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1987 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1988 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1989 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1990 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1991 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1992 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1993 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1994 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1995 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1996 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1997 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1998 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1999 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
2000 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
2001 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
2002 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
2003 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2004 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
2005 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
2006 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
2007 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2008 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
2009 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
2010 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
2011 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
2012 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
2013 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
2014 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
2015 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
2016 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2017 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
2018 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2019 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2022 static const struct font_data charset_1[] = /* Uses VDMX */
2024 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
2025 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
2026 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2027 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2028 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2029 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2030 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2031 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2032 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2033 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2034 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2035 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2036 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2037 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2038 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2039 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2040 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2041 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2042 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2043 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2044 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2045 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2046 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2047 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
2048 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
2049 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
2050 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2051 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2052 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2053 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2054 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2055 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2056 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2057 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2058 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2059 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2060 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2061 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2062 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2063 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2064 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2065 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2066 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2067 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2068 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2069 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2070 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2071 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2072 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2073 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2074 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2075 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2076 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2079 static const struct vdmx_data
2081 WORD version;
2082 BYTE bCharSet;
2083 const struct font_data *fd;
2084 } data[] =
2086 { 0, 0, charset_0 },
2087 { 0, 1, charset_1 },
2088 { 1, 0, charset_0 },
2089 { 1, 1, charset_1 }
2091 int i;
2092 DWORD size, num;
2093 WORD *vdmx_header;
2094 BYTE *ratio_rec;
2095 char ttf_name[MAX_PATH];
2096 void *res, *copy;
2097 BOOL ret;
2099 for (i = 0; i < ARRAY_SIZE(data); i++)
2101 res = get_res_data( "wine_vdmx.ttf", &size );
2103 copy = HeapAlloc( GetProcessHeap(), 0, size );
2104 memcpy( copy, res, size );
2105 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2106 vdmx_header[0] = GET_BE_WORD( data[i].version );
2107 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2108 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2109 ratio_rec = (BYTE *)&vdmx_header[3];
2110 ratio_rec[0] = data[i].bCharSet;
2112 write_tmp_file( copy, &size, ttf_name );
2113 HeapFree( GetProcessHeap(), 0, copy );
2115 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2116 num = AddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2117 if (!num) win_skip("Unable to add ttf font resource\n");
2118 else
2120 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2121 test_height( hdc, data[i].fd );
2122 RemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2124 ret = DeleteFileA( ttf_name );
2125 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2126 "DeleteFile error %ld\n", GetLastError());
2130 static void test_height_selection(void)
2132 static const struct font_data tahoma[] =
2134 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2135 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2136 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2137 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2138 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2139 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2140 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2141 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2142 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2143 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2144 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2146 HDC hdc = CreateCompatibleDC(0);
2147 ok(hdc != NULL, "failed to create hdc\n");
2149 test_height( hdc, tahoma );
2150 test_height_selection_vdmx( hdc );
2152 DeleteDC(hdc);
2155 static UINT get_font_fsselection(LOGFONTA *lf)
2157 OUTLINETEXTMETRICA *otm;
2158 HFONT hfont, hfont_old;
2159 DWORD ret, otm_size;
2160 UINT fsSelection;
2161 HDC hdc;
2163 hdc = GetDC(0);
2164 hfont = CreateFontIndirectA(lf);
2165 ok(hfont != NULL, "failed to create a font\n");
2167 hfont_old = SelectObject(hdc, hfont);
2169 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2170 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2171 otm->otmSize = sizeof(*otm);
2172 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2173 ok(ret == otm->otmSize, "expected %u, got %lu, error %ld\n", otm->otmSize, ret, GetLastError());
2174 fsSelection = otm->otmfsSelection;
2175 HeapFree(GetProcessHeap(), 0, otm);
2176 SelectObject(hdc, hfont_old);
2177 DeleteObject(hfont);
2178 ReleaseDC(0, hdc);
2180 return fsSelection;
2183 static void test_GetOutlineTextMetrics(void)
2185 OUTLINETEXTMETRICA *otm;
2186 LOGFONTA lf;
2187 HFONT hfont, hfont_old;
2188 HDC hdc;
2189 DWORD ret, otm_size;
2190 LPSTR unset_ptr;
2191 UINT fsSelection;
2193 /* check fsSelection field with bold simulation */
2194 memset(&lf, 0, sizeof(lf));
2195 strcpy(lf.lfFaceName, "Wingdings");
2196 lf.lfCharSet = SYMBOL_CHARSET;
2198 /* regular face */
2199 fsSelection = get_font_fsselection(&lf);
2200 ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection);
2202 /* face with bold simulation */
2203 lf.lfWeight = FW_BOLD;
2204 fsSelection = get_font_fsselection(&lf);
2205 ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection);
2207 /* check fsSelection field with oblique simulation */
2208 memset(&lf, 0, sizeof(lf));
2209 strcpy(lf.lfFaceName, "Tahoma");
2210 lf.lfHeight = -13;
2211 lf.lfWeight = FW_NORMAL;
2212 lf.lfPitchAndFamily = DEFAULT_PITCH;
2213 lf.lfQuality = PROOF_QUALITY;
2215 /* regular face */
2216 fsSelection = get_font_fsselection(&lf);
2217 ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection);
2219 lf.lfItalic = 1;
2220 /* face with oblique simulation */
2221 fsSelection = get_font_fsselection(&lf);
2222 ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection);
2224 if (!is_font_installed("Arial"))
2226 skip("Arial is not installed\n");
2227 return;
2230 hdc = GetDC(0);
2232 memset(&lf, 0, sizeof(lf));
2233 strcpy(lf.lfFaceName, "Arial");
2234 lf.lfHeight = -13;
2235 lf.lfWeight = FW_NORMAL;
2236 lf.lfPitchAndFamily = DEFAULT_PITCH;
2237 lf.lfQuality = PROOF_QUALITY;
2238 hfont = CreateFontIndirectA(&lf);
2239 ok(hfont != NULL, "failed to create a font\n");
2241 hfont_old = SelectObject(hdc, hfont);
2242 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2244 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2246 memset(otm, 0xAA, otm_size);
2247 SetLastError(0xdeadbeef);
2248 otm->otmSize = sizeof(*otm);
2249 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2250 ok(ret == otm->otmSize, "expected %u, got %lu, error %ld\n", otm->otmSize, ret, GetLastError());
2251 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2252 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2253 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2254 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2256 memset(otm, 0xAA, otm_size);
2257 SetLastError(0xdeadbeef);
2258 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2259 ok(ret == otm->otmSize, "expected %u, got %lu, error %ld\n", otm->otmSize, ret, GetLastError());
2260 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2261 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2262 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2263 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2265 /* ask about truncated data */
2266 memset(otm, 0xAA, otm_size);
2267 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2268 SetLastError(0xdeadbeef);
2269 otm->otmSize = sizeof(*otm) - sizeof(char*);
2270 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2271 ok(ret == otm->otmSize, "expected %u, got %lu, error %ld\n", otm->otmSize, ret, GetLastError());
2272 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2273 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2274 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2275 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2277 /* check handling of NULL pointer */
2278 SetLastError(0xdeadbeef);
2279 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2280 ok(ret == otm_size, "expected %lu, got %lu, error %ld\n", otm_size, ret, GetLastError());
2282 HeapFree(GetProcessHeap(), 0, otm);
2284 SelectObject(hdc, hfont_old);
2285 DeleteObject(hfont);
2287 ReleaseDC(0, hdc);
2290 static void testJustification(const char *context, HDC hdc, PCSTR str, RECT *clientArea)
2292 INT y,
2293 breakCount,
2294 areaWidth = clientArea->right - clientArea->left,
2295 nErrors = 0, e;
2296 const char *pFirstChar, *pLastChar;
2297 SIZE size;
2298 TEXTMETRICA tm;
2299 struct err
2301 const char *start;
2302 int len;
2303 int GetTextExtentExPointWWidth;
2304 } error[20];
2306 GetTextMetricsA(hdc, &tm);
2307 y = clientArea->top;
2308 do {
2309 breakCount = 0;
2310 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2311 pFirstChar = str;
2313 do {
2314 pLastChar = str;
2316 /* if not at the end of the string, ... */
2317 if (*str == '\0') break;
2318 /* ... add the next word to the current extent */
2319 while (*str != '\0' && *str++ != tm.tmBreakChar);
2320 breakCount++;
2321 SetTextJustification(hdc, 0, 0);
2322 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2323 } while ((int) size.cx < areaWidth);
2325 /* ignore trailing break chars */
2326 breakCount--;
2327 while (*(pLastChar - 1) == tm.tmBreakChar)
2329 pLastChar--;
2330 breakCount--;
2333 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2335 SetTextJustification(hdc, 0, 0);
2336 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2338 /* do not justify the last extent */
2339 if (*str != '\0' && breakCount > 0)
2341 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2342 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2343 if (size.cx != areaWidth && nErrors < ARRAY_SIZE(error) - 1)
2345 error[nErrors].start = pFirstChar;
2346 error[nErrors].len = pLastChar - pFirstChar;
2347 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2348 nErrors++;
2352 y += size.cy;
2353 str = pLastChar;
2354 } while (*str && y < clientArea->bottom);
2356 for (e = 0; e < nErrors; e++)
2358 /* The width returned by GetTextExtentPoint32() is exactly the same
2359 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2360 ok(error[e].GetTextExtentExPointWWidth == areaWidth ||
2361 broken(abs(areaWidth - error[e].GetTextExtentExPointWWidth) <= 2) /* win10 */,
2362 "%s: GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2363 context, error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2367 static void test_SetTextJustification(void)
2369 HDC hdc;
2370 RECT clientArea;
2371 LOGFONTA lf;
2372 HFONT hfont;
2373 HWND hwnd;
2374 SIZE size, expect;
2375 int i;
2376 WORD indices[2];
2377 static const char testText[] =
2378 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2379 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2380 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2381 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2382 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2383 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2384 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2386 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2387 GetClientRect( hwnd, &clientArea );
2388 hdc = GetDC( hwnd );
2390 if (!is_font_installed("Times New Roman"))
2392 skip("Times New Roman is not installed\n");
2393 return;
2396 memset(&lf, 0, sizeof lf);
2397 lf.lfCharSet = ANSI_CHARSET;
2398 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2399 lf.lfWeight = FW_DONTCARE;
2400 lf.lfHeight = 20;
2401 lf.lfQuality = DEFAULT_QUALITY;
2402 lstrcpyA(lf.lfFaceName, "Times New Roman");
2403 hfont = create_font("Times New Roman", &lf);
2404 SelectObject(hdc, hfont);
2406 testJustification("default", hdc, testText, &clientArea);
2408 GetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2410 SetTextJustification(hdc, 0, 0);
2411 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2412 GetTextExtentPoint32A(hdc, " ", 3, &size);
2413 ok( size.cx == 3 * expect.cx, "wrong size %ld/%ld\n", size.cx, expect.cx );
2414 SetTextJustification(hdc, 4, 1);
2415 GetTextExtentPoint32A(hdc, " ", 1, &size);
2416 ok( size.cx == expect.cx + 4, "wrong size %ld/%ld\n", size.cx, expect.cx );
2417 SetTextJustification(hdc, 9, 2);
2418 GetTextExtentPoint32A(hdc, " ", 2, &size);
2419 ok( size.cx == 2 * expect.cx + 9, "wrong size %ld/%ld\n", size.cx, expect.cx );
2420 SetTextJustification(hdc, 7, 3);
2421 GetTextExtentPoint32A(hdc, " ", 3, &size);
2422 ok( size.cx == 3 * expect.cx + 7, "wrong size %ld/%ld\n", size.cx, expect.cx );
2423 SetTextJustification(hdc, 7, 3);
2424 SetTextCharacterExtra(hdc, 2 );
2425 GetTextExtentPoint32A(hdc, " ", 3, &size);
2426 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %ld/%ld\n", size.cx, expect.cx );
2427 SetTextJustification(hdc, 0, 0);
2428 SetTextCharacterExtra(hdc, 0);
2429 size.cx = size.cy = 1234;
2430 GetTextExtentPoint32A(hdc, " ", 0, &size);
2431 ok( size.cx == 0 && size.cy == 0, "wrong size %ld,%ld\n", size.cx, size.cy );
2432 GetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2433 SetTextJustification(hdc, 5, 1);
2434 GetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2435 ok( size.cx == expect.cx + 5, "wrong size %ld/%ld\n", size.cx, expect.cx );
2436 SetTextJustification(hdc, 0, 0);
2438 SetMapMode( hdc, MM_ANISOTROPIC );
2439 SetWindowExtEx( hdc, 2, 2, NULL );
2440 GetClientRect( hwnd, &clientArea );
2441 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2442 testJustification("2x2", hdc, testText, &clientArea);
2444 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2445 for (i = 0; i < 10; i++)
2447 SetTextCharacterExtra(hdc, i);
2448 GetTextExtentPoint32A(hdc, "A", 1, &size);
2449 ok( size.cx == expect.cx + i, "wrong size %ld/%ld+%d\n", size.cx, expect.cx, i );
2451 SetTextCharacterExtra(hdc, 0);
2452 GetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2453 for (i = 0; i < 10; i++)
2455 SetTextCharacterExtra(hdc, i);
2456 GetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2457 ok( size.cx == expect.cx + i, "wrong size %ld/%ld+%d\n", size.cx, expect.cx, i );
2459 SetTextCharacterExtra(hdc, 0);
2461 SetViewportExtEx( hdc, 3, 3, NULL );
2462 GetClientRect( hwnd, &clientArea );
2463 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2464 testJustification("3x3", hdc, testText, &clientArea);
2466 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2467 for (i = 0; i < 10; i++)
2469 SetTextCharacterExtra(hdc, i);
2470 GetTextExtentPoint32A(hdc, "A", 1, &size);
2471 ok( size.cx == expect.cx + i, "wrong size %ld/%ld+%d\n", size.cx, expect.cx, i );
2474 DeleteObject(hfont);
2475 ReleaseDC(hwnd, hdc);
2476 DestroyWindow(hwnd);
2479 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2481 HDC hdc;
2482 LOGFONTA lf;
2483 HFONT hfont, hfont_old;
2484 CHARSETINFO csi;
2485 FONTSIGNATURE fs;
2486 INT cs;
2487 DWORD i, ret;
2488 char name[64];
2490 assert(count <= 128);
2492 memset(&lf, 0, sizeof(lf));
2494 lf.lfCharSet = charset;
2495 lf.lfHeight = 10;
2496 lstrcpyA(lf.lfFaceName, "Arial");
2497 SetLastError(0xdeadbeef);
2498 hfont = CreateFontIndirectA(&lf);
2499 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
2501 hdc = GetDC(0);
2502 hfont_old = SelectObject(hdc, hfont);
2504 cs = GetTextCharsetInfo(hdc, &fs, 0);
2505 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2507 SetLastError(0xdeadbeef);
2508 ret = GetTextFaceA(hdc, sizeof(name), name);
2509 ok(ret, "GetTextFaceA error %lu\n", GetLastError());
2511 if (charset == SYMBOL_CHARSET)
2513 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2514 ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n");
2516 else
2518 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2519 ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2522 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2524 trace("Can't find codepage for charset %d\n", cs);
2525 ReleaseDC(0, hdc);
2526 return FALSE;
2528 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2530 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2532 skip("Font code page %ld, looking for code page %d\n",
2533 pGdiGetCodePage(hdc), code_page);
2534 ReleaseDC(0, hdc);
2535 return FALSE;
2538 if (unicode)
2540 char ansi_buf[128];
2541 WCHAR unicode_buf[128];
2543 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2545 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2547 SetLastError(0xdeadbeef);
2548 ret = GetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2549 ok(ret == count, "GetGlyphIndicesW expected %d got %ld, error %lu\n",
2550 count, ret, GetLastError());
2552 else
2554 char ansi_buf[128];
2556 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2558 SetLastError(0xdeadbeef);
2559 ret = GetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2560 ok(ret == count, "GetGlyphIndicesA expected %d got %ld, error %lu\n",
2561 count, ret, GetLastError());
2564 SelectObject(hdc, hfont_old);
2565 DeleteObject(hfont);
2567 ReleaseDC(0, hdc);
2569 return TRUE;
2572 static void test_TranslateCharsetInfo(void)
2574 static CHARSETINFO tests[] =
2576 { ANSI_CHARSET, 1252, { {0}, { FS_LATIN1 }}},
2577 { EASTEUROPE_CHARSET, 1250, { {0}, { FS_LATIN2 }}},
2578 { RUSSIAN_CHARSET, 1251, { {0}, { FS_CYRILLIC }}},
2579 { GREEK_CHARSET, 1253, { {0}, { FS_GREEK }}},
2580 { TURKISH_CHARSET, 1254, { {0}, { FS_TURKISH }}},
2581 { HEBREW_CHARSET, 1255, { {0}, { FS_HEBREW }}},
2582 { ARABIC_CHARSET, 1256, { {0}, { FS_ARABIC }}},
2583 { BALTIC_CHARSET, 1257, { {0}, { FS_BALTIC }}},
2584 { VIETNAMESE_CHARSET, 1258, { {0}, { FS_VIETNAMESE }}},
2585 { THAI_CHARSET, 874, { {0}, { FS_THAI }}},
2586 { SHIFTJIS_CHARSET, 932, { {0}, { FS_JISJAPAN }}},
2587 { GB2312_CHARSET, 936, { {0}, { FS_CHINESESIMP }}},
2588 { HANGEUL_CHARSET, 949, { {0}, { FS_WANSUNG }}},
2589 { CHINESEBIG5_CHARSET, 950, { {0}, { FS_CHINESETRAD }}},
2590 { JOHAB_CHARSET, 1361, { {0}, { FS_JOHAB }}},
2591 { 254, CP_UTF8, { {0}, { 0x04000000 }}},
2592 { SYMBOL_CHARSET, CP_SYMBOL, { {0}, { FS_SYMBOL }}}
2594 CHARSETINFO csi;
2595 DWORD i, j;
2596 BOOL ret;
2598 /* try all codepages */
2599 for (i = 0; i < 65536; i++)
2601 memset( &csi, 0xcc, sizeof(csi) );
2602 ret = TranslateCharsetInfo( ULongToPtr(i), &csi, TCI_SRCCODEPAGE );
2603 if (ret)
2605 for (j = 0; j < ARRAY_SIZE(tests); j++)
2607 if (tests[j].ciACP != i) continue;
2608 ok( !memcmp( &csi, &tests[j], sizeof(csi) ),
2609 "%lu: wrong info %u %u %08lx %08lx %08lx %08lx %08lx %08lx\n", i,
2610 csi.ciCharset, csi.ciACP, csi.fs.fsUsb[0], csi.fs.fsUsb[1],
2611 csi.fs.fsUsb[2], csi.fs.fsUsb[3], csi.fs.fsCsb[0], csi.fs.fsCsb[1] );
2612 break;
2614 ok( j < ARRAY_SIZE(tests), "%lu: TranslateCharsetInfo succeeded\n", i );
2616 else ok( !ret, "%lu: TranslateCharsetInfo succeeded\n", i );
2619 /* try all charsets */
2620 for (i = 0; i < 256; i++)
2622 memset( &csi, 0xcc, sizeof(csi) );
2623 ret = TranslateCharsetInfo( ULongToPtr(i), &csi, TCI_SRCCHARSET );
2624 if (ret)
2626 for (j = 0; j < ARRAY_SIZE(tests); j++)
2628 if (tests[j].ciCharset != i) continue;
2629 ok( !memcmp( &csi, &tests[j], sizeof(csi) ),
2630 "%lu: wrong info %u %u %08lx %08lx %08lx %08lx %08lx %08lx\n", i,
2631 csi.ciCharset, csi.ciACP, csi.fs.fsUsb[0], csi.fs.fsUsb[1],
2632 csi.fs.fsUsb[2], csi.fs.fsUsb[3], csi.fs.fsCsb[0], csi.fs.fsCsb[1] );
2633 break;
2635 ok( j < ARRAY_SIZE(tests), "%lu: TranslateCharsetInfo succeeded\n", i );
2637 else ok( !ret, "%lu: TranslateCharsetInfo succeeded\n", i );
2640 /* try all fontsigs */
2641 for (i = 0; i < 64; i++)
2643 DWORD csb[2] = { 0, 0 };
2644 csb[i / 32] = 1 << (i % 32);
2645 memset( &csi, 0xcc, sizeof(csi) );
2646 ret = TranslateCharsetInfo( csb, &csi, TCI_SRCFONTSIG );
2647 if (ret)
2649 for (j = 0; j < ARRAY_SIZE(tests); j++)
2651 if (tests[j].fs.fsCsb[0] != csb[0]) continue;
2652 ok( !memcmp( &csi, &tests[j], sizeof(csi) ),
2653 "%lu: wrong info %u %u %08lx %08lx %08lx %08lx %08lx %08lx\n", i,
2654 csi.ciCharset, csi.ciACP, csi.fs.fsUsb[0], csi.fs.fsUsb[1],
2655 csi.fs.fsUsb[2], csi.fs.fsUsb[3], csi.fs.fsCsb[0], csi.fs.fsCsb[1] );
2656 break;
2658 ok( j < ARRAY_SIZE(tests), "%lu: TranslateCharsetInfo succeeded\n", i );
2660 else ok( !ret, "%lu: TranslateCharsetInfo succeeded\n", i );
2664 static void test_font_charset(void)
2666 static struct charset_data
2668 INT charset;
2669 UINT code_page;
2670 WORD font_idxA[128], font_idxW[128];
2671 } cd[] =
2673 { ANSI_CHARSET, 1252 },
2674 { RUSSIAN_CHARSET, 1251 },
2675 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2677 int i;
2679 if (!is_font_installed("Arial"))
2681 skip("Arial is not installed\n");
2682 return;
2685 for (i = 0; i < ARRAY_SIZE(cd); i++)
2687 if (cd[i].charset == SYMBOL_CHARSET)
2689 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2691 skip("Symbol or Wingdings is not installed\n");
2692 break;
2695 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2696 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2697 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2700 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2701 if (i > 2)
2703 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2704 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2706 else
2707 skip("Symbol or Wingdings is not installed\n");
2710 static void test_GdiGetCodePage(void)
2712 static const struct _matching_data
2714 UINT current_codepage;
2715 LPCSTR lfFaceName;
2716 UCHAR lfCharSet;
2717 UINT expected_codepage;
2718 } matching_data[] = {
2719 {1251, "Arial", ANSI_CHARSET, 1252},
2720 {1251, "Tahoma", ANSI_CHARSET, 1252},
2722 {1252, "Arial", ANSI_CHARSET, 1252},
2723 {1252, "Tahoma", ANSI_CHARSET, 1252},
2725 {1253, "Arial", ANSI_CHARSET, 1252},
2726 {1253, "Tahoma", ANSI_CHARSET, 1252},
2728 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2729 { 932, "Tahoma", ANSI_CHARSET, 1252},
2730 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2732 { 936, "Arial", ANSI_CHARSET, 936},
2733 { 936, "Tahoma", ANSI_CHARSET, 936},
2734 { 936, "Simsun", ANSI_CHARSET, 936},
2736 { 949, "Arial", ANSI_CHARSET, 949},
2737 { 949, "Tahoma", ANSI_CHARSET, 949},
2738 { 949, "Gulim", ANSI_CHARSET, 949},
2740 { 950, "Arial", ANSI_CHARSET, 950},
2741 { 950, "Tahoma", ANSI_CHARSET, 950},
2742 { 950, "PMingLiU", ANSI_CHARSET, 950},
2744 HDC hdc;
2745 LOGFONTA lf;
2746 HFONT hfont;
2747 UINT acp;
2748 DWORD codepage;
2749 int i;
2751 if (!pGdiGetCodePage)
2753 skip("GdiGetCodePage not available on this platform\n");
2754 return;
2757 acp = GetACP();
2759 for (i = 0; i < ARRAY_SIZE(matching_data); i++)
2761 /* only test data matched current locale codepage */
2762 if (matching_data[i].current_codepage != acp)
2763 continue;
2765 if (!is_font_installed(matching_data[i].lfFaceName))
2767 skip("%s is not installed\n", matching_data[i].lfFaceName);
2768 continue;
2771 hdc = GetDC(0);
2773 memset(&lf, 0, sizeof(lf));
2774 lf.lfHeight = -16;
2775 lf.lfCharSet = matching_data[i].lfCharSet;
2776 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2777 hfont = CreateFontIndirectA(&lf);
2778 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
2780 hfont = SelectObject(hdc, hfont);
2781 codepage = pGdiGetCodePage(hdc);
2782 ok(codepage == matching_data[i].expected_codepage,
2783 "GdiGetCodePage should have returned %d, got %ld\n", matching_data[i].expected_codepage, codepage);
2785 hfont = SelectObject(hdc, hfont);
2786 DeleteObject(hfont);
2788 /* CLIP_DFA_DISABLE turns off the font association */
2789 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2790 hfont = CreateFontIndirectA(&lf);
2791 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
2793 hfont = SelectObject(hdc, hfont);
2794 codepage = pGdiGetCodePage(hdc);
2795 ok(codepage == 1252, "GdiGetCodePage returned %ld\n", codepage);
2797 hfont = SelectObject(hdc, hfont);
2798 DeleteObject(hfont);
2800 ReleaseDC(NULL, hdc);
2804 static void test_GetFontUnicodeRanges(void)
2806 LOGFONTA lf;
2807 HDC hdc;
2808 HFONT hfont, hfont_old;
2809 DWORD size;
2810 GLYPHSET *gs;
2812 memset(&lf, 0, sizeof(lf));
2813 lstrcpyA(lf.lfFaceName, "Arial");
2814 hfont = create_font("Arial", &lf);
2816 hdc = GetDC(0);
2817 hfont_old = SelectObject(hdc, hfont);
2819 size = GetFontUnicodeRanges(NULL, NULL);
2820 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2822 size = GetFontUnicodeRanges(hdc, NULL);
2823 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2825 gs = heap_alloc_zero(size);
2827 size = GetFontUnicodeRanges(hdc, gs);
2828 ok(size, "GetFontUnicodeRanges failed\n");
2829 ok(gs->cRanges, "Unexpected ranges count.\n");
2831 heap_free(gs);
2833 SelectObject(hdc, hfont_old);
2834 DeleteObject(hfont);
2835 ReleaseDC(NULL, hdc);
2838 struct enum_font_data
2840 int total, size;
2841 LOGFONTA *lf;
2844 struct enum_fullname_data
2846 int total, size;
2847 ENUMLOGFONTA *elf;
2850 struct enum_fullname_data_w
2852 int total, size;
2853 ENUMLOGFONTW *elf;
2856 struct enum_font_dataW
2858 int total, size;
2859 LOGFONTW *lf;
2862 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2864 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2865 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2867 ok(lf->lfHeight == tm->tmHeight, "lfHeight %ld != tmHeight %ld\n", lf->lfHeight, tm->tmHeight);
2869 if (type != TRUETYPE_FONTTYPE) return 1;
2871 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2873 if (efd->total >= efd->size)
2875 efd->size = max( (efd->total + 1) * 2, 256 );
2876 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2877 if (!efd->lf) return 0;
2879 efd->lf[efd->total++] = *lf;
2881 return 1;
2884 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2886 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2887 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2889 ok(lf->lfHeight == tm->tmHeight, "lfHeight %ld != tmHeight %ld\n", lf->lfHeight, tm->tmHeight);
2891 if (type != TRUETYPE_FONTTYPE) return 1;
2893 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2895 if (efd->total >= efd->size)
2897 efd->size = max( (efd->total + 1) * 2, 256 );
2898 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2899 if (!efd->lf) return 0;
2901 efd->lf[efd->total++] = *lf;
2903 return 1;
2906 static void get_charset_stats(struct enum_font_data *efd,
2907 int *ansi_charset, int *symbol_charset,
2908 int *russian_charset)
2910 int i;
2912 *ansi_charset = 0;
2913 *symbol_charset = 0;
2914 *russian_charset = 0;
2916 for (i = 0; i < efd->total; i++)
2918 switch (efd->lf[i].lfCharSet)
2920 case ANSI_CHARSET:
2921 (*ansi_charset)++;
2922 break;
2923 case SYMBOL_CHARSET:
2924 (*symbol_charset)++;
2925 break;
2926 case RUSSIAN_CHARSET:
2927 (*russian_charset)++;
2928 break;
2933 static void get_charset_statsW(struct enum_font_dataW *efd,
2934 int *ansi_charset, int *symbol_charset,
2935 int *russian_charset)
2937 int i;
2939 *ansi_charset = 0;
2940 *symbol_charset = 0;
2941 *russian_charset = 0;
2943 for (i = 0; i < efd->total; i++)
2945 switch (efd->lf[i].lfCharSet)
2947 case ANSI_CHARSET:
2948 (*ansi_charset)++;
2949 break;
2950 case SYMBOL_CHARSET:
2951 (*symbol_charset)++;
2952 break;
2953 case RUSSIAN_CHARSET:
2954 (*russian_charset)++;
2955 break;
2960 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2962 struct enum_font_data efd;
2963 struct enum_font_dataW efdw;
2964 LOGFONTA lf;
2965 HDC hdc;
2966 int i, ret, ansi_charset, symbol_charset, russian_charset;
2968 if (*font_name && !is_truetype_font_installed(font_name))
2970 skip("%s is not installed\n", font_name);
2971 return;
2973 memset( &efd, 0, sizeof(efd) );
2974 memset( &efdw, 0, sizeof(efdw) );
2976 hdc = GetDC(0);
2978 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2979 * while EnumFontFamiliesEx doesn't.
2981 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2984 * Use EnumFontFamiliesW since win98 crashes when the
2985 * second parameter is NULL using EnumFontFamilies
2987 efdw.total = 0;
2988 SetLastError(0xdeadbeef);
2989 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2990 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %lu\n", GetLastError());
2991 if(ret)
2993 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2994 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2995 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2996 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2997 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
3000 efdw.total = 0;
3001 SetLastError(0xdeadbeef);
3002 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
3003 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %lu\n", GetLastError());
3004 if(ret)
3006 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
3007 ok(efdw.total > 0, "fonts enumerated: NULL\n");
3008 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
3009 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3010 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
3014 efd.total = 0;
3015 SetLastError(0xdeadbeef);
3016 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
3017 ok(ret, "EnumFontFamilies error %lu\n", GetLastError());
3018 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3019 if (*font_name)
3020 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
3021 else
3022 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
3023 for (i = 0; i < efd.total; i++)
3025 /* FIXME: remove completely once Wine is fixed */
3026 todo_wine_if(efd.lf[i].lfCharSet != font_charset)
3027 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3028 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3029 font_name, efd.lf[i].lfFaceName);
3032 memset(&lf, 0, sizeof(lf));
3033 lf.lfCharSet = ANSI_CHARSET;
3034 strcpy(lf.lfFaceName, font_name);
3035 efd.total = 0;
3036 SetLastError(0xdeadbeef);
3037 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3038 ok(ret, "EnumFontFamiliesEx error %lu\n", GetLastError());
3039 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3040 if (font_charset == SYMBOL_CHARSET)
3042 if (*font_name)
3043 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
3044 else
3045 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
3047 else
3049 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
3050 for (i = 0; i < efd.total; i++)
3052 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3053 if (*font_name)
3054 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3055 font_name, efd.lf[i].lfFaceName);
3059 /* DEFAULT_CHARSET should enumerate all available charsets */
3060 memset(&lf, 0, sizeof(lf));
3061 lf.lfCharSet = DEFAULT_CHARSET;
3062 strcpy(lf.lfFaceName, font_name);
3063 efd.total = 0;
3064 SetLastError(0xdeadbeef);
3065 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3066 ok(ret, "EnumFontFamiliesEx error %lu\n", GetLastError());
3067 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3068 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
3069 for (i = 0; i < efd.total; i++)
3071 if (*font_name)
3072 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3073 font_name, efd.lf[i].lfFaceName);
3075 if (*font_name)
3077 switch (font_charset)
3079 case ANSI_CHARSET:
3080 ok(ansi_charset > 0,
3081 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3082 ok(!symbol_charset,
3083 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
3084 ok(russian_charset > 0,
3085 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3086 break;
3087 case SYMBOL_CHARSET:
3088 ok(!ansi_charset,
3089 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
3090 ok(symbol_charset,
3091 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3092 ok(!russian_charset,
3093 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
3094 break;
3095 case DEFAULT_CHARSET:
3096 ok(ansi_charset > 0,
3097 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3098 ok(symbol_charset > 0,
3099 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3100 ok(russian_charset > 0,
3101 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3102 break;
3105 else
3107 ok(ansi_charset > 0,
3108 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3109 ok(symbol_charset > 0,
3110 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3111 ok(russian_charset > 0,
3112 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3115 memset(&lf, 0, sizeof(lf));
3116 lf.lfCharSet = SYMBOL_CHARSET;
3117 strcpy(lf.lfFaceName, font_name);
3118 efd.total = 0;
3119 SetLastError(0xdeadbeef);
3120 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3121 ok(ret, "EnumFontFamiliesEx error %lu\n", GetLastError());
3122 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3123 if (*font_name && font_charset == ANSI_CHARSET)
3124 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
3125 else
3127 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
3128 for (i = 0; i < efd.total; i++)
3130 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3131 if (*font_name)
3132 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3133 font_name, efd.lf[i].lfFaceName);
3136 ok(!ansi_charset,
3137 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3138 ok(symbol_charset > 0,
3139 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3140 ok(!russian_charset,
3141 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3144 ReleaseDC(0, hdc);
3146 heap_free( efd.lf );
3147 heap_free( efdw.lf );
3150 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
3152 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
3153 LOGFONTA *target = (LOGFONTA *)lParam;
3154 const DWORD valid_bits = 0x003f01ff;
3155 CHARSETINFO csi;
3156 DWORD fs;
3158 if (type != TRUETYPE_FONTTYPE) return TRUE;
3160 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
3161 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
3162 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
3163 *target = *lf;
3164 return FALSE;
3168 return TRUE;
3171 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3173 struct enum_font_data *efd = (struct enum_font_data *)lParam;
3175 if (type != TRUETYPE_FONTTYPE) return 1;
3177 if (efd->total >= efd->size)
3179 efd->size = max( (efd->total + 1) * 2, 256 );
3180 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
3181 if (!efd->lf) return 0;
3183 efd->lf[efd->total++] = *lf;
3185 return 1;
3188 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3190 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3192 if (type != TRUETYPE_FONTTYPE) return 1;
3194 if (efnd->total >= efnd->size)
3196 efnd->size = max( (efnd->total + 1) * 2, 256 );
3197 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
3198 if (!efnd->elf) return 0;
3200 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3202 return 1;
3205 static INT CALLBACK enum_fullname_data_proc_w( const LOGFONTW *lf, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam )
3207 struct enum_fullname_data_w *efnd = (struct enum_fullname_data_w *)lParam;
3209 if (type != TRUETYPE_FONTTYPE) return 1;
3211 if (efnd->total >= efnd->size)
3213 efnd->size = max( (efnd->total + 1) * 2, 256 );
3214 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
3215 if (!efnd->elf) return 0;
3217 efnd->elf[efnd->total++] = *(ENUMLOGFONTW *)lf;
3219 return 1;
3222 static void test_EnumFontFamiliesEx_default_charset(void)
3224 struct enum_font_data efd;
3225 LOGFONTA target, enum_font;
3226 UINT acp;
3227 HDC hdc;
3228 CHARSETINFO csi;
3230 acp = GetACP();
3231 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3232 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3233 return;
3236 hdc = GetDC(0);
3237 memset(&enum_font, 0, sizeof(enum_font));
3238 enum_font.lfCharSet = csi.ciCharset;
3239 target.lfFaceName[0] = '\0';
3240 target.lfCharSet = csi.ciCharset;
3241 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3242 if (target.lfFaceName[0] == '\0') {
3243 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3244 return;
3246 if (acp == 874 || acp == 1255 || acp == 1256) {
3247 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3248 target.lfCharSet = ANSI_CHARSET;
3251 memset(&efd, 0, sizeof(efd));
3252 memset(&enum_font, 0, sizeof(enum_font));
3253 strcpy(enum_font.lfFaceName, target.lfFaceName);
3254 enum_font.lfCharSet = DEFAULT_CHARSET;
3255 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3256 ReleaseDC(0, hdc);
3258 if (efd.total < 2)
3259 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3260 else
3261 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3262 "(%s) got charset %d expected %d\n",
3263 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3265 heap_free(efd.lf);
3266 return;
3269 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3271 HFONT hfont, hfont_prev;
3272 DWORD ret;
3273 GLYPHMETRICS gm1, gm2;
3274 LOGFONTA lf2 = *lf;
3275 WORD idx;
3277 /* negative widths are handled just as positive ones */
3278 lf2.lfWidth = -lf->lfWidth;
3280 SetLastError(0xdeadbeef);
3281 hfont = CreateFontIndirectA(lf);
3282 ok(hfont != 0, "CreateFontIndirect error %lu\n", GetLastError());
3283 check_font("original", lf, hfont);
3285 hfont_prev = SelectObject(hdc, hfont);
3287 ret = GetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3288 if (ret == GDI_ERROR || idx == 0xffff)
3290 SelectObject(hdc, hfont_prev);
3291 DeleteObject(hfont);
3292 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3293 return;
3296 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3297 memset(&gm1, 0xab, sizeof(gm1));
3298 SetLastError(0xdeadbeef);
3299 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3300 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%lx\n", GetLastError());
3302 SelectObject(hdc, hfont_prev);
3303 DeleteObject(hfont);
3305 SetLastError(0xdeadbeef);
3306 hfont = CreateFontIndirectA(&lf2);
3307 ok(hfont != 0, "CreateFontIndirect error %lu\n", GetLastError());
3308 check_font("negative width", &lf2, hfont);
3310 hfont_prev = SelectObject(hdc, hfont);
3312 memset(&gm2, 0xbb, sizeof(gm2));
3313 SetLastError(0xdeadbeef);
3314 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3315 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%lx\n", GetLastError());
3317 SelectObject(hdc, hfont_prev);
3318 DeleteObject(hfont);
3320 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3321 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3322 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3323 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3324 gm1.gmCellIncX == gm2.gmCellIncX &&
3325 gm1.gmCellIncY == gm2.gmCellIncY,
3326 "gm1=%d,%d,%ld,%ld,%d,%d gm2=%d,%d,%ld,%ld,%d,%d\n",
3327 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3328 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3329 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3330 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3333 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3334 #include "pshpack2.h"
3335 typedef struct
3337 USHORT version;
3338 SHORT xAvgCharWidth;
3339 USHORT usWeightClass;
3340 USHORT usWidthClass;
3341 SHORT fsType;
3342 SHORT ySubscriptXSize;
3343 SHORT ySubscriptYSize;
3344 SHORT ySubscriptXOffset;
3345 SHORT ySubscriptYOffset;
3346 SHORT ySuperscriptXSize;
3347 SHORT ySuperscriptYSize;
3348 SHORT ySuperscriptXOffset;
3349 SHORT ySuperscriptYOffset;
3350 SHORT yStrikeoutSize;
3351 SHORT yStrikeoutPosition;
3352 SHORT sFamilyClass;
3353 PANOSE panose;
3354 ULONG ulUnicodeRange1;
3355 ULONG ulUnicodeRange2;
3356 ULONG ulUnicodeRange3;
3357 ULONG ulUnicodeRange4;
3358 CHAR achVendID[4];
3359 USHORT fsSelection;
3360 USHORT usFirstCharIndex;
3361 USHORT usLastCharIndex;
3362 /* According to the Apple spec, original version didn't have the below fields,
3363 * version numbers were taken from the OpenType spec.
3365 /* version 0 (TrueType 1.5) */
3366 USHORT sTypoAscender;
3367 USHORT sTypoDescender;
3368 USHORT sTypoLineGap;
3369 USHORT usWinAscent;
3370 USHORT usWinDescent;
3371 /* version 1 (TrueType 1.66) */
3372 ULONG ulCodePageRange1;
3373 ULONG ulCodePageRange2;
3374 /* version 2 (OpenType 1.2) */
3375 SHORT sxHeight;
3376 SHORT sCapHeight;
3377 USHORT usDefaultChar;
3378 USHORT usBreakChar;
3379 USHORT usMaxContext;
3380 /* version 4 (OpenType 1.6) */
3381 USHORT usLowerOpticalPointSize;
3382 USHORT usUpperOpticalPointSize;
3383 } TT_OS2_V4;
3384 #include "poppack.h"
3386 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3388 typedef struct
3390 USHORT version;
3391 USHORT num_tables;
3392 } cmap_header;
3394 typedef struct
3396 USHORT plat_id;
3397 USHORT enc_id;
3398 ULONG offset;
3399 } cmap_encoding_record;
3401 typedef struct
3403 USHORT format;
3404 USHORT length;
3405 USHORT language;
3407 BYTE glyph_ids[256];
3408 } cmap_format_0;
3410 typedef struct
3412 USHORT format;
3413 USHORT length;
3414 USHORT language;
3416 USHORT seg_countx2;
3417 USHORT search_range;
3418 USHORT entry_selector;
3419 USHORT range_shift;
3421 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3422 /* Then follows:
3423 USHORT pad;
3424 USHORT start_count[seg_countx2 / 2];
3425 USHORT id_delta[seg_countx2 / 2];
3426 USHORT id_range_offset[seg_countx2 / 2];
3427 USHORT glyph_ids[];
3429 } cmap_format_4;
3431 typedef struct
3433 USHORT end_count;
3434 USHORT start_count;
3435 USHORT id_delta;
3436 USHORT id_range_offset;
3437 } cmap_format_4_seg;
3439 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V4 *os2, WORD family, const char *name)
3441 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3442 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3443 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3444 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3445 os2->panose.bWeight, os2->panose.bProportion);
3448 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3450 int i;
3451 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3453 *first = 256;
3455 for(i = 0; i < 256; i++)
3457 if(cmap->glyph_ids[i] == 0) continue;
3458 *last = i;
3459 if(*first == 256) *first = i;
3461 if(*first == 256) return FALSE;
3462 return TRUE;
3465 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3467 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3468 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3469 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3470 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3471 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3474 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3476 int i;
3477 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3478 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3480 *first = 0x10000;
3482 for(i = 0; i < seg_count; i++)
3484 cmap_format_4_seg seg;
3486 get_seg4(cmap, i, &seg);
3488 if(seg.start_count > 0xfffe) break;
3490 if(*first == 0x10000) *first = seg.start_count;
3492 *last = min(seg.end_count, 0xfffe);
3495 if(*first == 0x10000) return FALSE;
3496 return TRUE;
3499 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3501 USHORT i;
3502 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3504 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3506 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3507 return (BYTE *)header + GET_BE_DWORD(record->offset);
3508 record++;
3510 return NULL;
3513 typedef enum
3515 cmap_none,
3516 cmap_ms_unicode,
3517 cmap_ms_symbol
3518 } cmap_type;
3520 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3522 LONG size, ret;
3523 cmap_header *header;
3524 void *cmap;
3525 BOOL r = FALSE;
3526 WORD format;
3528 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3529 ok(size != GDI_ERROR, "no cmap table found\n");
3530 if(size == GDI_ERROR) return FALSE;
3532 header = HeapAlloc(GetProcessHeap(), 0, size);
3533 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3534 ok(ret == size, "GetFontData should return %lu not %lu\n", size, ret);
3535 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3537 cmap = get_cmap(header, 3, 1);
3538 if(cmap)
3539 *cmap_type = cmap_ms_unicode;
3540 else
3542 cmap = get_cmap(header, 3, 0);
3543 if(cmap) *cmap_type = cmap_ms_symbol;
3545 if(!cmap)
3547 *cmap_type = cmap_none;
3548 goto end;
3551 format = GET_BE_WORD(*(WORD *)cmap);
3552 switch(format)
3554 case 0:
3555 r = get_first_last_from_cmap0(cmap, first, last);
3556 break;
3557 case 4:
3558 r = get_first_last_from_cmap4(cmap, first, last, size);
3559 break;
3560 default:
3561 skip("unhandled cmap format %d\n", format);
3562 break;
3565 end:
3566 HeapFree(GetProcessHeap(), 0, header);
3567 return r;
3570 #define TT_PLATFORM_APPLE_UNICODE 0
3571 #define TT_PLATFORM_MACINTOSH 1
3572 #define TT_PLATFORM_MICROSOFT 3
3573 #define TT_APPLE_ID_DEFAULT 0
3574 #define TT_APPLE_ID_ISO_10646 2
3575 #define TT_APPLE_ID_UNICODE_2_0 3
3576 #define TT_MS_ID_SYMBOL_CS 0
3577 #define TT_MS_ID_UNICODE_CS 1
3578 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3579 #define TT_NAME_ID_FONT_FAMILY 1
3580 #define TT_NAME_ID_FONT_SUBFAMILY 2
3581 #define TT_NAME_ID_UNIQUE_ID 3
3582 #define TT_NAME_ID_FULL_NAME 4
3583 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3585 typedef struct sfnt_name
3587 USHORT platform_id;
3588 USHORT encoding_id;
3589 USHORT language_id;
3590 USHORT name_id;
3591 USHORT length;
3592 USHORT offset;
3593 } sfnt_name;
3595 static const LANGID mac_langid_table[] =
3597 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3598 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3599 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3600 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3601 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3602 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3603 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3604 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3605 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3606 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3607 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3608 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3609 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3610 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3611 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3612 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3613 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3614 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3615 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3616 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3617 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3618 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3619 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3620 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3621 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3622 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3623 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3624 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3625 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3626 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3627 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3628 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3629 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3630 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3631 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3632 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3633 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3634 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3635 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3636 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3637 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3638 0, /* TT_MAC_LANGID_YIDDISH */
3639 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3640 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3641 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3642 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3643 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3644 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3645 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3646 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3647 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3648 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3649 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3650 0, /* TT_MAC_LANGID_MOLDAVIAN */
3651 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3652 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3653 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3654 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3655 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3656 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3657 0, /* TT_MAC_LANGID_KURDISH */
3658 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3659 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3660 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3661 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3662 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3663 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3664 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3665 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3666 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3667 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3668 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3669 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3670 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3671 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3672 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3673 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3674 0, /* TT_MAC_LANGID_BURMESE */
3675 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3676 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3677 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3678 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3679 0, /* TT_MAC_LANGID_TAGALOG */
3680 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3681 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3682 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3683 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3684 0, /* TT_MAC_LANGID_GALLA */
3685 0, /* TT_MAC_LANGID_SOMALI */
3686 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3687 0, /* TT_MAC_LANGID_RUANDA */
3688 0, /* TT_MAC_LANGID_RUNDI */
3689 0, /* TT_MAC_LANGID_CHEWA */
3690 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3691 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3692 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3693 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3694 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3695 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3696 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3697 0, /* TT_MAC_LANGID_LATIN */
3698 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3699 0, /* TT_MAC_LANGID_GUARANI */
3700 0, /* TT_MAC_LANGID_AYMARA */
3701 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3702 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3703 0, /* TT_MAC_LANGID_DZONGKHA */
3704 0, /* TT_MAC_LANGID_JAVANESE */
3705 0, /* TT_MAC_LANGID_SUNDANESE */
3706 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3707 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3708 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3709 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3710 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3711 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3712 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3713 0, /* TT_MAC_LANGID_TONGAN */
3714 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3715 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3716 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3719 static inline WORD get_mac_code_page( const sfnt_name *name )
3721 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3722 return 10000 + GET_BE_WORD(name->encoding_id);
3725 static int match_name_table_language( const sfnt_name *name, LANGID lang )
3727 LANGID name_lang;
3728 int res = 0;
3730 switch (GET_BE_WORD(name->platform_id))
3732 case TT_PLATFORM_MICROSOFT:
3733 res += 5; /* prefer the Microsoft name */
3734 switch (GET_BE_WORD(name->encoding_id))
3736 case TT_MS_ID_UNICODE_CS:
3737 case TT_MS_ID_SYMBOL_CS:
3738 name_lang = GET_BE_WORD(name->language_id);
3739 break;
3740 default:
3741 return 0;
3743 break;
3744 case TT_PLATFORM_MACINTOSH:
3745 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3746 if (GET_BE_WORD(name->language_id) >= ARRAY_SIZE(mac_langid_table)) return 0;
3747 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3748 break;
3749 case TT_PLATFORM_APPLE_UNICODE:
3750 res += 2; /* prefer Unicode encodings */
3751 switch (GET_BE_WORD(name->encoding_id))
3753 case TT_APPLE_ID_DEFAULT:
3754 case TT_APPLE_ID_ISO_10646:
3755 case TT_APPLE_ID_UNICODE_2_0:
3756 if (GET_BE_WORD(name->language_id) >= ARRAY_SIZE(mac_langid_table)) return 0;
3757 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3758 break;
3759 default:
3760 return 0;
3762 break;
3763 default:
3764 return 0;
3766 if (name_lang == lang) res += 30;
3767 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3768 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3769 return res;
3772 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3774 struct sfnt_name_header
3776 USHORT format;
3777 USHORT number_of_record;
3778 USHORT storage_offset;
3779 } *header;
3780 sfnt_name *entry;
3781 BOOL r = FALSE;
3782 LONG size, offset, length;
3783 LONG c, ret;
3784 WCHAR *name;
3785 BYTE *data;
3786 USHORT i;
3787 int res, best_lang = 0, best_index = -1;
3789 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3790 ok(size != GDI_ERROR, "no name table found\n");
3791 if(size == GDI_ERROR) return FALSE;
3793 data = HeapAlloc(GetProcessHeap(), 0, size);
3794 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3795 ok(ret == size, "GetFontData should return %lu not %lu\n", size, ret);
3797 header = (void *)data;
3798 header->format = GET_BE_WORD(header->format);
3799 header->number_of_record = GET_BE_WORD(header->number_of_record);
3800 header->storage_offset = GET_BE_WORD(header->storage_offset);
3801 if (header->format != 0)
3803 skip("got format %u\n", header->format);
3804 goto out;
3806 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3808 skip("number records out of range: %d\n", header->number_of_record);
3809 goto out;
3811 if (header->storage_offset >= size)
3813 skip("storage_offset %u > size %lu\n", header->storage_offset, size);
3814 goto out;
3817 entry = (void *)&header[1];
3818 for (i = 0; i < header->number_of_record; i++)
3820 if (GET_BE_WORD(entry[i].name_id) != name_id) continue;
3821 res = match_name_table_language( &entry[i], language_id);
3822 if (res > best_lang)
3824 best_lang = res;
3825 best_index = i;
3829 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset);
3830 length = GET_BE_WORD(entry[best_index].length);
3831 if (offset + length > size)
3833 skip("entry %d is out of range\n", best_index);
3834 goto out;
3836 if (length >= out_size)
3838 skip("buffer too small for entry %d\n", best_index);
3839 goto out;
3842 name = (WCHAR *)(data + offset);
3843 for (c = 0; c < length / 2; c++)
3844 out_buf[c] = GET_BE_WORD(name[c]);
3845 out_buf[c] = 0;
3847 r = TRUE;
3849 out:
3850 HeapFree(GetProcessHeap(), 0, data);
3851 return r;
3854 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3856 HDC hdc;
3857 HFONT hfont, hfont_old;
3858 TEXTMETRICA tmA;
3859 TT_OS2_V4 tt_os2;
3860 LONG size, ret;
3861 const char *font_name = lf->lfFaceName;
3862 DWORD cmap_first = 0, cmap_last = 0;
3863 UINT ascent, descent, cell_height;
3864 cmap_type cmap_type;
3865 BOOL sys_lang_non_english;
3867 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3868 hdc = GetDC(0);
3870 SetLastError(0xdeadbeef);
3871 hfont = CreateFontIndirectA(lf);
3872 ok(hfont != 0, "CreateFontIndirect error %lu\n", GetLastError());
3874 hfont_old = SelectObject(hdc, hfont);
3876 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3877 if (size == GDI_ERROR)
3879 trace("OS/2 chunk was not found\n");
3880 goto end_of_test;
3882 if (size > sizeof(tt_os2))
3884 trace("got too large OS/2 chunk of size %lu\n", size);
3885 size = sizeof(tt_os2);
3888 memset(&tt_os2, 0, sizeof(tt_os2));
3889 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3890 ok(ret >= TT_OS2_V0_SIZE && ret <= size, "GetFontData should return size from [%lu,%lu] not %lu\n", TT_OS2_V0_SIZE,
3891 size, ret);
3893 SetLastError(0xdeadbeef);
3894 ret = GetTextMetricsA(hdc, &tmA);
3895 ok(ret, "GetTextMetricsA error %lu\n", GetLastError());
3897 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3899 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3901 else
3903 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3904 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3905 UINT os2_first_char, os2_last_char, default_char, break_char;
3906 USHORT version;
3907 TEXTMETRICW tmW;
3909 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3910 descent = abs((SHORT)GET_BE_WORD(tt_os2.usWinDescent));
3911 cell_height = ascent + descent;
3912 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3913 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3915 /* NEWTEXTMETRIC's scaling method is different from TEXTMETRIC's */
3916 #define SCALE_NTM(value) (MulDiv(ntm->tmHeight, (value), cell_height))
3917 size = MulDiv(32, ntm->ntmCellHeight, ntm->ntmSizeEM);
3918 ok(ntm->tmHeight == size, "%s: ntm->tmHeight %ld != %ld (%u/%u)\n",
3919 font_name, ntm->tmHeight, size, ntm->ntmCellHeight, ntm->ntmSizeEM);
3920 size = SCALE_NTM(ntm->ntmAvgWidth);
3921 ok(ntm->tmAveCharWidth == size, "%s: ntm->tmAveCharWidth %ld != %ld (%u/%u,%ld)\n",
3922 font_name, ntm->tmAveCharWidth, size, ntm->ntmAvgWidth, cell_height, ntm->tmHeight);
3923 size = SCALE_NTM(ascent);
3924 ok(ntm->tmAscent == size, "%s: ntm->tmAscent %ld != %ld (%u/%u,%ld)\n",
3925 font_name, ntm->tmAscent, size, ascent, cell_height, ntm->tmHeight);
3926 size = ntm->tmHeight - ntm->tmAscent;
3927 ok(ntm->tmDescent == size, "%s: ntm->tmDescent %ld != %ld (%u/%u,%ld)\n",
3928 font_name, ntm->tmDescent, size, descent, cell_height, ntm->tmHeight);
3929 size = SCALE_NTM(cell_height - ntm->ntmSizeEM);
3930 ok(ntm->tmInternalLeading == size, "%s: ntm->tmInternalLeading %ld != %ld (%u/%u,%ld)\n",
3931 font_name, ntm->tmInternalLeading, size, cell_height - ntm->ntmSizeEM, cell_height, ntm->tmHeight);
3932 #undef SCALE_NTM
3934 version = GET_BE_WORD(tt_os2.version);
3936 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3937 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3938 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3939 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3941 if (winetest_debug > 1)
3942 trace("font %s charset %u: %x-%x (%lx-%lx) default %x break %x OS/2 version %u vendor %4.4s\n",
3943 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3944 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3946 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3948 expect_first_W = 0;
3949 switch(GetACP())
3951 case 1255: /* Hebrew */
3952 expect_last_W = 0xf896;
3953 break;
3954 case 1257: /* Baltic */
3955 expect_last_W = 0xf8fd;
3956 break;
3957 default:
3958 expect_last_W = 0xf0ff;
3960 expect_break_W = 0x20;
3961 expect_default_W = expect_break_W - 1;
3962 expect_first_A = 0x1e;
3963 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3965 else
3967 expect_first_W = cmap_first;
3968 expect_last_W = cmap_last;
3969 if(os2_first_char <= 1)
3970 expect_break_W = os2_first_char + 2;
3971 else if(os2_first_char > 0xff)
3972 expect_break_W = 0x20;
3973 else
3974 expect_break_W = os2_first_char;
3975 expect_default_W = expect_break_W - 1;
3976 expect_first_A = expect_default_W - 1;
3977 expect_last_A = min(os2_last_char, 0xff);
3979 expect_break_A = expect_break_W;
3980 expect_default_A = expect_default_W;
3982 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3983 todo_wine_if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3984 ok(tmA.tmFirstChar == expect_first_A,
3985 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3986 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3987 todo_wine_if(expect_last_A != 0 && expect_last_A != 0xff) ok(tmA.tmLastChar == expect_last_A,
3988 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3989 else
3990 skip("tmLastChar is DBCS lead byte\n");
3991 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3992 font_name, tmA.tmBreakChar, expect_break_A);
3993 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3994 "A: tmDefaultChar for %s got %02x expected %02x\n",
3995 font_name, tmA.tmDefaultChar, expect_default_A);
3998 SetLastError(0xdeadbeef);
3999 ret = GetTextMetricsW(hdc, &tmW);
4000 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
4001 "GetTextMetricsW error %lu\n", GetLastError());
4002 if (ret)
4004 /* Wine uses the os2 first char */
4005 todo_wine_if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
4006 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
4007 font_name, tmW.tmFirstChar, expect_first_W);
4009 /* Wine uses the os2 last char */
4010 todo_wine_if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
4011 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
4012 font_name, tmW.tmLastChar, expect_last_W);
4013 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
4014 font_name, tmW.tmBreakChar, expect_break_W);
4015 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
4016 "W: tmDefaultChar for %s got %02x expected %02x\n",
4017 font_name, tmW.tmDefaultChar, expect_default_W);
4019 /* Test the aspect ratio while we have tmW */
4020 ret = GetDeviceCaps(hdc, LOGPIXELSX);
4021 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %lu != %lu\n",
4022 tmW.tmDigitizedAspectX, ret);
4023 ret = GetDeviceCaps(hdc, LOGPIXELSY);
4024 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %lu != %lu\n",
4025 tmW.tmDigitizedAspectX, ret);
4029 /* test FF_ values */
4030 switch(tt_os2.panose.bFamilyType)
4032 case PAN_ANY:
4033 case PAN_NO_FIT:
4034 case PAN_FAMILY_TEXT_DISPLAY:
4035 case PAN_FAMILY_PICTORIAL:
4036 default:
4037 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
4038 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
4040 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
4041 break;
4043 switch(tt_os2.panose.bSerifStyle)
4045 case PAN_ANY:
4046 case PAN_NO_FIT:
4047 default:
4048 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
4049 break;
4051 case PAN_SERIF_COVE:
4052 case PAN_SERIF_OBTUSE_COVE:
4053 case PAN_SERIF_SQUARE_COVE:
4054 case PAN_SERIF_OBTUSE_SQUARE_COVE:
4055 case PAN_SERIF_SQUARE:
4056 case PAN_SERIF_THIN:
4057 case PAN_SERIF_BONE:
4058 case PAN_SERIF_EXAGGERATED:
4059 case PAN_SERIF_TRIANGLE:
4060 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
4061 break;
4063 case PAN_SERIF_NORMAL_SANS:
4064 case PAN_SERIF_OBTUSE_SANS:
4065 case PAN_SERIF_PERP_SANS:
4066 case PAN_SERIF_FLARED:
4067 case PAN_SERIF_ROUNDED:
4068 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
4069 break;
4071 break;
4073 case PAN_FAMILY_SCRIPT:
4074 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
4075 break;
4077 case PAN_FAMILY_DECORATIVE:
4078 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
4079 break;
4082 test_negative_width(hdc, lf);
4084 end_of_test:
4085 SelectObject(hdc, hfont_old);
4086 DeleteObject(hfont);
4088 ReleaseDC(0, hdc);
4091 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4093 INT *enumed = (INT *)lParam;
4095 if (type == TRUETYPE_FONTTYPE)
4097 (*enumed)++;
4098 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
4100 return 1;
4103 static void test_GetTextMetrics(void)
4105 HFONT old_hf, hf;
4106 TEXTMETRICA tm;
4107 LOGFONTA lf;
4108 BOOL ret;
4109 HDC hdc;
4110 INT enumed;
4112 hdc = GetDC(0);
4114 memset(&lf, 0, sizeof(lf));
4115 lf.lfCharSet = DEFAULT_CHARSET;
4116 enumed = 0;
4117 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
4119 /* Test a bug triggered by rounding up FreeType ppem */
4120 hf = CreateFontA(20, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
4121 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
4122 "Tahoma");
4123 ok(hf != NULL, "CreateFontA failed, error %lu\n", GetLastError());
4124 old_hf = SelectObject(hdc, hf);
4125 ret = GetTextMetricsA(hdc, &tm);
4126 ok(ret, "GetTextMetricsA failed, error %lu\n", GetLastError());
4127 ok(tm.tmHeight <= 20, "Got unexpected tmHeight %ld\n", tm.tmHeight);
4128 SelectObject(hdc, old_hf);
4129 DeleteObject(hf);
4131 ReleaseDC(0, hdc);
4134 static void test_nonexistent_font(void)
4136 static const struct
4138 const char *name;
4139 int charset;
4140 } font_subst[] =
4142 { "Times New Roman Baltic", 186 },
4143 { "Times New Roman CE", 238 },
4144 { "Times New Roman CYR", 204 },
4145 { "Times New Roman Greek", 161 },
4146 { "Times New Roman TUR", 162 }
4148 static const struct
4150 const char *name;
4151 int charset;
4152 } shell_subst[] =
4154 { "MS Shell Dlg", 186 },
4155 { "MS Shell Dlg", 238 },
4156 { "MS Shell Dlg", 204 },
4157 { "MS Shell Dlg", 161 },
4158 { "MS Shell Dlg", 162 }
4160 LOGFONTA lf;
4161 HDC hdc;
4162 HFONT hfont;
4163 CHARSETINFO csi;
4164 INT cs, expected_cs, i, ret;
4165 char buf[LF_FACESIZE];
4167 expected_cs = GetACP();
4168 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
4170 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
4171 return;
4173 expected_cs = csi.ciCharset;
4174 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
4176 hdc = CreateCompatibleDC(0);
4178 for (i = 0; i < ARRAY_SIZE(shell_subst); i++)
4180 ret = is_font_installed(shell_subst[i].name);
4181 ok(ret, "%s should be enumerated\n", shell_subst[i].name);
4182 ret = is_truetype_font_installed(shell_subst[i].name);
4183 ok(ret, "%s should be enumerated\n", shell_subst[i].name);
4185 memset(&lf, 0, sizeof(lf));
4186 lf.lfHeight = -13;
4187 lf.lfWeight = FW_REGULAR;
4188 strcpy(lf.lfFaceName, shell_subst[i].name);
4189 hfont = CreateFontIndirectA(&lf);
4190 hfont = SelectObject(hdc, hfont);
4191 GetTextFaceA(hdc, sizeof(buf), buf);
4192 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4193 cs = GetTextCharset(hdc);
4194 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name);
4196 DeleteObject(SelectObject(hdc, hfont));
4198 memset(&lf, 0, sizeof(lf));
4199 lf.lfHeight = -13;
4200 lf.lfWeight = FW_DONTCARE;
4201 strcpy(lf.lfFaceName, shell_subst[i].name);
4202 hfont = CreateFontIndirectA(&lf);
4203 hfont = SelectObject(hdc, hfont);
4204 GetTextFaceA(hdc, sizeof(buf), buf);
4205 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4206 cs = GetTextCharset(hdc);
4207 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name);
4208 DeleteObject(SelectObject(hdc, hfont));
4211 if (!is_truetype_font_installed("Arial") ||
4212 !is_truetype_font_installed("Times New Roman"))
4214 DeleteDC(hdc);
4215 skip("Arial or Times New Roman not installed\n");
4216 return;
4219 memset(&lf, 0, sizeof(lf));
4220 lf.lfHeight = 100;
4221 lf.lfWeight = FW_REGULAR;
4222 lf.lfCharSet = ANSI_CHARSET;
4223 lf.lfPitchAndFamily = FF_SWISS;
4224 strcpy(lf.lfFaceName, "Nonexistent font");
4225 hfont = CreateFontIndirectA(&lf);
4226 hfont = SelectObject(hdc, hfont);
4227 GetTextFaceA(hdc, sizeof(buf), buf);
4228 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4229 cs = GetTextCharset(hdc);
4230 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4231 DeleteObject(SelectObject(hdc, hfont));
4233 memset(&lf, 0, sizeof(lf));
4234 lf.lfHeight = -13;
4235 lf.lfWeight = FW_DONTCARE;
4236 strcpy(lf.lfFaceName, "Nonexistent font");
4237 hfont = CreateFontIndirectA(&lf);
4238 hfont = SelectObject(hdc, hfont);
4239 GetTextFaceA(hdc, sizeof(buf), buf);
4240 todo_wine /* Wine uses Arial for all substitutions */
4241 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
4242 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4243 "Got %s\n", buf);
4244 cs = GetTextCharset(hdc);
4245 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
4246 DeleteObject(SelectObject(hdc, hfont));
4248 memset(&lf, 0, sizeof(lf));
4249 lf.lfHeight = -13;
4250 lf.lfWeight = FW_REGULAR;
4251 strcpy(lf.lfFaceName, "Nonexistent font");
4252 hfont = CreateFontIndirectA(&lf);
4253 hfont = SelectObject(hdc, hfont);
4254 GetTextFaceA(hdc, sizeof(buf), buf);
4255 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4256 cs = GetTextCharset(hdc);
4257 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4258 DeleteObject(SelectObject(hdc, hfont));
4260 memset(&lf, 0, sizeof(lf));
4261 lf.lfHeight = -13;
4262 lf.lfWeight = FW_DONTCARE;
4263 strcpy(lf.lfFaceName, "Times New Roman");
4264 hfont = CreateFontIndirectA(&lf);
4265 hfont = SelectObject(hdc, hfont);
4266 GetTextFaceA(hdc, sizeof(buf), buf);
4267 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
4268 cs = GetTextCharset(hdc);
4269 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4270 DeleteObject(SelectObject(hdc, hfont));
4272 for (i = 0; i < ARRAY_SIZE(font_subst); i++)
4274 ret = is_font_installed(font_subst[i].name);
4275 todo_wine
4276 ok(ret, "%s should be enumerated\n", font_subst[i].name);
4277 ret = is_truetype_font_installed(font_subst[i].name);
4278 todo_wine
4279 ok(ret, "%s should be enumerated\n", font_subst[i].name);
4281 memset(&lf, 0, sizeof(lf));
4282 lf.lfHeight = -13;
4283 lf.lfWeight = FW_REGULAR;
4284 strcpy(lf.lfFaceName, font_subst[i].name);
4285 hfont = CreateFontIndirectA(&lf);
4286 hfont = SelectObject(hdc, hfont);
4287 cs = GetTextCharset(hdc);
4288 if (font_subst[i].charset == expected_cs)
4290 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4291 GetTextFaceA(hdc, sizeof(buf), buf);
4292 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
4294 else
4296 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
4297 GetTextFaceA(hdc, sizeof(buf), buf);
4298 ok(!lstrcmpiA(buf, "Arial"), "got %s for font %s\n", buf, font_subst[i].name);
4300 DeleteObject(SelectObject(hdc, hfont));
4302 memset(&lf, 0, sizeof(lf));
4303 lf.lfHeight = -13;
4304 lf.lfWeight = FW_DONTCARE;
4305 strcpy(lf.lfFaceName, font_subst[i].name);
4306 hfont = CreateFontIndirectA(&lf);
4307 hfont = SelectObject(hdc, hfont);
4308 GetTextFaceA(hdc, sizeof(buf), buf);
4309 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
4310 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
4311 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4312 "got %s for font %s\n", buf, font_subst[i].name);
4313 cs = GetTextCharset(hdc);
4314 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4315 DeleteObject(SelectObject(hdc, hfont));
4318 DeleteDC(hdc);
4321 struct font_realization_info
4323 DWORD size;
4324 DWORD flags;
4325 DWORD cache_num;
4326 DWORD instance_id;
4327 DWORD file_count;
4328 WORD face_index;
4329 WORD simulations;
4332 struct file_info
4334 FILETIME time;
4335 LARGE_INTEGER size;
4336 WCHAR path[MAX_PATH];
4339 static void test_RealizationInfo(void)
4341 struct realization_info_t
4343 DWORD flags;
4344 DWORD cache_num;
4345 DWORD instance_id;
4348 struct file_info file_info;
4349 HDC hdc;
4350 DWORD info[4], info2[32], read;
4351 HFONT hfont, hfont_old;
4352 SIZE_T needed;
4353 LOGFONTA lf;
4354 HANDLE h;
4355 BYTE file[16], data[14];
4356 FILETIME time;
4357 LARGE_INTEGER size;
4358 BOOL r;
4360 if(!pGdiRealizationInfo)
4362 win_skip("GdiRealizationInfo not available\n");
4363 return;
4366 hdc = GetDC(0);
4368 memset(info, 0xcc, sizeof(info));
4369 r = pGdiRealizationInfo(hdc, info);
4370 ok(r != 0, "ret 0\n");
4371 ok((info[0] & 0xf) == 1, "info[0] = %lx for the system font\n", info[0]);
4372 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4374 if (!is_truetype_font_installed("Tahoma"))
4376 skip("skipping GdiRealizationInfo with truetype font\n");
4377 goto end;
4380 memset(&lf, 0, sizeof(lf));
4381 strcpy(lf.lfFaceName, "Tahoma");
4382 lf.lfHeight = 20;
4383 lf.lfWeight = FW_BOLD;
4384 lf.lfItalic = 1;
4385 hfont = CreateFontIndirectA(&lf);
4386 hfont_old = SelectObject(hdc, hfont);
4388 memset(info, 0xcc, sizeof(info));
4389 r = pGdiRealizationInfo(hdc, info);
4390 ok(r != 0, "ret 0\n");
4391 ok((info[0] & 0xf) == 3, "info[0] = %lx for arial\n", info[0]);
4392 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4394 if (pGetFontRealizationInfo)
4396 struct font_realization_info *fri = (struct font_realization_info*)info2;
4397 struct realization_info_t *ri = (struct realization_info_t*)info;
4399 /* The first DWORD represents a struct size. On a
4400 newly rebooted system setting this to < 16 results
4401 in GetFontRealizationInfo failing. However there
4402 appears to be some caching going on which results
4403 in calls after a successful call also succeeding even
4404 if the size < 16. This means we can't reliably test
4405 this behaviour. */
4407 memset(info2, 0xcc, sizeof(info2));
4408 info2[0] = 16;
4409 r = pGetFontRealizationInfo(hdc, info2);
4410 ok(r != 0, "ret 0\n");
4411 /* We may get the '24' version here if that has been previously
4412 requested. */
4413 ok(fri->size == 16 || fri->size == 24, "got %ld\n", info2[0]);
4414 ok(fri->flags == ri->flags, "flags mismatch\n");
4415 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4416 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4417 ok(info2[6] == 0xcccccccc, "got wrong dword 6, 0x%08lx\n", info2[6]);
4419 memset(info2, 0xcc, sizeof(info2));
4420 info2[0] = 28;
4421 r = pGetFontRealizationInfo(hdc, info2);
4422 ok(r == FALSE, "got %d\n", r);
4424 memset(info2, 0xcc, sizeof(info2));
4425 info2[0] = 24;
4426 r = pGetFontRealizationInfo(hdc, info2);
4427 ok(r != 0, "ret 0\n");
4428 ok(fri->size == 24, "got %ld\n", fri->size);
4429 ok(fri->flags == ri->flags, "flags mismatch\n");
4430 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4431 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4432 ok(fri->simulations == 0x2, "got simulations flags 0x%04x\n", fri->simulations);
4433 ok(fri->face_index == 0, "got wrong face index %u\n", fri->face_index);
4434 ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4436 /* Test GetFontFileInfo() */
4437 /* invalid font id */
4438 SetLastError(0xdeadbeef);
4439 r = pGetFontFileInfo(0xabababab, 0, &file_info, sizeof(file_info), &needed);
4440 ok(r == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "ret %d gle %ld\n", r, GetLastError());
4442 needed = 0;
4443 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed);
4444 ok(r != 0, "Failed to get font file info, error %ld.\n", GetLastError());
4446 if (r)
4448 ok(needed > 0 && needed < sizeof(file_info), "Unexpected required size.\n");
4450 h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
4451 ok(h != INVALID_HANDLE_VALUE, "Unable to open file %ld\n", GetLastError());
4453 GetFileTime(h, NULL, NULL, &time);
4454 ok(!CompareFileTime(&file_info.time, &time), "time mismatch\n");
4455 GetFileSizeEx(h, &size);
4456 ok(file_info.size.QuadPart == size.QuadPart, "size mismatch\n");
4458 /* Read first 16 bytes from the file */
4459 ReadFile(h, file, sizeof(file), &read, NULL);
4460 CloseHandle(h);
4462 /* shorter buffer */
4463 SetLastError(0xdeadbeef);
4464 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, needed - 1, &needed);
4465 ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %ld\n", r, GetLastError());
4468 /* Get bytes 2 - 16 using GetFontFileData */
4469 r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data));
4470 ok(r != 0, "ret 0 gle %ld\n", GetLastError());
4472 ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n");
4475 DeleteObject(SelectObject(hdc, hfont_old));
4477 end:
4478 ReleaseDC(0, hdc);
4481 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4482 the nul in the count of characters copied when the face name buffer is not
4483 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4484 always includes it. */
4485 static void test_GetTextFace(void)
4487 static const char faceA[] = "Tahoma";
4488 static const WCHAR faceW[] = L"Tahoma";
4489 LOGFONTA fA = {0};
4490 LOGFONTW fW = {0};
4491 char bufA[LF_FACESIZE];
4492 WCHAR bufW[LF_FACESIZE];
4493 HFONT f, g;
4494 HDC dc;
4495 int n;
4497 if(!is_font_installed("Tahoma"))
4499 skip("Tahoma is not installed so skipping this test\n");
4500 return;
4503 /* 'A' case. */
4504 memcpy(fA.lfFaceName, faceA, sizeof faceA);
4505 f = CreateFontIndirectA(&fA);
4506 ok(f != NULL, "CreateFontIndirectA failed\n");
4508 dc = GetDC(NULL);
4509 g = SelectObject(dc, f);
4510 n = GetTextFaceA(dc, sizeof bufA, bufA);
4511 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
4512 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
4514 /* Play with the count arg. */
4515 bufA[0] = 'x';
4516 n = GetTextFaceA(dc, 0, bufA);
4517 ok(n == 0, "GetTextFaceA returned %d\n", n);
4518 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4520 bufA[0] = 'x';
4521 n = GetTextFaceA(dc, 1, bufA);
4522 ok(n == 0, "GetTextFaceA returned %d\n", n);
4523 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4525 bufA[0] = 'x'; bufA[1] = 'y';
4526 n = GetTextFaceA(dc, 2, bufA);
4527 ok(n == 1, "GetTextFaceA returned %d\n", n);
4528 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
4530 n = GetTextFaceA(dc, 0, NULL);
4531 ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
4533 DeleteObject(SelectObject(dc, g));
4534 ReleaseDC(NULL, dc);
4536 /* 'W' case. */
4537 memcpy(fW.lfFaceName, faceW, sizeof faceW);
4538 SetLastError(0xdeadbeef);
4539 f = CreateFontIndirectW(&fW);
4540 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
4542 win_skip("CreateFontIndirectW is not implemented\n");
4543 return;
4545 ok(f != NULL, "CreateFontIndirectW failed\n");
4547 dc = GetDC(NULL);
4548 g = SelectObject(dc, f);
4549 n = GetTextFaceW(dc, ARRAY_SIZE(bufW), bufW);
4550 ok(n == ARRAY_SIZE(faceW), "GetTextFaceW returned %d\n", n);
4551 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
4553 /* Play with the count arg. */
4554 bufW[0] = 'x';
4555 n = GetTextFaceW(dc, 0, bufW);
4556 ok(n == 0, "GetTextFaceW returned %d\n", n);
4557 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4559 bufW[0] = 'x';
4560 n = GetTextFaceW(dc, 1, bufW);
4561 ok(n == 1, "GetTextFaceW returned %d\n", n);
4562 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4564 bufW[0] = 'x'; bufW[1] = 'y';
4565 n = GetTextFaceW(dc, 2, bufW);
4566 ok(n == 2, "GetTextFaceW returned %d\n", n);
4567 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4569 n = GetTextFaceW(dc, 0, NULL);
4570 ok(n == ARRAY_SIZE(faceW), "GetTextFaceW returned %d\n", n);
4572 DeleteObject(SelectObject(dc, g));
4573 ReleaseDC(NULL, dc);
4576 static void test_orientation(void)
4578 static const char test_str[11] = "Test String";
4579 HDC hdc;
4580 LOGFONTA lf;
4581 HFONT hfont, old_hfont;
4582 SIZE size;
4584 if (!is_truetype_font_installed("Arial"))
4586 skip("Arial is not installed\n");
4587 return;
4590 hdc = CreateCompatibleDC(0);
4591 memset(&lf, 0, sizeof(lf));
4592 lstrcpyA(lf.lfFaceName, "Arial");
4593 lf.lfHeight = 72;
4594 lf.lfOrientation = lf.lfEscapement = 900;
4595 hfont = create_font("orientation", &lf);
4596 old_hfont = SelectObject(hdc, hfont);
4597 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4598 ok(near_match(311, size.cx), "cx should be about 311, got %ld\n", size.cx);
4599 ok(near_match(75, size.cy), "cy should be about 75, got %ld\n", size.cy);
4600 SelectObject(hdc, old_hfont);
4601 DeleteObject(hfont);
4602 DeleteDC(hdc);
4605 static void test_oemcharset(void)
4607 HDC hdc;
4608 LOGFONTA lf, clf;
4609 HFONT hfont, old_hfont;
4610 int charset;
4612 hdc = CreateCompatibleDC(0);
4613 ZeroMemory(&lf, sizeof(lf));
4614 lf.lfHeight = 12;
4615 lf.lfCharSet = OEM_CHARSET;
4616 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4617 lstrcpyA(lf.lfFaceName, "Terminal");
4618 hfont = CreateFontIndirectA(&lf);
4619 old_hfont = SelectObject(hdc, hfont);
4620 charset = GetTextCharset(hdc);
4621 todo_wine
4622 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4623 hfont = SelectObject(hdc, old_hfont);
4624 GetObjectA(hfont, sizeof(clf), &clf);
4625 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4626 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4627 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4628 ok(clf.lfHeight == lf.lfHeight, "expected %ld height, got %ld\n", lf.lfHeight, clf.lfHeight);
4629 DeleteObject(hfont);
4630 DeleteDC(hdc);
4633 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4634 const TEXTMETRICA *lpntme,
4635 DWORD FontType, LPARAM lParam)
4637 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4638 CHARSETINFO csi;
4639 LOGFONTA lf = *lpelfe;
4640 HFONT hfont;
4641 DWORD found_subset;
4643 /* skip bitmap, proportional or vertical font */
4644 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4645 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4646 lf.lfFaceName[0] == '@')
4647 return 1;
4649 /* skip linked font */
4650 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4651 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4652 return 1;
4654 /* skip linked font, like SimSun-ExtB */
4655 switch (lpelfe->lfCharSet) {
4656 case SHIFTJIS_CHARSET:
4657 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4658 break;
4659 case GB2312_CHARSET:
4660 case CHINESEBIG5_CHARSET:
4661 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4662 break;
4663 case HANGEUL_CHARSET:
4664 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4665 break;
4666 default:
4667 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4668 break;
4670 if (!found_subset)
4671 return 1;
4673 /* test with an odd height */
4674 lf.lfHeight = -19;
4675 lf.lfWidth = 0;
4676 hfont = CreateFontIndirectA(&lf);
4677 if (hfont)
4679 *(HFONT *)lParam = hfont;
4680 return 0;
4682 return 1;
4685 static void test_GetGlyphOutline(void)
4687 HDC hdc;
4688 GLYPHMETRICS gm, gm2;
4689 LOGFONTA lf;
4690 HFONT hfont, old_hfont;
4691 INT ret, ret2;
4692 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4693 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4694 static const struct
4696 UINT cs;
4697 UINT a;
4698 UINT w;
4699 } c[] =
4701 {ANSI_CHARSET, 0x30, 0x30},
4702 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4703 {HANGEUL_CHARSET, 0x8141, 0xac02},
4704 {GB2312_CHARSET, 0x8141, 0x4e04},
4705 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4707 UINT i;
4709 if (!is_truetype_font_installed("Tahoma"))
4711 skip("Tahoma is not installed\n");
4712 return;
4715 hdc = CreateCompatibleDC(0);
4716 memset(&lf, 0, sizeof(lf));
4717 lf.lfHeight = 72;
4718 lstrcpyA(lf.lfFaceName, "Tahoma");
4719 SetLastError(0xdeadbeef);
4720 hfont = CreateFontIndirectA(&lf);
4721 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
4722 old_hfont = SelectObject(hdc, hfont);
4724 memset(&gm, 0, sizeof(gm));
4725 SetLastError(0xdeadbeef);
4726 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4727 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %lu\n", GetLastError());
4729 memset(&gm, 0, sizeof(gm));
4730 SetLastError(0xdeadbeef);
4731 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4732 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4733 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", GetLastError());
4735 memset(&gm, 0, sizeof(gm));
4736 SetLastError(0xdeadbeef);
4737 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4738 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4739 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %lu\n", GetLastError());
4741 memset(&gm, 0, sizeof(gm));
4742 SetLastError(0xdeadbeef);
4743 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4744 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4746 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4747 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", GetLastError());
4750 /* test for needed buffer size request on space char */
4751 memset(&gm, 0, sizeof(gm));
4752 SetLastError(0xdeadbeef);
4753 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4754 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4756 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4757 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX);
4758 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY);
4761 /* requesting buffer size for space char + error */
4762 memset(&gm, 0, sizeof(gm));
4763 SetLastError(0xdeadbeef);
4764 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4765 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4767 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4768 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", GetLastError());
4769 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX);
4770 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY);
4773 /* test GetGlyphOutline with a buffer too small */
4774 SetLastError(0xdeadbeef);
4775 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat);
4776 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4777 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4779 for (i = 0; i < ARRAY_SIZE(fmt); ++i)
4781 DWORD dummy;
4783 memset(&gm, 0xab, sizeof(gm));
4784 SetLastError(0xdeadbeef);
4785 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4786 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4788 if (fmt[i] == GGO_METRICS)
4789 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4790 else
4791 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4792 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4793 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4796 memset(&gm, 0xab, sizeof(gm));
4797 SetLastError(0xdeadbeef);
4798 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4799 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4801 if (fmt[i] == GGO_METRICS)
4802 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4803 else
4804 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4805 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4806 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4809 memset(&gm, 0xab, sizeof(gm));
4810 SetLastError(0xdeadbeef);
4811 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4812 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4814 if (fmt[i] == GGO_METRICS)
4815 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4816 else
4817 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4818 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4819 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4822 memset(&gm, 0xab, sizeof(gm));
4823 SetLastError(0xdeadbeef);
4824 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4825 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4827 if (fmt[i] == GGO_METRICS) {
4828 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4829 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4830 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4832 else
4834 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4835 memset(&gm2, 0xab, sizeof(gm2));
4836 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4837 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4842 SelectObject(hdc, old_hfont);
4843 DeleteObject(hfont);
4845 for (i = 0; i < ARRAY_SIZE(c); ++i)
4847 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4848 TEXTMETRICA tm;
4850 lf.lfFaceName[0] = '\0';
4851 lf.lfCharSet = c[i].cs;
4852 lf.lfPitchAndFamily = 0;
4853 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4855 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4856 continue;
4859 old_hfont = SelectObject(hdc, hfont);
4861 /* expected to ignore superfluous bytes (single-byte character) */
4862 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4863 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4864 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4866 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4867 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4868 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4870 /* expected to ignore superfluous bytes (double-byte character) */
4871 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4872 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4873 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4874 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4876 /* expected to match wide-char version results */
4877 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4878 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4880 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4882 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4883 continue;
4885 DeleteObject(SelectObject(hdc, hfont));
4886 if (c[i].a <= 0xff)
4888 DeleteObject(SelectObject(hdc, old_hfont));
4889 continue;
4892 ret = GetObjectA(hfont, sizeof lf, &lf);
4893 ok(ret > 0, "GetObject error %lu\n", GetLastError());
4895 ret = GetTextMetricsA(hdc, &tm);
4896 ok(ret, "GetTextMetrics error %lu\n", GetLastError());
4897 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4898 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %lu\n", GetLastError());
4899 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4900 "expected %ld, got %d (%s:%d)\n",
4901 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4903 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4904 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %lu\n", GetLastError());
4905 ok(gm2.gmCellIncY == -lf.lfHeight,
4906 "expected %ld, got %d (%s:%d)\n",
4907 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4909 lf.lfItalic = TRUE;
4910 hfont = CreateFontIndirectA(&lf);
4911 ok(hfont != NULL, "CreateFontIndirect error %lu\n", GetLastError());
4912 DeleteObject(SelectObject(hdc, hfont));
4913 ret = GetTextMetricsA(hdc, &tm);
4914 ok(ret, "GetTextMetrics error %lu\n", GetLastError());
4915 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4916 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %lu\n", GetLastError());
4917 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4918 "expected %ld, got %d (%s:%d)\n",
4919 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4921 lf.lfItalic = FALSE;
4922 lf.lfEscapement = lf.lfOrientation = 2700;
4923 hfont = CreateFontIndirectA(&lf);
4924 ok(hfont != NULL, "CreateFontIndirect error %lu\n", GetLastError());
4925 DeleteObject(SelectObject(hdc, hfont));
4926 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4927 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %lu\n", GetLastError());
4928 ok(gm2.gmCellIncY == -lf.lfHeight,
4929 "expected %ld, got %d (%s:%d)\n",
4930 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4932 hfont = SelectObject(hdc, old_hfont);
4933 DeleteObject(hfont);
4936 DeleteDC(hdc);
4939 /* bug #9995: there is a limit to the character width that can be specified */
4940 static void test_GetTextMetrics2(const char *fontname, int font_height)
4942 HFONT of, hf;
4943 HDC hdc;
4944 TEXTMETRICA tm;
4945 BOOL ret;
4946 int ave_width, height, width, ratio;
4948 if (!is_truetype_font_installed( fontname)) {
4949 skip("%s is not installed\n", fontname);
4950 return;
4952 hdc = CreateCompatibleDC(0);
4953 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4954 /* select width = 0 */
4955 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4956 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4957 DEFAULT_QUALITY, VARIABLE_PITCH,
4958 fontname);
4959 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4960 of = SelectObject( hdc, hf);
4961 ret = GetTextMetricsA( hdc, &tm);
4962 ok(ret, "GetTextMetricsA error %lu\n", GetLastError());
4963 height = tm.tmHeight;
4964 ave_width = tm.tmAveCharWidth;
4965 SelectObject( hdc, of);
4966 DeleteObject( hf);
4968 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4970 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4971 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4972 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4973 ok(hf != 0, "CreateFont failed\n");
4974 of = SelectObject(hdc, hf);
4975 ret = GetTextMetricsA(hdc, &tm);
4976 ok(ret, "GetTextMetrics error %lu\n", GetLastError());
4977 SelectObject(hdc, of);
4978 DeleteObject(hf);
4980 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4981 break;
4984 DeleteDC(hdc);
4986 ratio = width / height;
4988 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4991 static void test_GetCharacterPlacement(void)
4993 GCP_RESULTSA result;
4994 DWORD size, size2;
4995 WCHAR glyphs[20];
4996 int pos[20];
4997 HDC hdc;
4999 hdc = CreateCompatibleDC(0);
5000 ok(!!hdc, "CreateCompatibleDC failed\n");
5002 memset(&result, 0, sizeof(result));
5003 result.lStructSize = sizeof(result);
5004 result.lpCaretPos = pos;
5005 result.lpGlyphs = glyphs;
5006 result.nGlyphs = 20;
5008 pos[0] = -1;
5009 glyphs[0] = '!';
5010 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, &result, 0);
5011 ok(size, "GetCharacterPlacementA failed!\n");
5012 ok(result.nGlyphs == 9, "Unexpected number of glyphs %u\n", result.nGlyphs);
5013 ok(glyphs[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs, 1));
5014 ok(pos[0] == 0, "Unexpected caret position %d\n", pos[0]);
5016 pos[0] = -1;
5017 glyphs[0] = '!';
5018 result.nGlyphs = 20;
5019 size2 = GetCharacterPlacementA(hdc, "Wine Test", 0, 0, &result, 0);
5020 ok(!size2, "Expected GetCharacterPlacementA to fail\n");
5021 ok(result.nGlyphs == 20, "Unexpected number of glyphs %u\n", result.nGlyphs);
5022 ok(glyphs[0] == '!', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs, 1));
5023 ok(pos[0] == -1, "Unexpected caret position %d\n", pos[0]);
5025 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, NULL, 0);
5026 ok(size2, "GetCharacterPlacementA failed!\n");
5027 ok(size == size2, "GetCharacterPlacementA returned different result: %lu vs %lu\n", size2, size);
5029 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, NULL, GCP_REORDER);
5030 ok(size2, "GetCharacterPlacementA failed!\n");
5031 ok(size == size2, "GetCharacterPlacementA returned different result: %lu vs %lu\n", size2, size);
5033 pos[0] = -1;
5034 glyphs[0] = '!';
5035 result.nGlyphs = 20;
5036 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, &result, GCP_REORDER);
5037 ok(size, "GetCharacterPlacementA failed!\n");
5038 ok(size == size2, "GetCharacterPlacementA returned different result: %lu vs %lu\n", size2, size);
5039 ok(result.nGlyphs == 9, "Unexpected number of glyphs %u\n", result.nGlyphs);
5040 ok(glyphs[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs, 1));
5041 todo_wine ok(pos[0] == 0, "Unexpected caret position %d\n", pos[0]);
5043 DeleteDC(hdc);
5046 static void test_CreateFontIndirect(void)
5048 LOGFONTA lf, getobj_lf;
5049 int ret, i;
5050 HFONT hfont;
5051 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
5053 memset(&lf, 0, sizeof(lf));
5054 lf.lfCharSet = ANSI_CHARSET;
5055 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5056 lf.lfHeight = 16;
5057 lf.lfWidth = 16;
5058 lf.lfQuality = DEFAULT_QUALITY;
5059 lf.lfItalic = FALSE;
5060 lf.lfWeight = FW_DONTCARE;
5062 for (i = 0; i < ARRAY_SIZE(TestName); i++)
5064 lstrcpyA(lf.lfFaceName, TestName[i]);
5065 hfont = CreateFontIndirectA(&lf);
5066 ok(hfont != 0, "CreateFontIndirectA failed\n");
5067 SetLastError(0xdeadbeef);
5068 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
5069 ok(ret, "GetObject failed: %ld\n", GetLastError());
5070 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
5071 ok(lf.lfWeight == getobj_lf.lfWeight, "lfWeight: expect %08lx got %08lx\n", lf.lfWeight, getobj_lf.lfWeight);
5072 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName), "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
5073 DeleteObject(hfont);
5077 static void test_CreateFontIndirectEx(void)
5079 ENUMLOGFONTEXDVA lfex;
5080 HFONT hfont;
5082 if (!is_truetype_font_installed("Arial"))
5084 skip("Arial is not installed\n");
5085 return;
5088 SetLastError(0xdeadbeef);
5089 hfont = CreateFontIndirectExA(NULL);
5090 ok(hfont == NULL, "got %p\n", hfont);
5091 ok(GetLastError() == 0xdeadbeef, "got error %ld\n", GetLastError());
5093 memset(&lfex, 0, sizeof(lfex));
5094 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
5095 hfont = CreateFontIndirectExA(&lfex);
5096 ok(hfont != 0, "CreateFontIndirectEx failed\n");
5097 if (hfont)
5098 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
5099 DeleteObject(hfont);
5102 static void test_realization_info(const char *name, DWORD size, BOOL is_memory_resource)
5104 struct font_realization_info info;
5105 struct file_info file_info;
5106 HFONT hfont, hfont_prev;
5107 SIZE_T needed;
5108 LOGFONTA lf;
5109 BYTE *data;
5110 BOOL ret;
5111 HDC hdc;
5113 if (!pGetFontRealizationInfo)
5114 return;
5116 memset(&lf, 0, sizeof(lf));
5117 lf.lfHeight = 72;
5118 strcpy(lf.lfFaceName, name);
5120 hfont = CreateFontIndirectA(&lf);
5121 ok(hfont != 0, "Failed to create a font, %lu.\n", GetLastError());
5123 hdc = GetDC(NULL);
5125 hfont_prev = SelectObject(hdc, hfont);
5126 ok(hfont_prev != NULL, "Failed to select font.\n");
5128 memset(&info, 0xcc, sizeof(info));
5129 info.size = sizeof(info);
5130 ret = pGetFontRealizationInfo(hdc, (DWORD *)&info);
5131 ok(ret != 0, "Unexpected return value %d.\n", ret);
5133 ok((info.flags & 0xf) == 0x3, "Unexpected flags %#lx.\n", info.flags);
5134 ok(info.cache_num != 0, "Unexpected cache num %lu.\n", info.cache_num);
5135 ok(info.instance_id != 0, "Unexpected instance id %lu.\n", info.instance_id);
5136 ok(info.simulations == 0, "Unexpected simulations %#x.\n", info.simulations);
5137 ok(info.face_index == 0, "Unexpected face index %u.\n", info.face_index);
5139 ret = pGetFontFileInfo(info.instance_id, 0, NULL, 0, NULL);
5140 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %ld.\n",
5141 ret, GetLastError());
5143 needed = 0;
5144 ret = pGetFontFileInfo(info.instance_id, 0, NULL, 0, &needed);
5145 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %ld.\n",
5146 ret, GetLastError());
5148 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, 0, NULL);
5149 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %ld.\n",
5150 ret, GetLastError());
5152 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, needed - 1, NULL);
5153 ok(ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return value %d, error %ld.\n",
5154 ret, GetLastError());
5156 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, needed, NULL);
5157 ok(ret != 0, "Failed to get font file info, ret %d gle %ld.\n", ret, GetLastError());
5159 memset(&file_info, 0xcc, sizeof(file_info));
5160 ret = pGetFontFileInfo(info.instance_id, 0, &file_info, sizeof(file_info), NULL);
5161 ok(ret != 0, "Failed to get font file info, ret %d gle %ld.\n", ret, GetLastError());
5162 if (ret)
5164 ok(is_memory_resource ? file_info.size.QuadPart == size : file_info.size.QuadPart > 0, "Unexpected file size.\n");
5165 ok(is_memory_resource ? !file_info.path[0] : file_info.path[0], "Unexpected file path %s.\n",
5166 wine_dbgstr_w(file_info.path));
5169 size = file_info.size.LowPart;
5170 data = HeapAlloc(GetProcessHeap(), 0, size + 16);
5172 memset(data, 0xcc, size);
5173 ret = pGetFontFileData(info.instance_id, 0, 0, data, size);
5174 ok(ret != 0, "Failed to get font file data, %ld\n", GetLastError());
5175 ok(*(DWORD *)data == 0x00000100, "Unexpected sfnt header version %#lx.\n", *(DWORD *)data);
5176 ok(*(WORD *)(data + 4) == 0x0e00, "Unexpected table count %#x.\n", *(WORD *)(data + 4));
5178 /* Larger than font data size. */
5179 memset(data, 0xcc, size);
5180 ret = pGetFontFileData(info.instance_id, 0, 0, data, size + 16);
5181 ok(ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected return value %d, error %ld\n",
5182 ret, GetLastError());
5183 ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#lx.\n", *(DWORD *)data);
5185 /* With offset. */
5186 memset(data, 0xcc, size);
5187 ret = pGetFontFileData(info.instance_id, 0, 16, data, size - 16);
5188 ok(ret != 0, "Failed to get font file data, %ld\n", GetLastError());
5189 ok(*(DWORD *)data == 0x1000000, "Unexpected buffer contents %#lx.\n", *(DWORD *)data);
5191 memset(data, 0xcc, size);
5192 ret = pGetFontFileData(info.instance_id, 0, 16, data, size);
5193 ok(ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected return value %d, error %ld\n",
5194 ret, GetLastError());
5195 ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#lx.\n", *(DWORD *)data);
5197 /* Zero buffer size. */
5198 memset(data, 0xcc, size);
5199 ret = pGetFontFileData(info.instance_id, 0, 16, data, 0);
5200 todo_wine
5201 ok(ret == 0 && GetLastError() == ERROR_NOACCESS, "Unexpected return value %d, error %ld\n", ret, GetLastError());
5202 ok(*(DWORD *)data == 0xcccccccc, "Unexpected buffer contents %#lx.\n", *(DWORD *)data);
5204 HeapFree(GetProcessHeap(), 0, data);
5206 SelectObject(hdc, hfont_prev);
5207 DeleteObject(hfont);
5208 ReleaseDC(NULL, hdc);
5211 static void test_AddFontMemResource(void)
5213 char ttf_name[MAX_PATH];
5214 void *font;
5215 DWORD font_size, num_fonts;
5216 HANDLE ret;
5217 BOOL bRet;
5219 SetLastError(0xdeadbeef);
5220 ret = AddFontMemResourceEx(NULL, 0, NULL, NULL);
5221 ok(!ret, "AddFontMemResourceEx should fail\n");
5222 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5223 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5224 GetLastError());
5226 SetLastError(0xdeadbeef);
5227 ret = AddFontMemResourceEx(NULL, 10, NULL, NULL);
5228 ok(!ret, "AddFontMemResourceEx should fail\n");
5229 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5230 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5231 GetLastError());
5233 SetLastError(0xdeadbeef);
5234 ret = AddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
5235 ok(!ret, "AddFontMemResourceEx should fail\n");
5236 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5237 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5238 GetLastError());
5240 SetLastError(0xdeadbeef);
5241 ret = AddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
5242 ok(!ret, "AddFontMemResourceEx should fail\n");
5243 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5244 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5245 GetLastError());
5247 /* Now with scalable font */
5248 bRet = write_ttf_file("wine_test.ttf", ttf_name);
5249 ok(bRet, "Failed to create test font file.\n");
5251 font = load_font(ttf_name, &font_size);
5252 ok(font != NULL, "Failed to map font file.\n");
5254 bRet = is_truetype_font_installed("wine_test");
5255 ok(!bRet, "Font wine_test should not be enumerated.\n");
5257 num_fonts = 0;
5258 ret = AddFontMemResourceEx(font, font_size, NULL, &num_fonts);
5259 ok(ret != 0, "Failed to add resource, %ld.\n", GetLastError());
5260 ok(num_fonts == 1, "Unexpected number of fonts %lu.\n", num_fonts);
5262 bRet = is_truetype_font_installed("wine_test");
5263 todo_wine
5264 ok(!bRet, "Font wine_test should not be enumerated.\n");
5266 test_realization_info("wine_test", font_size, TRUE);
5268 bRet = RemoveFontMemResourceEx(ret);
5269 ok(bRet, "RemoveFontMemResourceEx error %ld\n", GetLastError());
5271 free_font(font);
5273 bRet = DeleteFileA(ttf_name);
5274 ok(bRet, "Failed to delete font file, %ld.\n", GetLastError());
5276 font = load_font("sserife.fon", &font_size);
5277 if (!font)
5279 skip("Unable to locate and load font sserife.fon\n");
5280 return;
5283 SetLastError(0xdeadbeef);
5284 ret = AddFontMemResourceEx(font, 0, NULL, NULL);
5285 ok(!ret, "AddFontMemResourceEx should fail\n");
5286 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5287 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5288 GetLastError());
5290 SetLastError(0xdeadbeef);
5291 ret = AddFontMemResourceEx(font, 10, NULL, NULL);
5292 ok(!ret, "AddFontMemResourceEx should fail\n");
5293 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5294 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5295 GetLastError());
5297 num_fonts = 0xdeadbeef;
5298 SetLastError(0xdeadbeef);
5299 ret = AddFontMemResourceEx(font, 0, NULL, &num_fonts);
5300 ok(!ret, "AddFontMemResourceEx should fail\n");
5301 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5302 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5303 GetLastError());
5304 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5306 num_fonts = 0xdeadbeef;
5307 SetLastError(0xdeadbeef);
5308 ret = AddFontMemResourceEx(font, 10, NULL, &num_fonts);
5309 ok(!ret, "AddFontMemResourceEx should fail\n");
5310 ok(GetLastError() == 0xdeadbeef,
5311 "Expected GetLastError() to return 0xdeadbeef, got %lu\n",
5312 GetLastError());
5313 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5315 num_fonts = 0xdeadbeef;
5316 SetLastError(0xdeadbeef);
5317 ret = AddFontMemResourceEx(font, font_size, NULL, &num_fonts);
5318 ok(ret != 0, "AddFontMemResourceEx error %ld\n", GetLastError());
5319 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5320 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
5322 free_font(font);
5324 SetLastError(0xdeadbeef);
5325 bRet = RemoveFontMemResourceEx(ret);
5326 ok(bRet, "RemoveFontMemResourceEx error %ld\n", GetLastError());
5328 /* test invalid pointer to number of loaded fonts */
5329 font = load_font("sserife.fon", &font_size);
5330 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
5332 SetLastError(0xdeadbeef);
5333 ret = AddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
5334 ok(!ret, "AddFontMemResourceEx should fail\n");
5335 ok(GetLastError() == 0xdeadbeef,
5336 "Expected GetLastError() to return 0xdeadbeef, got %lu\n",
5337 GetLastError());
5339 SetLastError(0xdeadbeef);
5340 ret = AddFontMemResourceEx(font, font_size, NULL, NULL);
5341 ok(!ret, "AddFontMemResourceEx should fail\n");
5342 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5343 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5344 GetLastError());
5346 free_font(font);
5349 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5351 LOGFONTA *lf;
5353 if (type != TRUETYPE_FONTTYPE) return 1;
5355 ok(ntm->tmWeight == elf->lfWeight, "expected %ld got %ld\n", ntm->tmWeight, elf->lfWeight);
5357 lf = (LOGFONTA *)lparam;
5358 *lf = *elf;
5359 return 0;
5362 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5364 int ret;
5365 LOGFONTA *lf;
5367 if (type != TRUETYPE_FONTTYPE) return 1;
5369 lf = (LOGFONTA *)lparam;
5370 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
5371 if(ret == 0)
5373 ok(ntm->tmWeight == elf->lfWeight, "expected %ld got %ld\n", ntm->tmWeight, elf->lfWeight);
5374 *lf = *elf;
5375 return 0;
5377 return 1;
5380 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5382 return lparam;
5385 static void test_EnumFonts(void)
5387 int ret;
5388 LOGFONTA lf;
5389 HDC hdc;
5391 if (!is_truetype_font_installed("Arial"))
5393 skip("Arial is not installed\n");
5394 return;
5397 /* Windows uses localized font face names, so Arial Bold won't be found */
5398 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
5400 skip("User locale is not English, skipping the test\n");
5401 return;
5404 hdc = CreateCompatibleDC(0);
5406 /* check that the enumproc's retval is returned */
5407 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
5408 ok(ret == 0xcafe, "got %08x\n", ret);
5410 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
5411 ok(!ret, "font Arial is not enumerated\n");
5412 ret = strcmp(lf.lfFaceName, "Arial");
5413 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5414 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %ld\n", lf.lfWeight);
5416 strcpy(lf.lfFaceName, "Arial");
5417 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5418 ok(!ret, "font Arial is not enumerated\n");
5419 ret = strcmp(lf.lfFaceName, "Arial");
5420 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5421 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %ld\n", lf.lfWeight);
5423 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
5424 ok(!ret, "font Arial Bold is not enumerated\n");
5425 ret = strcmp(lf.lfFaceName, "Arial");
5426 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5427 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %ld\n", lf.lfWeight);
5429 strcpy(lf.lfFaceName, "Arial Bold");
5430 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5431 ok(ret, "font Arial Bold should not be enumerated\n");
5433 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
5434 ok(!ret, "font Arial Bold Italic is not enumerated\n");
5435 ret = strcmp(lf.lfFaceName, "Arial");
5436 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5437 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %ld\n", lf.lfWeight);
5439 strcpy(lf.lfFaceName, "Arial Bold Italic");
5440 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5441 ok(ret, "font Arial Bold Italic should not be enumerated\n");
5443 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
5444 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5446 strcpy(lf.lfFaceName, "Arial Italic Bold");
5447 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5448 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5450 DeleteDC(hdc);
5453 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5455 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5457 if (winetest_debug > 2)
5458 trace("enumed font \"%s\", charset %d, height %ld, weight %ld, italic %d\n",
5459 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5461 if (type != TRUETYPE_FONTTYPE) return 1;
5462 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1;
5464 if (efnd->total >= efnd->size)
5466 efnd->size = max( (efnd->total + 1) * 2, 256 );
5467 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5468 if (!efnd->elf) return 0;
5470 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5471 return 0;
5474 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5476 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5478 if (winetest_debug > 2)
5479 trace("enumed font \"%s\", charset %d, height %ld, weight %ld, italic %d\n",
5480 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5482 if (type != TRUETYPE_FONTTYPE) return 1;
5483 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1;
5485 if (efnd->total >= efnd->size)
5487 efnd->size = max( (efnd->total + 1) * 2, 256 );
5488 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5489 if (!efnd->elf) return 0;
5491 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5492 return 0;
5495 static void test_EnumFonts_subst(void)
5497 int ret;
5498 LOGFONTA lf;
5499 HDC hdc;
5500 struct enum_fullname_data efnd;
5502 ret = is_font_installed("MS Shell Dlg");
5503 ok(ret, "MS Shell Dlg should be enumerated\n");
5504 ret = is_truetype_font_installed("MS Shell Dlg");
5505 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n");
5507 ret = is_font_installed("MS Shell Dlg 2");
5508 ok(ret, "MS Shell Dlg 2 should be enumerated\n");
5509 ret = is_truetype_font_installed("MS Shell Dlg 2");
5510 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5512 hdc = CreateCompatibleDC(0);
5514 memset(&efnd, 0, sizeof(efnd));
5515 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5516 ok(ret, "MS Shell Dlg should not be enumerated\n");
5517 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n");
5519 memset(&lf, 0, sizeof(lf));
5520 lf.lfCharSet = DEFAULT_CHARSET;
5522 efnd.total = 0;
5523 strcpy(lf.lfFaceName, "MS Shell Dlg");
5524 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5525 ok(!ret, "MS Shell Dlg should be enumerated\n");
5526 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n");
5527 if (efnd.total)
5529 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
5530 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5531 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg");
5532 ok(ret, "did not expect MS Shell Dlg\n");
5535 efnd.total = 0;
5536 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5537 ok(ret, "MS Shell Dlg 2 should not be enumerated\n");
5538 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n");
5540 efnd.total = 0;
5541 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
5542 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5543 ok(!ret, "MS Shell Dlg 2 should be enumerated\n");
5544 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n");
5545 if (efnd.total)
5547 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
5548 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5549 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
5550 ok(ret, "did not expect MS Shell Dlg 2\n");
5553 heap_free(efnd.elf);
5554 DeleteDC(hdc);
5557 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5559 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
5560 const char *fullname = (const char *)lParam;
5562 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
5564 return 1;
5567 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
5569 HDC hdc = GetDC(0);
5570 BOOL ret = FALSE;
5572 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
5573 ret = TRUE;
5575 ReleaseDC(0, hdc);
5576 return ret;
5579 static void test_fullname(void)
5581 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5582 WCHAR bufW[LF_FULLFACESIZE];
5583 char bufA[LF_FULLFACESIZE];
5584 HFONT hfont, of;
5585 LOGFONTA lf;
5586 HDC hdc;
5587 int i;
5588 DWORD ret;
5590 hdc = CreateCompatibleDC(0);
5591 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5593 memset(&lf, 0, sizeof(lf));
5594 lf.lfCharSet = ANSI_CHARSET;
5595 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5596 lf.lfHeight = 16;
5597 lf.lfWidth = 16;
5598 lf.lfQuality = DEFAULT_QUALITY;
5599 lf.lfItalic = FALSE;
5600 lf.lfWeight = FW_DONTCARE;
5602 for (i = 0; i < ARRAY_SIZE(TestName); i++)
5604 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
5606 skip("%s is not installed\n", TestName[i]);
5607 continue;
5610 lstrcpyA(lf.lfFaceName, TestName[i]);
5611 hfont = CreateFontIndirectA(&lf);
5612 ok(hfont != 0, "CreateFontIndirectA failed\n");
5614 of = SelectObject(hdc, hfont);
5615 bufW[0] = 0;
5616 bufA[0] = 0;
5617 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
5618 ok(ret, "face full name could not be read\n");
5619 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
5620 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
5621 SelectObject(hdc, of);
5622 DeleteObject(hfont);
5624 DeleteDC(hdc);
5627 static WCHAR *prepend_at(WCHAR *family)
5629 if (!family)
5630 return NULL;
5632 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
5633 family[0] = '@';
5634 return family;
5637 static void test_fullname2_helper(const char *Family)
5639 char *FamilyName, *FaceName, *StyleName, *otmStr;
5640 struct enum_fullname_data efnd;
5641 WCHAR *bufW;
5642 char *bufA;
5643 HFONT hfont, of;
5644 LOGFONTA lf;
5645 HDC hdc;
5646 int i;
5647 DWORD otm_size, ret, buf_size;
5648 OUTLINETEXTMETRICA *otm;
5649 BOOL want_vertical, get_vertical;
5650 want_vertical = ( Family[0] == '@' );
5652 hdc = CreateCompatibleDC(0);
5653 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5655 memset(&lf, 0, sizeof(lf));
5656 lf.lfCharSet = DEFAULT_CHARSET;
5657 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5658 lf.lfHeight = 16;
5659 lf.lfWidth = 16;
5660 lf.lfQuality = DEFAULT_QUALITY;
5661 lf.lfItalic = FALSE;
5662 lf.lfWeight = FW_DONTCARE;
5663 strcpy(lf.lfFaceName, Family);
5664 memset(&efnd, 0, sizeof(efnd));
5665 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
5666 if (efnd.total == 0)
5667 skip("%s is not installed\n", lf.lfFaceName);
5669 for (i = 0; i < efnd.total; i++)
5671 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
5672 FaceName = (char *)efnd.elf[i].elfFullName;
5673 StyleName = (char *)efnd.elf[i].elfStyle;
5675 get_vertical = ( FamilyName[0] == '@' );
5676 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
5678 lstrcpyA(lf.lfFaceName, FaceName);
5679 hfont = CreateFontIndirectA(&lf);
5680 ok(hfont != 0, "CreateFontIndirectA failed\n");
5682 of = SelectObject(hdc, hfont);
5683 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
5684 ok(buf_size != GDI_ERROR, "no name table found\n");
5685 if (buf_size == GDI_ERROR) continue;
5687 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
5688 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
5690 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5691 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5692 memset(otm, 0, otm_size);
5693 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
5694 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
5695 if (ret == 0) continue;
5697 bufW[0] = 0;
5698 bufA[0] = 0;
5699 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
5700 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5701 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
5702 if (want_vertical) bufW = prepend_at(bufW);
5703 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5704 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
5705 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
5706 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
5708 bufW[0] = 0;
5709 bufA[0] = 0;
5710 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
5711 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5712 ok(ret, "FULL_NAME (face name) could not be read\n");
5713 if (want_vertical) bufW = prepend_at(bufW);
5714 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5715 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
5716 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
5717 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
5719 bufW[0] = 0;
5720 bufA[0] = 0;
5721 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
5722 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5723 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
5724 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5725 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
5726 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
5727 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
5729 bufW[0] = 0;
5730 bufA[0] = 0;
5731 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
5732 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5733 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
5734 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5735 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
5736 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
5738 SelectObject(hdc, of);
5739 DeleteObject(hfont);
5741 HeapFree(GetProcessHeap(), 0, otm);
5742 HeapFree(GetProcessHeap(), 0, bufW);
5743 HeapFree(GetProcessHeap(), 0, bufA);
5745 heap_free(efnd.elf);
5746 DeleteDC(hdc);
5749 static void test_fullname2(void)
5751 test_fullname2_helper("Arial");
5752 test_fullname2_helper("DejaVu Sans");
5753 test_fullname2_helper("Lucida Sans");
5754 test_fullname2_helper("Tahoma");
5755 test_fullname2_helper("Webdings");
5756 test_fullname2_helper("Wingdings");
5757 test_fullname2_helper("SimSun");
5758 test_fullname2_helper("NSimSun");
5759 test_fullname2_helper("MingLiu");
5760 test_fullname2_helper("PMingLiu");
5761 test_fullname2_helper("WenQuanYi Micro Hei");
5762 test_fullname2_helper("MS UI Gothic");
5763 test_fullname2_helper("Ume UI Gothic");
5764 test_fullname2_helper("MS Gothic");
5765 test_fullname2_helper("Ume Gothic");
5766 test_fullname2_helper("MS PGothic");
5767 test_fullname2_helper("Ume P Gothic");
5768 test_fullname2_helper("Gulim");
5769 test_fullname2_helper("Batang");
5770 test_fullname2_helper("UnBatang");
5771 test_fullname2_helper("UnDotum");
5772 test_fullname2_helper("@SimSun");
5773 test_fullname2_helper("@NSimSun");
5774 test_fullname2_helper("@MingLiu");
5775 test_fullname2_helper("@PMingLiu");
5776 test_fullname2_helper("@WenQuanYi Micro Hei");
5777 test_fullname2_helper("@MS UI Gothic");
5778 test_fullname2_helper("@Ume UI Gothic");
5779 test_fullname2_helper("@MS Gothic");
5780 test_fullname2_helper("@Ume Gothic");
5781 test_fullname2_helper("@MS PGothic");
5782 test_fullname2_helper("@Ume P Gothic");
5783 test_fullname2_helper("@Gulim");
5784 test_fullname2_helper("@Batang");
5785 test_fullname2_helper("@UnBatang");
5786 test_fullname2_helper("@UnDotum");
5790 static void test_GetGlyphOutline_empty_contour(void)
5792 HDC hdc;
5793 LOGFONTA lf;
5794 HFONT hfont, hfont_prev;
5795 TTPOLYGONHEADER *header;
5796 GLYPHMETRICS gm;
5797 char buf[1024];
5798 DWORD ret;
5800 memset(&lf, 0, sizeof(lf));
5801 lf.lfHeight = 72;
5802 lstrcpyA(lf.lfFaceName, "wine_test");
5804 hfont = CreateFontIndirectA(&lf);
5805 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
5807 hdc = GetDC(NULL);
5809 hfont_prev = SelectObject(hdc, hfont);
5810 ok(hfont_prev != NULL, "SelectObject failed\n");
5812 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5813 ok(ret == 228, "GetGlyphOutline returned %ld, expected 228\n", ret);
5815 header = (TTPOLYGONHEADER*)buf;
5816 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5817 ok(ret == 228, "GetGlyphOutline returned %ld, expected 228\n", ret);
5818 ok(header->cb == 36, "header->cb = %ld, expected 36\n", header->cb);
5819 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %ld, expected TT_POLYGON_TYPE\n", header->dwType);
5820 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5821 ok(header->cb == 96, "header->cb = %ld, expected 96\n", header->cb);
5822 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5823 ok(header->cb == 96, "header->cb = %ld, expected 96\n", header->cb);
5825 SelectObject(hdc, hfont_prev);
5826 DeleteObject(hfont);
5827 ReleaseDC(NULL, hdc);
5830 static void test_GetGlyphOutline_metric_clipping(void)
5832 HDC hdc;
5833 LOGFONTA lf;
5834 HFONT hfont, hfont_prev;
5835 GLYPHMETRICS gm;
5836 TEXTMETRICA tm;
5837 TEXTMETRICW tmW;
5838 DWORD ret;
5840 memset(&lf, 0, sizeof(lf));
5841 lf.lfHeight = 72;
5842 lstrcpyA(lf.lfFaceName, "wine_test");
5844 SetLastError(0xdeadbeef);
5845 hfont = CreateFontIndirectA(&lf);
5846 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
5848 hdc = GetDC(NULL);
5850 hfont_prev = SelectObject(hdc, hfont);
5851 ok(hfont_prev != NULL, "SelectObject failed\n");
5853 SetLastError(0xdeadbeef);
5854 ret = GetTextMetricsA(hdc, &tm);
5855 ok(ret, "GetTextMetrics error %lu\n", GetLastError());
5857 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5858 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5859 "Glyph top(%ld) exceeds ascent(%ld)\n",
5860 gm.gmptGlyphOrigin.y, tm.tmAscent);
5861 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5862 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5863 "Glyph bottom(%ld) exceeds descent(%ld)\n",
5864 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5866 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5867 GetTextMetricsW(hdc, &tmW);
5868 todo_wine
5869 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5871 SelectObject(hdc, hfont_prev);
5872 DeleteObject(hfont);
5873 ReleaseDC(NULL, hdc);
5876 static void test_GetGlyphOutline_character(void)
5878 HFONT hfont, hfont_old;
5879 LOGFONTA lf;
5880 HDC hdc;
5881 DWORD ret;
5882 GLYPHMETRICS gm1, gm2, gmn;
5883 char test_chars[] = { 'A', 'D', '!', '\0' };
5884 char *current_char;
5886 memset(&lf, 0, sizeof(lf));
5887 lf.lfHeight = 72;
5888 lstrcpyA(lf.lfFaceName, "wine_test");
5890 hfont = CreateFontIndirectA(&lf);
5891 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
5893 hdc = GetDC(NULL);
5895 hfont_old = SelectObject(hdc, hfont);
5896 ok(hfont_old != NULL, "SelectObject failed\n");
5898 ret = GetGlyphOutlineW(hdc, 'Z', GGO_METRICS, &gmn, 0, NULL, &mat);
5899 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed to default to .notdef for character 'Z'\n");
5901 for (current_char = test_chars; *current_char != '\0'; current_char++)
5903 ret = GetGlyphOutlineW(hdc, *current_char, GGO_METRICS, &gm1, 0, NULL, &mat);
5904 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed for '%c'\n", *current_char);
5905 ok(memcmp(&gm1, &gmn, sizeof(gmn)) != 0, "the test character '%c' matches .notdef\n", *current_char);
5907 ret = GetGlyphOutlineW(hdc, 0x10000 + *current_char, GGO_METRICS, &gm2, 0, NULL, &mat);
5908 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed for 0x10000 + '%c'\n", *current_char);
5909 ok(memcmp(&gm1, &gm2, sizeof(gmn)) == 0, "GetGlyphOutlineW returned wrong metrics for character 0x10000 + '%c'\n", *current_char);
5912 ret = GetGlyphOutlineW(hdc, 0x3, GGO_METRICS|GGO_GLYPH_INDEX, &gm1, 0, NULL, &mat);
5913 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed for glyph index 0x3\n");
5915 ret = GetGlyphOutlineW(hdc, 0xFFFF, GGO_METRICS|GGO_GLYPH_INDEX, &gm2, 0, NULL, &mat);
5916 ok(ret == GDI_ERROR, "GetGlyphOutlineW for nonexistent glyph index 0xFFFF has succeeded\n");
5918 ret = GetGlyphOutlineW(hdc, 0x10003, GGO_METRICS|GGO_GLYPH_INDEX, &gm2, 0, NULL, &mat);
5919 ok(ret != GDI_ERROR, "GetGlyphOutlineW for index 0x10003 has failed\n");
5920 ok(memcmp(&gm1, &gm2, sizeof(gmn)) == 0, "GetGlyphOutlineW returned wrong metrics for glyph 0x10003\n");
5922 SelectObject(hdc, hfont_old);
5923 DeleteObject(hfont);
5924 ReleaseDC(NULL, hdc);
5927 static void test_fstype_fixup(void)
5929 HDC hdc;
5930 LOGFONTA lf;
5931 HFONT hfont, hfont_prev;
5932 DWORD ret;
5933 OUTLINETEXTMETRICA *otm;
5934 DWORD otm_size;
5936 memset(&lf, 0, sizeof(lf));
5937 lf.lfHeight = 72;
5938 lstrcpyA(lf.lfFaceName, "wine_test");
5940 SetLastError(0xdeadbeef);
5941 hfont = CreateFontIndirectA(&lf);
5942 ok(hfont != 0, "CreateFontIndirectA error %lu\n", GetLastError());
5944 hdc = GetDC(NULL);
5946 hfont_prev = SelectObject(hdc, hfont);
5947 ok(hfont_prev != NULL, "SelectObject failed\n");
5949 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5950 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5951 otm->otmSize = sizeof(*otm);
5952 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
5953 ok(ret == otm->otmSize, "expected %u, got %lu, error %ld\n", otm->otmSize, ret, GetLastError());
5955 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5956 valid bits are 1, 2, 3, 8, 9. */
5957 ok((otm->otmfsType & ~0x30e) == 0, "fsType %#x\n", otm->otmfsType);
5959 HeapFree(GetProcessHeap(), 0, otm);
5961 SelectObject(hdc, hfont_prev);
5962 DeleteObject(hfont);
5963 ReleaseDC(NULL, hdc);
5966 static void test_CreateScalableFontResource(void)
5968 char ttf_name[MAX_PATH];
5969 char tmp_path[MAX_PATH];
5970 char fot_name[MAX_PATH];
5971 char *file_part;
5972 DWORD ret;
5973 int i;
5975 if (!write_ttf_file("wine_test.ttf", ttf_name))
5977 skip("Failed to create ttf file for testing\n");
5978 return;
5981 trace("created %s\n", ttf_name);
5983 ret = is_truetype_font_installed("wine_test");
5984 ok(!ret, "font wine_test should not be enumerated\n");
5986 ret = GetTempPathA(MAX_PATH, tmp_path);
5987 ok(ret, "GetTempPath() error %ld\n", GetLastError());
5988 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5989 ok(ret, "GetTempFileName() error %ld\n", GetLastError());
5991 ret = GetFileAttributesA(fot_name);
5992 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5994 SetLastError(0xdeadbeef);
5995 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5996 ok(!ret, "CreateScalableFontResource() should fail\n");
5997 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %ld\n", GetLastError());
5999 SetLastError(0xdeadbeef);
6000 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
6001 ok(!ret, "CreateScalableFontResource() should fail\n");
6002 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %ld\n", GetLastError());
6004 file_part = strrchr(ttf_name, '\\');
6005 SetLastError(0xdeadbeef);
6006 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
6007 ok(!ret, "CreateScalableFontResource() should fail\n");
6008 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %ld\n", GetLastError());
6010 SetLastError(0xdeadbeef);
6011 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
6012 ok(!ret, "CreateScalableFontResource() should fail\n");
6013 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %ld\n", GetLastError());
6015 SetLastError(0xdeadbeef);
6016 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
6017 ok(!ret, "CreateScalableFontResource() should fail\n");
6018 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %ld\n", GetLastError());
6020 ret = DeleteFileA(fot_name);
6021 ok(ret, "DeleteFile() error %ld\n", GetLastError());
6023 ret = RemoveFontResourceExA(fot_name, 0, 0);
6024 ok(!ret, "RemoveFontResourceEx() should fail\n");
6026 /* test public font resource */
6027 SetLastError(0xdeadbeef);
6028 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
6029 ok(ret, "CreateScalableFontResource() error %ld\n", GetLastError());
6031 ret = is_truetype_font_installed("wine_test");
6032 ok(!ret, "font wine_test should not be enumerated\n");
6034 SetLastError(0xdeadbeef);
6035 ret = AddFontResourceExA(fot_name, 0, 0);
6036 ok(ret, "AddFontResourceEx() error %ld\n", GetLastError());
6038 ret = is_truetype_font_installed("wine_test");
6039 ok(ret, "font wine_test should be enumerated\n");
6041 test_GetGlyphOutline_empty_contour();
6042 test_GetGlyphOutline_metric_clipping();
6043 test_GetGlyphOutline_character();
6044 test_fstype_fixup();
6046 ret = RemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
6047 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
6049 SetLastError(0xdeadbeef);
6050 ret = RemoveFontResourceExA(fot_name, 0, 0);
6051 ok(ret, "RemoveFontResourceEx() error %ld\n", GetLastError());
6053 ret = is_truetype_font_installed("wine_test");
6054 ok(!ret, "font wine_test should not be enumerated\n");
6056 ret = RemoveFontResourceExA(fot_name, 0, 0);
6057 ok(!ret, "RemoveFontResourceEx() should fail\n");
6059 /* test refcounting */
6060 for (i = 0; i < 5; i++)
6062 SetLastError(0xdeadbeef);
6063 ret = AddFontResourceExA(fot_name, 0, 0);
6064 ok(ret, "AddFontResourceEx() error %ld\n", GetLastError());
6066 for (i = 0; i < 5; i++)
6068 SetLastError(0xdeadbeef);
6069 ret = RemoveFontResourceExA(fot_name, 0, 0);
6070 ok(ret, "RemoveFontResourceEx() error %ld\n", GetLastError());
6072 ret = RemoveFontResourceExA(fot_name, 0, 0);
6073 ok(!ret, "RemoveFontResourceEx() should fail\n");
6075 DeleteFileA(fot_name);
6077 /* test hidden font resource */
6078 SetLastError(0xdeadbeef);
6079 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
6080 ok(ret, "CreateScalableFontResource() error %ld\n", GetLastError());
6082 ret = is_truetype_font_installed("wine_test");
6083 ok(!ret, "font wine_test should not be enumerated\n");
6085 SetLastError(0xdeadbeef);
6086 ret = AddFontResourceExA(fot_name, 0, 0);
6087 ok(ret, "AddFontResourceEx() error %ld\n", GetLastError());
6089 ret = is_truetype_font_installed("wine_test");
6090 todo_wine
6091 ok(!ret, "font wine_test should not be enumerated\n");
6093 /* XP allows removing a private font added with 0 flags */
6094 SetLastError(0xdeadbeef);
6095 ret = RemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
6096 ok(ret, "RemoveFontResourceEx() error %ld\n", GetLastError());
6098 ret = is_truetype_font_installed("wine_test");
6099 ok(!ret, "font wine_test should not be enumerated\n");
6101 ret = RemoveFontResourceExA(fot_name, 0, 0);
6102 ok(!ret, "RemoveFontResourceEx() should fail\n");
6104 DeleteFileA(fot_name);
6105 DeleteFileA(ttf_name);
6108 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
6110 LOGFONTA lf;
6111 HFONT hfont, hfont_prev;
6112 HDC hdc;
6113 char facename[100];
6114 DWORD ret;
6115 static const WCHAR str[] = { 0x2025 };
6117 *installed = is_truetype_font_installed(name);
6119 lf.lfHeight = -18;
6120 lf.lfWidth = 0;
6121 lf.lfEscapement = 0;
6122 lf.lfOrientation = 0;
6123 lf.lfWeight = FW_DONTCARE;
6124 lf.lfItalic = 0;
6125 lf.lfUnderline = 0;
6126 lf.lfStrikeOut = 0;
6127 lf.lfCharSet = DEFAULT_CHARSET;
6128 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
6129 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6130 lf.lfQuality = DEFAULT_QUALITY;
6131 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6132 strcpy(lf.lfFaceName, name);
6134 hfont = CreateFontIndirectA(&lf);
6135 ok(hfont != NULL, "CreateFontIndirectA failed\n");
6137 hdc = GetDC(NULL);
6139 hfont_prev = SelectObject(hdc, hfont);
6140 ok(hfont_prev != NULL, "SelectObject failed\n");
6142 ret = GetTextFaceA(hdc, sizeof facename, facename);
6143 ok(ret, "GetTextFaceA failed\n");
6144 *selected = !strcmp(facename, name);
6146 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
6147 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
6148 if (!*selected)
6149 memset(gm, 0, sizeof *gm);
6151 ret = GetGlyphIndicesW(hdc, str, 1, gi, 0);
6152 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
6154 SelectObject(hdc, hfont_prev);
6155 DeleteObject(hfont);
6156 ReleaseDC(NULL, hdc);
6159 static void check_vertical_metrics(const char *face)
6161 LOGFONTA lf;
6162 HFONT hfont, hfont_prev;
6163 HDC hdc;
6164 DWORD ret;
6165 GLYPHMETRICS rgm, vgm;
6166 const UINT code = 0x5EAD, height = 1000;
6167 WORD idx;
6168 ABC abc, vabc;
6169 OUTLINETEXTMETRICA otm;
6170 USHORT numOfLongVerMetrics;
6172 hdc = GetDC(NULL);
6174 memset(&lf, 0, sizeof(lf));
6175 strcpy(lf.lfFaceName, face);
6176 lf.lfHeight = -height;
6177 lf.lfCharSet = DEFAULT_CHARSET;
6178 lf.lfEscapement = lf.lfOrientation = 900;
6179 hfont = CreateFontIndirectA(&lf);
6180 hfont_prev = SelectObject(hdc, hfont);
6181 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
6182 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
6183 ret = GetCharABCWidthsW(hdc, code, code, &abc);
6184 ok(ret, "GetCharABCWidthsW failed\n");
6185 DeleteObject(SelectObject(hdc, hfont_prev));
6187 memset(&lf, 0, sizeof(lf));
6188 strcpy(lf.lfFaceName, "@");
6189 strcat(lf.lfFaceName, face);
6190 lf.lfHeight = -height;
6191 lf.lfCharSet = DEFAULT_CHARSET;
6192 hfont = CreateFontIndirectA(&lf);
6193 hfont_prev = SelectObject(hdc, hfont);
6194 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
6195 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
6196 ret = GetCharABCWidthsW(hdc, code, code, &vabc);
6197 ok(ret, "GetCharABCWidthsW failed\n");
6198 ok(vabc.abcA == vgm.gmptGlyphOrigin.x, "expected %d, got %ld\n",
6199 vabc.abcA, vgm.gmptGlyphOrigin.x);
6200 ok(vabc.abcB == vgm.gmBlackBoxX, "expected %d, got %d\n",
6201 vabc.abcB, vgm.gmBlackBoxX);
6202 ok(vabc.abcA + vabc.abcB + vabc.abcC == vgm.gmCellIncX,
6203 "expected %d, got %d\n",
6204 vabc.abcA + vabc.abcB + vabc.abcC, vgm.gmCellIncX);
6206 memset(&otm, 0, sizeof(otm));
6207 otm.otmSize = sizeof(otm);
6208 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
6209 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
6211 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
6212 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
6213 int offset;
6214 SHORT topSideBearing;
6216 ret = GetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
6217 ok(ret != 0, "GetGlyphIndicesW failed\n");
6218 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
6219 if (numOfLongVerMetrics > idx)
6220 offset = idx * 2 + 1;
6221 else
6222 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
6223 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
6224 &topSideBearing, sizeof(SHORT));
6225 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
6226 topSideBearing = GET_BE_WORD(topSideBearing);
6227 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
6228 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
6229 "expected %d, got %ld\n",
6230 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
6232 else
6234 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
6235 "got %ld, expected rgm.origin.x(%ld) + vgm.cellIncX(%d) + descent(%d)\n",
6236 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
6239 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent,
6240 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6241 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
6243 DeleteObject(SelectObject(hdc, hfont_prev));
6244 ReleaseDC(NULL, hdc);
6247 static void test_vertical_font(void)
6249 char ttf_name[MAX_PATH];
6250 int num, i;
6251 BOOL ret, installed, selected;
6252 GLYPHMETRICS gm;
6253 WORD hgi, vgi;
6254 const char* face_list[] = {
6255 "@WineTestVertical", /* has vmtx table */
6256 "@Ume Gothic", /* doesn't have vmtx table */
6257 "@MS UI Gothic", /* has vmtx table, available on native */
6260 if (!write_ttf_file("vertical.ttf", ttf_name))
6262 skip("Failed to create ttf file for testing\n");
6263 return;
6266 num = AddFontResourceExA(ttf_name, FR_PRIVATE, 0);
6267 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6269 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
6270 ok(installed, "WineTestVertical is not installed\n");
6271 ok(selected, "WineTestVertical is not selected\n");
6272 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6273 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6274 gm.gmBlackBoxX, gm.gmBlackBoxY);
6276 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
6277 ok(installed, "@WineTestVertical is not installed\n");
6278 ok(selected, "@WineTestVertical is not selected\n");
6279 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6280 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6281 gm.gmBlackBoxX, gm.gmBlackBoxY);
6283 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
6285 for (i = 0; i < ARRAY_SIZE(face_list); i++) {
6286 const char* face = face_list[i];
6287 if (!is_truetype_font_installed(face)) {
6288 skip("%s is not installed\n", face);
6289 continue;
6291 check_vertical_metrics(&face[1]);
6294 ret = RemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
6295 ok(ret, "RemoveFontResourceEx() error %ld\n", GetLastError());
6297 DeleteFileA(ttf_name);
6300 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
6301 DWORD type, LPARAM lParam)
6303 if (lf->lfFaceName[0] == '@') {
6304 return 0;
6306 return 1;
6309 static void test_east_asian_font_selection(void)
6311 HDC hdc;
6312 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
6313 GB2312_CHARSET, CHINESEBIG5_CHARSET };
6314 size_t i;
6316 hdc = GetDC(NULL);
6318 for (i = 0; i < ARRAY_SIZE(charset); i++)
6320 LOGFONTA lf;
6321 HFONT hfont;
6322 char face_name[LF_FACESIZE];
6323 int ret;
6325 memset(&lf, 0, sizeof lf);
6326 lf.lfFaceName[0] = '\0';
6327 lf.lfCharSet = charset[i];
6329 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
6331 skip("Vertical font for charset %u is not installed\n", charset[i]);
6332 continue;
6335 hfont = CreateFontIndirectA(&lf);
6336 hfont = SelectObject(hdc, hfont);
6337 memset(face_name, 0, sizeof face_name);
6338 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6339 ok(ret && face_name[0] != '@',
6340 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
6341 DeleteObject(SelectObject(hdc, hfont));
6343 memset(&lf, 0, sizeof lf);
6344 strcpy(lf.lfFaceName, "@");
6345 lf.lfCharSet = charset[i];
6346 hfont = CreateFontIndirectA(&lf);
6347 hfont = SelectObject(hdc, hfont);
6348 memset(face_name, 0, sizeof face_name);
6349 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6350 ok(ret && face_name[0] == '@',
6351 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
6352 DeleteObject(SelectObject(hdc, hfont));
6354 ReleaseDC(NULL, hdc);
6357 static int get_font_dpi(const LOGFONTA *lf, int *height)
6359 HDC hdc = CreateCompatibleDC(0);
6360 HFONT hfont;
6361 TEXTMETRICA tm;
6362 int ret;
6364 hfont = CreateFontIndirectA(lf);
6365 ok(hfont != 0, "CreateFontIndirect failed\n");
6367 SelectObject(hdc, hfont);
6368 ret = GetTextMetricsA(hdc, &tm);
6369 ok(ret, "GetTextMetrics failed\n");
6370 ret = tm.tmDigitizedAspectX;
6371 if (height) *height = tm.tmHeight;
6373 DeleteDC(hdc);
6374 DeleteObject(hfont);
6376 return ret;
6379 static void test_stock_fonts(void)
6381 static const int font[] =
6383 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
6384 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6386 static const struct test_data
6388 int charset, weight, height, height_pixels, dpi;
6389 const char face_name[LF_FACESIZE];
6390 WORD lang_id;
6391 } td[][17] =
6393 { /* ANSI_FIXED_FONT */
6394 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
6395 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_HEBREW},
6396 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
6397 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
6398 { 0 }
6400 { /* ANSI_VAR_FONT */
6401 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
6402 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
6403 { 0 }
6405 { /* SYSTEM_FONT */
6406 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6407 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6408 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6409 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6410 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6411 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6412 { 0 }
6414 { /* DEVICE_DEFAULT_FONT */
6415 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6416 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6417 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6418 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6419 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6420 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6421 { 0 }
6423 { /* DEFAULT_GUI_FONT */
6424 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6425 { SHIFTJIS_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6426 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
6427 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
6428 { HANGEUL_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6429 { HANGEUL_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6430 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
6431 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
6432 { GB2312_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6433 { GB2312_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6434 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
6435 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
6436 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
6437 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
6438 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6439 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6440 { 0 }
6443 int i, j;
6445 for (i = 0; i < ARRAY_SIZE(font); i++)
6447 HFONT hfont;
6448 LOGFONTA lf;
6449 int ret, height;
6451 hfont = GetStockObject(font[i]);
6452 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
6454 ret = GetObjectA(hfont, sizeof(lf), &lf);
6455 ok(ret == sizeof(lf), "%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
6457 for (j = 0; td[i][j].face_name[0] != 0; j++)
6459 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) ||
6460 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) ||
6461 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name)))
6463 continue;
6466 ret = get_font_dpi(&lf, &height);
6467 if (ret != td[i][j].dpi)
6469 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6470 i, j, lf.lfFaceName, ret, td[i][j].dpi);
6471 continue;
6474 /* FIXME: Remove once Wine is fixed */
6475 todo_wine_if (td[i][j].dpi != 96 &&
6476 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6477 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
6478 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6479 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
6480 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6482 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %ld\n", i, j, td[i][j].weight, lf.lfWeight);
6483 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %ld\n", i, j, td[i][j].height, lf.lfHeight);
6484 if (td[i][j].face_name[0] == '?')
6486 /* Wine doesn't have this font, skip this case for now.
6487 Actually, the face name is localized on Windows and varies
6488 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6489 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
6491 else
6493 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);
6495 break;
6500 static void test_max_height(void)
6502 HDC hdc;
6503 LOGFONTA lf;
6504 HFONT hfont, hfont_old;
6505 TEXTMETRICA tm1, tm;
6506 BOOL r;
6507 LONG invalid_height[] = { -65536, -123456, 123456 };
6508 size_t i;
6510 memset(&tm1, 0, sizeof(tm1));
6511 memset(&lf, 0, sizeof(lf));
6512 strcpy(lf.lfFaceName, "Tahoma");
6513 lf.lfHeight = -1;
6515 hdc = GetDC(NULL);
6517 /* get 1 ppem value */
6518 hfont = CreateFontIndirectA(&lf);
6519 hfont_old = SelectObject(hdc, hfont);
6520 r = GetTextMetricsA(hdc, &tm1);
6521 ok(r, "GetTextMetrics failed\n");
6522 ok(tm1.tmHeight > 0, "expected a positive value, got %ld\n", tm1.tmHeight);
6523 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %ld\n", tm1.tmHeight);
6524 DeleteObject(SelectObject(hdc, hfont_old));
6526 /* test the largest value */
6527 lf.lfHeight = -((1 << 16) - 1);
6528 hfont = CreateFontIndirectA(&lf);
6529 hfont_old = SelectObject(hdc, hfont);
6530 memset(&tm, 0, sizeof(tm));
6531 r = GetTextMetricsA(hdc, &tm);
6532 ok(r, "GetTextMetrics failed\n");
6533 ok(tm.tmHeight > tm1.tmHeight,
6534 "expected greater than 1 ppem value (%ld), got %ld\n", tm1.tmHeight, tm.tmHeight);
6535 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
6536 "expected greater than 1 ppem value (%ld), got %ld\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6537 DeleteObject(SelectObject(hdc, hfont_old));
6539 /* test an invalid value */
6540 for (i = 0; i < ARRAY_SIZE(invalid_height); i++) {
6541 winetest_push_context("height=%ld", invalid_height[i]);
6542 lf.lfHeight = invalid_height[i];
6543 hfont = CreateFontIndirectA(&lf);
6544 hfont_old = SelectObject(hdc, hfont);
6545 memset(&tm, 0, sizeof(tm));
6546 r = GetTextMetricsA(hdc, &tm);
6547 ok(r, "GetTextMetrics failed\n");
6548 ok(tm.tmHeight == tm1.tmHeight,
6549 "expected 1 ppem value (%ld), got %ld\n", tm1.tmHeight, tm.tmHeight);
6550 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
6551 "expected 1 ppem value (%ld), got %ld\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6552 DeleteObject(SelectObject(hdc, hfont_old));
6553 winetest_pop_context();
6556 ReleaseDC(NULL, hdc);
6557 return;
6560 static void test_vertical_order(void)
6562 struct enum_font_data efd;
6563 LOGFONTA lf;
6564 HDC hdc;
6565 int i, j;
6567 hdc = CreateCompatibleDC(0);
6568 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6570 memset(&lf, 0, sizeof(lf));
6571 lf.lfCharSet = DEFAULT_CHARSET;
6572 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6573 lf.lfHeight = 16;
6574 lf.lfWidth = 16;
6575 lf.lfQuality = DEFAULT_QUALITY;
6576 lf.lfItalic = FALSE;
6577 lf.lfWeight = FW_DONTCARE;
6578 memset( &efd, 0, sizeof(efd) );
6579 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
6580 for (i = 0; i < efd.total; i++)
6582 if (efd.lf[i].lfFaceName[0] != '@') continue;
6583 for (j = 0; j < efd.total; j++)
6585 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
6587 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
6588 break;
6592 heap_free( efd.lf );
6593 DeleteDC( hdc );
6596 static void test_GetCharWidth32(void)
6598 BOOL ret;
6599 HDC hdc;
6600 LOGFONTA lf;
6601 HFONT hfont;
6602 INT bufferA;
6603 INT bufferW;
6604 HWND hwnd;
6606 memset(&lf, 0, sizeof(lf));
6607 strcpy(lf.lfFaceName, "System");
6608 lf.lfHeight = 20;
6610 hfont = CreateFontIndirectA(&lf);
6611 hdc = GetDC(0);
6612 hfont = SelectObject(hdc, hfont);
6614 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6615 ok(ret, "GetCharWidth32W should have succeeded\n");
6616 ret = GetCharWidth32A(hdc, 'a', 'a', &bufferA);
6617 ok(ret, "GetCharWidth32A should have succeeded\n");
6618 ok (bufferA == bufferW, "Widths should be the same\n");
6619 ok (bufferA > 0," Width should be greater than zero\n");
6621 hfont = SelectObject(hdc, hfont);
6622 DeleteObject(hfont);
6623 ReleaseDC(NULL, hdc);
6625 memset(&lf, 0, sizeof(lf));
6626 strcpy(lf.lfFaceName, "Tahoma");
6627 lf.lfHeight = 20;
6629 hfont = CreateFontIndirectA(&lf);
6630 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
6631 0, 0, 0, NULL);
6632 hdc = GetDC(hwnd);
6633 SetMapMode( hdc, MM_ANISOTROPIC );
6634 SelectObject(hdc, hfont);
6636 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6637 ok(ret, "GetCharWidth32W should have succeeded\n");
6638 ok (bufferW > 0," Width should be greater than zero\n");
6639 SetWindowExtEx(hdc, -1,-1,NULL);
6640 SetGraphicsMode(hdc, GM_COMPATIBLE);
6641 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6642 ok(ret, "GetCharWidth32W should have succeeded\n");
6643 ok (bufferW > 0," Width should be greater than zero\n");
6644 SetGraphicsMode(hdc, GM_ADVANCED);
6645 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6646 ok(ret, "GetCharWidth32W should have succeeded\n");
6647 ok (bufferW > 0," Width should be greater than zero\n");
6648 SetWindowExtEx(hdc, 1,1,NULL);
6649 SetGraphicsMode(hdc, GM_COMPATIBLE);
6650 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6651 ok(ret, "GetCharWidth32W should have succeeded\n");
6652 ok (bufferW > 0," Width should be greater than zero\n");
6653 SetGraphicsMode(hdc, GM_ADVANCED);
6654 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6655 ok(ret, "GetCharWidth32W should have succeeded\n");
6656 ok (bufferW > 0," Width should be greater than zero\n");
6658 ReleaseDC(hwnd, hdc);
6659 DestroyWindow(hwnd);
6661 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
6662 0, 0, 0, NULL);
6663 hdc = GetDC(hwnd);
6664 SetMapMode( hdc, MM_ANISOTROPIC );
6665 SelectObject(hdc, hfont);
6667 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6668 ok(ret, "GetCharWidth32W should have succeeded\n");
6669 ok (bufferW > 0," Width should be greater than zero\n");
6670 SetWindowExtEx(hdc, -1,-1,NULL);
6671 SetGraphicsMode(hdc, GM_COMPATIBLE);
6672 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6673 ok(ret, "GetCharWidth32W should have succeeded\n");
6674 ok (bufferW > 0," Width should be greater than zero\n");
6675 SetGraphicsMode(hdc, GM_ADVANCED);
6676 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6677 ok(ret, "GetCharWidth32W should have succeeded\n");
6678 ok (bufferW > 0," Width should be greater than zero\n");
6679 SetWindowExtEx(hdc, 1,1,NULL);
6680 SetGraphicsMode(hdc, GM_COMPATIBLE);
6681 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6682 ok(ret, "GetCharWidth32W should have succeeded\n");
6683 ok (bufferW > 0," Width should be greater than zero\n");
6684 SetGraphicsMode(hdc, GM_ADVANCED);
6685 ret = GetCharWidth32W(hdc, 'a', 'a', &bufferW);
6686 ok(ret, "GetCharWidth32W should have succeeded\n");
6687 ok (bufferW > 0," Width should be greater than zero\n");
6689 ReleaseDC(hwnd, hdc);
6690 DestroyWindow(hwnd);
6691 DeleteObject(hfont);
6694 static void test_fake_bold_font(void)
6696 static const MAT2 x2_mat = { {0,2}, {0,0}, {0,0}, {0,2} };
6697 HDC hdc;
6698 LOGFONTA lf;
6699 BOOL ret;
6700 struct glyph_data {
6701 TEXTMETRICA tm;
6702 ABC abc;
6703 INT w;
6704 GLYPHMETRICS gm;
6705 } data[4];
6706 int i;
6707 DWORD r;
6709 /* Test outline font */
6710 memset(&lf, 0, sizeof(lf));
6711 strcpy(lf.lfFaceName, "Wingdings");
6712 lf.lfCharSet = SYMBOL_CHARSET;
6714 hdc = GetDC(NULL);
6716 for (i = 0; i <= 1; i++)
6718 HFONT hfont, hfont_old;
6720 lf.lfWeight = i ? FW_BOLD : FW_NORMAL;
6721 hfont = CreateFontIndirectA(&lf);
6722 hfont_old = SelectObject(hdc, hfont);
6724 ret = GetTextMetricsA(hdc, &data[i].tm);
6725 ok(ret, "got %d\n", ret);
6726 ret = GetCharABCWidthsA(hdc, 0x76, 0x76, &data[i].abc);
6727 ok(ret, "got %d\n", ret);
6728 data[i].w = data[i].abc.abcA + data[i].abc.abcB + data[i].abc.abcC;
6729 r = GetGlyphOutlineA(hdc, 0x76, GGO_METRICS, &data[i].gm, 0, NULL, &x2_mat);
6730 ok(r != GDI_ERROR, "got %d\n", ret);
6732 SelectObject(hdc, hfont_old);
6733 DeleteObject(hfont);
6735 ReleaseDC(NULL, hdc);
6737 /* compare results (outline) */
6738 ok(data[0].tm.tmHeight == data[1].tm.tmHeight,
6739 "expected %ld, got %ld\n", data[0].tm.tmHeight, data[1].tm.tmHeight);
6740 ok(data[0].tm.tmAscent == data[1].tm.tmAscent,
6741 "expected %ld, got %ld\n", data[0].tm.tmAscent, data[1].tm.tmAscent);
6742 ok(data[0].tm.tmDescent == data[1].tm.tmDescent,
6743 "expected %ld, got %ld\n", data[0].tm.tmDescent, data[1].tm.tmDescent);
6744 ok(data[0].tm.tmAveCharWidth + 1 == data[1].tm.tmAveCharWidth,
6745 "expected %ld, got %ld\n", data[0].tm.tmAveCharWidth + 1, data[1].tm.tmAveCharWidth);
6746 ok(data[0].tm.tmMaxCharWidth + 1 == data[1].tm.tmMaxCharWidth,
6747 "expected %ld, got %ld\n", data[0].tm.tmMaxCharWidth + 1, data[1].tm.tmMaxCharWidth);
6748 ok(data[0].tm.tmOverhang == data[1].tm.tmOverhang,
6749 "expected %ld, got %ld\n", data[0].tm.tmOverhang, data[1].tm.tmOverhang);
6750 ok(data[0].w + 1 == data[1].w,
6751 "expected %d, got %d\n", data[0].w + 1, data[1].w);
6753 ok(data[0].gm.gmCellIncX + 1 == data[1].gm.gmCellIncX,
6754 "expected %d, got %d\n", data[0].gm.gmCellIncX + 1, data[1].gm.gmCellIncX);
6755 ok(data[0].gm.gmCellIncY == data[1].gm.gmCellIncY,
6756 "expected %d, got %d\n", data[0].gm.gmCellIncY, data[1].gm.gmCellIncY);
6758 /* Test bitmap font */
6759 memset(&data, 0xaa, sizeof(data));
6760 memset(&lf, 0, sizeof(lf));
6761 strcpy(lf.lfFaceName, "Courier");
6762 lf.lfCharSet = ANSI_CHARSET;
6764 hdc = GetDC(NULL);
6766 for (i = 0; i < 4; i++)
6768 HFONT hfont, hfont_old;
6770 lf.lfWeight = (i % 2) ? FW_BOLD : FW_NORMAL;
6771 lf.lfHeight = (i > 1) ? data[0].tm.tmHeight * x2_mat.eM11.value : 0;
6772 hfont = CreateFontIndirectA(&lf);
6773 hfont_old = SelectObject(hdc, hfont);
6775 ret = GetTextMetricsA(hdc, &data[i].tm);
6776 ok(ret, "got %d\n", ret);
6777 ret = GetCharWidth32A(hdc, 0x76, 0x76, &data[i].w);
6778 ok(ret, "got %d\n", ret);
6780 SelectObject(hdc, hfont_old);
6781 DeleteObject(hfont);
6783 ReleaseDC(NULL, hdc);
6785 /* compare results (bitmap) */
6786 for (i = 0; i < 4; i+=2)
6788 int diff = (i > 1) ? x2_mat.eM11.value : 1;
6789 if (data[i].tm.tmPitchAndFamily & TMPF_TRUETYPE)
6791 skip("TrueType font is selected (expected a bitmap one)\n");
6792 continue;
6794 ok(data[i].tm.tmHeight == data[i+1].tm.tmHeight,
6795 "expected %ld, got %ld\n", data[i].tm.tmHeight, data[i+1].tm.tmHeight);
6796 ok(data[i].tm.tmAscent == data[i+1].tm.tmAscent,
6797 "expected %ld, got %ld\n", data[i].tm.tmAscent, data[i+1].tm.tmAscent);
6798 ok(data[i].tm.tmDescent == data[i+1].tm.tmDescent,
6799 "expected %ld, got %ld\n", data[i].tm.tmDescent, data[i+1].tm.tmDescent);
6800 ok(data[i+1].tm.tmAveCharWidth - data[i].tm.tmAveCharWidth == diff,
6801 "expected %d, got %ld\n", diff, data[i+1].tm.tmAveCharWidth - data[i].tm.tmAveCharWidth);
6802 ok(data[i+1].tm.tmMaxCharWidth - data[i].tm.tmMaxCharWidth == diff,
6803 "expected %d, got %ld\n", diff, data[i+1].tm.tmMaxCharWidth - data[i].tm.tmMaxCharWidth);
6804 ok(data[i].tm.tmOverhang == 0,
6805 "expected 0, got %ld\n", data[i].tm.tmOverhang);
6806 ok(data[i+1].tm.tmOverhang == 1,
6807 "expected 1, got %ld\n", data[i+1].tm.tmOverhang);
6808 ok(data[i].w + 1 == data[i+1].w,
6809 "expected %d, got %d\n", data[i].w + 1, data[i+1].w);
6813 static void test_bitmap_font_glyph_index(void)
6815 const WCHAR text[] = L"#!/bin/sh";
6816 const struct {
6817 LPCSTR face;
6818 BYTE charset;
6819 } bitmap_font_list[] = {
6820 { "Courier", ANSI_CHARSET },
6821 { "Small Fonts", ANSI_CHARSET },
6822 { "Fixedsys", DEFAULT_CHARSET },
6823 { "System", DEFAULT_CHARSET }
6825 HDC hdc;
6826 LOGFONTA lf;
6827 HFONT hFont;
6828 CHAR facename[LF_FACESIZE];
6829 BITMAPINFO bmi;
6830 HBITMAP hBmp[2];
6831 void *pixels[2];
6832 int i, j;
6833 DWORD ret;
6834 BITMAP bmp;
6835 TEXTMETRICA tm;
6836 CHARSETINFO ci;
6837 BYTE chr = '\xA9';
6839 hdc = CreateCompatibleDC(0);
6840 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6842 memset(&bmi, 0, sizeof(bmi));
6843 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
6844 bmi.bmiHeader.biBitCount = 32;
6845 bmi.bmiHeader.biPlanes = 1;
6846 bmi.bmiHeader.biWidth = 128;
6847 bmi.bmiHeader.biHeight = 32;
6848 bmi.bmiHeader.biCompression = BI_RGB;
6850 for (i = 0; i < ARRAY_SIZE(bitmap_font_list); i++) {
6851 memset(&lf, 0, sizeof(lf));
6852 lf.lfCharSet = bitmap_font_list[i].charset;
6853 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
6854 hFont = CreateFontIndirectA(&lf);
6855 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
6856 hFont = SelectObject(hdc, hFont);
6857 ret = GetTextMetricsA(hdc, &tm);
6858 ok(ret, "GetTextMetric failed\n");
6859 ret = GetTextFaceA(hdc, sizeof(facename), facename);
6860 ok(ret, "GetTextFace failed\n");
6861 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
6862 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
6863 continue;
6865 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
6866 skip("expected %s, got %s\n", lf.lfFaceName, facename);
6867 continue;
6870 for (j = 0; j < 2; j++) {
6871 HBITMAP hBmpPrev;
6872 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
6873 ok(hBmp[j] != NULL, "Can't create DIB\n");
6874 hBmpPrev = SelectObject(hdc, hBmp[j]);
6875 switch (j) {
6876 case 0:
6877 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
6878 break;
6879 case 1:
6881 int len = lstrlenW(text);
6882 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
6883 ret = GetGlyphIndicesW(hdc, text, len, indices, 0);
6884 ok(ret, "GetGlyphIndices failed\n");
6885 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
6886 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
6887 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
6888 HeapFree(GetProcessHeap(), 0, indices);
6889 break;
6892 ok(ret, "ExtTextOutW failed\n");
6893 SelectObject(hdc, hBmpPrev);
6896 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
6897 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6898 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6900 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
6901 if (!ret) {
6902 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6903 goto next;
6905 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
6906 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
6907 goto next;
6910 for (j = 0; j < 2; j++) {
6911 HBITMAP hBmpPrev;
6912 WORD code;
6913 hBmpPrev = SelectObject(hdc, hBmp[j]);
6914 switch (j) {
6915 case 0:
6916 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6917 break;
6918 case 1:
6919 ret = GetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6920 ok(ret, "GetGlyphIndices failed\n");
6921 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6922 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6923 break;
6925 ok(ret, "ExtTextOutA failed\n");
6926 SelectObject(hdc, hBmpPrev);
6929 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6930 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6931 next:
6932 for (j = 0; j < 2; j++)
6933 DeleteObject(hBmp[j]);
6934 hFont = SelectObject(hdc, hFont);
6935 DeleteObject(hFont);
6938 DeleteDC(hdc);
6941 static void test_GetCharWidthI(void)
6943 static const char *teststr = "wine ";
6944 HFONT hfont, prev_hfont;
6945 WORD glyphs[5];
6946 INT widths[5];
6947 INT width;
6948 LOGFONTA lf;
6949 ABC abc[5], abc1;
6950 int len, i;
6951 DWORD nb;
6952 BOOL ret;
6953 HDC hdc;
6955 memset(&lf, 0, sizeof(lf));
6956 strcpy(lf.lfFaceName, "Tahoma");
6957 lf.lfHeight = -20;
6959 hdc = GetDC(0);
6961 hfont = CreateFontIndirectA(&lf);
6962 prev_hfont = SelectObject(hdc, hfont);
6964 len = strlen(teststr);
6965 nb = GetGlyphIndicesA(hdc, teststr, len, glyphs, 0);
6966 ok(nb == len, "\n");
6968 memset(abc, 0xcc, sizeof(abc));
6969 ret = GetCharABCWidthsI(hdc, 0, len, glyphs, abc);
6970 ok(ret, "GetCharABCWidthsI failed\n");
6972 memset(&abc1, 0xcc, sizeof(abc1));
6973 ret = GetCharABCWidthsI(hdc, glyphs[0], 1, NULL, &abc1);
6974 ok(ret, "GetCharABCWidthsI failed\n");
6975 ok(!memcmp(&abc1, abc, sizeof(abc1)), "unexpected abc1\n");
6977 memset(widths, 0xcc, sizeof(widths));
6978 ret = GetCharWidthI(hdc, 0, len, glyphs, widths);
6979 ok(ret, "GetCharWidthI failed\n");
6981 width = 0xdeadbeef;
6982 ret = GetCharWidthI(hdc, glyphs[0], 1, NULL, &width);
6983 ok(ret, "GetCharWidthI failed\n");
6984 ok(width == widths[0], "unexpected width %u\n", width);
6986 for (i = 0; i < len; i++)
6987 ok(widths[i] == abc[i].abcA + abc[i].abcB + abc[i].abcC, "%u, glyph %u, got width %d\n",
6988 i, glyphs[i], widths[i]);
6990 DeleteObject(SelectObject(hdc, prev_hfont));
6991 ReleaseDC(0, hdc);
6994 static INT CALLBACK long_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lparam)
6996 BOOL *found_font = (BOOL *)lparam;
6997 *found_font = TRUE;
6998 return 1;
7001 static void test_long_names(void)
7003 char ttf_name[MAX_PATH];
7004 LOGFONTA font = {0};
7005 HFONT handle_font;
7006 BOOL found_font;
7007 int ret;
7008 HDC dc;
7010 if (!write_ttf_file("wine_longname.ttf", ttf_name))
7012 skip("Failed to create ttf file for testing\n");
7013 return;
7016 dc = GetDC(NULL);
7018 ret = AddFontResourceExA(ttf_name, FR_PRIVATE, 0);
7019 ok(ret, "AddFontResourceEx() failed\n");
7021 strcpy(font.lfFaceName, "wine_3_this_is_a_very_long_name");
7022 found_font = FALSE;
7023 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
7024 ok(found_font == TRUE, "EnumFontFamiliesExA didn't find font.\n");
7026 strcpy(font.lfFaceName, "wine_2_this_is_a_very_long_name");
7027 found_font = FALSE;
7028 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
7029 ok(found_font == TRUE, "EnumFontFamiliesExA didn't find font.\n");
7031 strcpy(font.lfFaceName, "wine_1_this_is_a_very_long_name");
7032 found_font = FALSE;
7033 EnumFontFamiliesExA(dc, &font, long_enum_proc, (LPARAM)&found_font, 0);
7034 ok(found_font == FALSE, "EnumFontFamiliesExA must not find font.\n");
7036 handle_font = CreateFontIndirectA(&font);
7037 ok(handle_font != NULL, "CreateFontIndirectA failed\n");
7038 DeleteObject(handle_font);
7040 ret = RemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
7041 ok(ret, "RemoveFontResourceEx() failed\n");
7043 DeleteFileA(ttf_name);
7044 ReleaseDC(NULL, dc);
7047 static void test_ttf_names(void)
7049 struct enum_fullname_data efnd;
7050 char ttf_name[MAX_PATH], ttf_name_bold[MAX_PATH];
7051 LOGFONTA font = {0};
7052 HFONT handle_font;
7053 int ret;
7054 HDC dc;
7056 if (!write_ttf_file("wine_ttfnames.ttf", ttf_name))
7058 skip("Failed to create ttf file for testing\n");
7059 return;
7062 if (!write_ttf_file("wine_ttfnames_bold.ttf", ttf_name_bold))
7064 skip("Failed to create ttf file for testing\n");
7065 DeleteFileA(ttf_name);
7066 return;
7069 ret = AddFontResourceExA(ttf_name, FR_PRIVATE, 0);
7070 ok(ret, "AddFontResourceEx() failed\n");
7072 ret = AddFontResourceExA(ttf_name_bold, FR_PRIVATE, 0);
7073 ok(ret, "AddFontResourceEx() failed\n");
7075 dc = GetDC(NULL);
7077 strcpy(font.lfFaceName, "Wine_TTF_Names_Long_Family1_Con");
7078 memset(&efnd, 0, sizeof(efnd));
7079 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7080 ok(efnd.total == 0, "EnumFontFamiliesExA must not find font.\n");
7082 /* Windows doesn't match with Typographic/Preferred Family tags */
7083 strcpy(font.lfFaceName, "Wine TTF Names Long Family1");
7084 memset(&efnd, 0, sizeof(efnd));
7085 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7086 ok(efnd.total == 0, "EnumFontFamiliesExA must not find font.\n");
7088 strcpy(font.lfFaceName, "Wine TTF Names Long Family1 Ext");
7089 memset(&efnd, 0, sizeof(efnd));
7090 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7091 ok(efnd.total == 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd.total);
7093 strcpy(font.lfFaceName, "Wine TTF Names Long Family1 Con");
7094 memset(&efnd, 0, sizeof(efnd));
7095 EnumFontFamiliesExA(dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0);
7096 ok(efnd.total == 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd.total);
7098 handle_font = CreateFontIndirectA(&font);
7099 ok(handle_font != NULL, "CreateFontIndirectA failed\n");
7100 DeleteObject(handle_font);
7102 ret = RemoveFontResourceExA(ttf_name_bold, FR_PRIVATE, 0);
7103 ok(ret, "RemoveFontResourceEx() failed\n");
7105 DeleteFileA(ttf_name_bold);
7107 ret = RemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
7108 ok(ret, "RemoveFontResourceEx() failed\n");
7110 DeleteFileA(ttf_name);
7111 ReleaseDC(NULL, dc);
7114 static void test_lang_names(void)
7116 static const WCHAR name_cond_ja_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja)";
7117 static const WCHAR name_cond_ja_reg_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg";
7118 static const WCHAR name_cond_ja_reg_ja_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg (ja)";
7119 static const WCHAR name_wws_ja_w[] = L"\x30d5\x30a9\x30f3\x30c8\x540d WWS (ja)";
7121 struct enum_fullname_data efnd;
7122 struct enum_fullname_data_w efnd_w;
7123 char ttf_name[MAX_PATH], ttf_name2[MAX_PATH], ttf_name3[MAX_PATH];
7124 LOGFONTA font = {0};
7125 LOGFONTW font_w = {0};
7126 int ret, i;
7127 HDC dc;
7128 const WCHAR *primary_family, *primary_fullname;
7130 if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH && PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE)
7132 skip( "Primary language is neither English nor Japanese, skipping test\n" );
7133 return;
7136 if (!write_ttf_file( "wine_langnames.ttf", ttf_name ))
7138 skip( "Failed to create ttf file for testing\n" );
7139 return;
7142 if (!write_ttf_file( "wine_langnames2.ttf", ttf_name2 ))
7144 skip( "Failed to create ttf file for testing\n" );
7145 DeleteFileA( ttf_name );
7146 return;
7149 if (!write_ttf_file( "wine_langnames3.ttf", ttf_name3 ))
7151 skip( "Failed to create ttf file for testing\n" );
7152 DeleteFileA( ttf_name2 );
7153 DeleteFileA( ttf_name );
7154 return;
7157 ret = AddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
7158 ok( ret, "AddFontResourceEx() failed\n" );
7160 dc = GetDC( NULL );
7162 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7164 primary_family = L"Wine Lang Cond (en)";
7165 primary_fullname = L"Wine Lang Cond Reg (en)";
7167 else
7169 primary_family = name_cond_ja_w;
7170 primary_fullname = name_cond_ja_reg_w;
7173 for (i = 0; i < 3; ++i)
7175 /* check that lookup by preferred or WWS family / full names or postscript FontName doesn't work */
7177 strcpy( font.lfFaceName, "Wine Lang (en)" );
7178 memset( &efnd, 0, sizeof(efnd) );
7179 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7180 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7182 strcpy( font.lfFaceName, "Wine Lang Condensed Bold (ko)" );
7183 memset( &efnd, 0, sizeof(efnd) );
7184 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7185 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7187 wcscpy( font_w.lfFaceName, name_wws_ja_w );
7188 memset( &efnd_w, 0, sizeof(efnd_w) );
7189 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7190 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7192 strcpy( font.lfFaceName, "Reg WWS (zh-tw)" );
7193 memset( &efnd, 0, sizeof(efnd) );
7194 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7195 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7197 strcpy( font.lfFaceName, "Wine Lang (en) Reg WWS (en)" );
7198 memset( &efnd, 0, sizeof(efnd) );
7199 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7200 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7202 strcpy( font.lfFaceName, "WineLangNamesRegular" );
7203 memset( &efnd, 0, sizeof(efnd) );
7204 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7205 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7207 /* then, the primary ttf family name always works */
7209 wcscpy( font_w.lfFaceName, primary_family );
7210 memset( &efnd_w, 0, sizeof(efnd_w) );
7211 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7212 ok( efnd_w.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7214 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7216 wcscpy( font_w.lfFaceName, name_cond_ja_w );
7217 memset( &efnd_w, 0, sizeof(efnd_w) );
7218 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7219 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7222 /* if there is no primary ttf family name, the english ttf name, or postscript FamilyName are used instead */
7224 strcpy( font.lfFaceName, "Wine_Lang_Names" );
7225 memset( &efnd, 0, sizeof(efnd) );
7226 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7227 if (i == 2)
7228 ok( efnd.total == 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7229 else
7230 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7232 /* same goes for ttf full names */
7234 wcscpy( font_w.lfFaceName, primary_fullname );
7235 memset( &efnd_w, 0, sizeof(efnd_w) );
7236 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7237 ok( efnd_w.total == 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7239 if (efnd_w.total >= 1)
7241 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfLogFont.lfFaceName, primary_family ),
7242 "%d: (%d) unexpected lfFaceName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfLogFont.lfFaceName) );
7243 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfFullName, primary_fullname ),
7244 "%d: (%d) unexpected elfFullName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfFullName) );
7245 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfStyle, PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH ? L"Reg (en)" : L"Reg (ja)" ),
7246 "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfStyle) );
7249 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7251 wcscpy( font_w.lfFaceName, name_cond_ja_reg_w );
7252 memset( &efnd_w, 0, sizeof(efnd_w) );
7253 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7254 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7257 wcscpy( font_w.lfFaceName, L"Wine_Lang_Names_Regular" );
7258 memset( &efnd_w, 0, sizeof(efnd_w) );
7259 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7260 ok( efnd_w.total == i, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7262 while (efnd_w.total--)
7264 ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfLogFont.lfFaceName, efnd_w.total == 1 ? L"Wine_Lang_Names" : primary_family ),
7265 "%d: (%d) unexpected lfFaceName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfLogFont.lfFaceName) );
7266 ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfFullName, L"Wine_Lang_Names_Regular" ),
7267 "%d: (%d) unexpected elfFullName %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfFullName) );
7268 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7269 ok( !wcscmp( (WCHAR *)efnd_w.elf[efnd_w.total].elfStyle, efnd_w.total == 1 ? L"Regular" : L"Reg (en)" ),
7270 "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[efnd_w.total].elfStyle) );
7271 else
7272 ok( !wcscmp( (WCHAR *)efnd_w.elf[0].elfStyle, L"Reg (ja)" ),
7273 "%d: (%d) unexpected elfStyle %s\n", i, efnd_w.total, debugstr_w((WCHAR *)efnd_w.elf[0].elfStyle) );
7276 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7278 wcscpy( font_w.lfFaceName, name_cond_ja_reg_ja_w );
7279 memset( &efnd_w, 0, sizeof(efnd_w) );
7280 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7281 ok( efnd_w.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd_w.total );
7284 /* another language can also be used for lookup, if the primary langid isn't english, then
7285 english seems to have priority, otherwise or if english is already the primary langid,
7286 the family name with the smallest langid is used as secondary lookup language. */
7288 strcpy( font.lfFaceName, "Wine Lang Cond (zh-tw)" );
7289 memset( &efnd, 0, sizeof(efnd) );
7290 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7291 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH)
7292 ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7293 else /* (zh-tw) doesn't match here probably because there's an (en) name too */
7294 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7296 strcpy( font.lfFaceName, "Wine Lang Cond (en)" );
7297 memset( &efnd, 0, sizeof(efnd) );
7298 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7299 /* either because it's the primary language, or because it's a secondary */
7300 ok( efnd.total == min( 2, i + 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7302 wcscpy( font_w.lfFaceName, L"Wine Police d'\xe9" "criture (fr)" );
7303 memset( &efnd_w, 0, sizeof(efnd_w) );
7304 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7305 /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */
7306 if (i == 2) ok( efnd_w.total == 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7307 else ok( efnd_w.total == 0, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7309 /* case matching should not depend on the current locale */
7310 if (i == 2)
7312 wcscpy( font_w.lfFaceName, L"Wine POLICE D'\xc9" "CRITURE (fr)" );
7313 memset( &efnd_w, 0, sizeof(efnd_w) );
7314 EnumFontFamiliesExW( dc, &font_w, enum_fullname_data_proc_w, (LPARAM)&efnd_w, 0 );
7315 ok( efnd_w.total == 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i, efnd_w.total );
7318 strcpy( font.lfFaceName, "Wine Lang Cond (ko)" );
7319 memset( &efnd, 0, sizeof(efnd) );
7320 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7321 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7323 /* that doesn't apply to full names */
7325 strcpy( font.lfFaceName, "Wine Lang Cond Reg (zh-tw)" );
7326 memset( &efnd, 0, sizeof(efnd) );
7327 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7328 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7330 strcpy( font.lfFaceName, "Wine Lang Cond Reg (fr)" );
7331 memset( &efnd, 0, sizeof(efnd) );
7332 EnumFontFamiliesExA( dc, &font, enum_fullname_data_proc, (LPARAM)&efnd, 0 );
7333 ok( efnd.total == 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i, efnd.total );
7335 if (i == 0)
7337 ret = AddFontResourceExA( ttf_name2, FR_PRIVATE, 0 );
7338 ok( ret, "AddFontResourceEx() failed\n" );
7340 else if (i == 1)
7342 ret = AddFontResourceExA( ttf_name3, FR_PRIVATE, 0 );
7343 ok( ret, "AddFontResourceEx() failed\n" );
7347 ret = RemoveFontResourceExA( ttf_name3, FR_PRIVATE, 0 );
7348 ok( ret, "RemoveFontResourceEx() failed\n" );
7350 DeleteFileA( ttf_name3 );
7352 ret = RemoveFontResourceExA( ttf_name2, FR_PRIVATE, 0 );
7353 ok( ret, "RemoveFontResourceEx() failed\n" );
7355 DeleteFileA( ttf_name2 );
7357 ret = RemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
7358 ok( ret, "RemoveFontResourceEx() failed\n" );
7360 DeleteFileA( ttf_name );
7361 ReleaseDC( NULL, dc );
7364 typedef struct
7366 USHORT majorVersion;
7367 USHORT minorVersion;
7368 SHORT ascender;
7369 SHORT descender;
7370 SHORT lineGap;
7371 USHORT advanceWidthMax;
7372 SHORT minLeftSideBearing;
7373 SHORT minRightSideBearing;
7374 SHORT xMaxExtent;
7375 SHORT caretSlopeRise;
7376 SHORT caretSlopeRun;
7377 SHORT caretOffset;
7378 SHORT reserved[4];
7379 SHORT metricDataFormat;
7380 SHORT numberOfHMetrics;
7381 } TT_Hori_Header;
7383 static void test_GetCharWidthInfo(void)
7385 HDC hdc;
7386 HFONT hfont, hfont_prev;
7387 LOGFONTA lf;
7388 BOOL r;
7389 DWORD ret, i;
7390 OUTLINETEXTMETRICA otm;
7391 TT_Hori_Header hhea;
7392 struct char_width_info
7394 INT lsb, rsb, unk;
7395 } info, info2;
7396 SHORT minLeftSideBearing, minRightSideBearing;
7397 POINT pt[2];
7398 const char* face_list[] = { "Symbol", "Ume Gothic", "MS Gothic" };
7400 if (!pGetCharWidthInfo)
7402 win_skip("GetCharWidthInfo is unavailable\n");
7403 return;
7406 hdc = GetDC(NULL);
7408 /* test default (System) font */
7409 memset(&info, 0xaa, sizeof(info));
7410 r = pGetCharWidthInfo(hdc, &info);
7411 if (r) /* win10 1803 succeeds */
7413 ok(info.lsb == 0, "expected 0, got %d\n", info.lsb);
7414 ok(info.rsb == 0, "expected 0, got %d\n", info.rsb);
7415 ok(info.unk == 0, "expected 0, got %d\n", info.unk);
7418 memset(&lf, 0, sizeof(lf));
7419 lf.lfWeight = FW_NORMAL;
7420 lf.lfCharSet = ANSI_CHARSET;
7421 strcpy(lf.lfFaceName, "Tahoma");
7422 hfont = CreateFontIndirectA(&lf);
7423 hfont_prev = SelectObject(hdc, hfont);
7424 ok(hfont_prev != NULL, "SelectObject failed\n");
7426 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
7427 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
7428 DeleteObject(SelectObject(hdc, hfont_prev));
7430 /* test Tahoma at the em square size */
7431 lf.lfHeight = -(int)otm.otmEMSquare;
7432 hfont = CreateFontIndirectA(&lf);
7433 hfont_prev = SelectObject(hdc, hfont);
7434 ok(hfont_prev != NULL, "SelectObject failed\n");
7436 ret = GetFontData(hdc, MS_MAKE_TAG('h','h','e','a'), 0, &hhea, sizeof(hhea));
7437 ok(ret == sizeof(hhea), "got %lu\n", ret);
7438 minLeftSideBearing = GET_BE_WORD(hhea.minLeftSideBearing);
7439 minRightSideBearing = GET_BE_WORD(hhea.minRightSideBearing);
7441 memset(&info, 0xaa, sizeof(info));
7442 r = pGetCharWidthInfo(hdc, &info);
7443 ok(r, "GetCharWidthInfo failed\n");
7444 ok(info.lsb == minLeftSideBearing, "expected %d, got %d\n", minLeftSideBearing, info.lsb);
7445 ok(info.rsb == minRightSideBearing, "expected %d, got %d\n", minRightSideBearing, info.rsb);
7447 DeleteObject(SelectObject(hdc, hfont_prev));
7449 /* these values are scaled, try with smaller size */
7450 lf.lfHeight /= 3;
7451 hfont = CreateFontIndirectA(&lf);
7452 hfont_prev = SelectObject(hdc, hfont);
7453 ok(hfont_prev != NULL, "SelectObject failed\n");
7455 memset(&info2, 0xaa, sizeof(info2));
7456 r = pGetCharWidthInfo(hdc, &info2);
7457 ok(r, "pGetCharWidthInfo failed\n");
7458 ok(info2.lsb == info.lsb/3, "expected %d, got %d\n", info.lsb/3, info2.lsb);
7459 ok(info2.rsb == info.rsb/3, "expected %d, got %d\n", info.rsb/3, info2.rsb);
7461 DeleteObject(SelectObject(hdc, hfont_prev));
7462 ReleaseDC(NULL, hdc);
7464 /* test with another mapping mode */
7465 hdc = GetDC(NULL);
7466 SetMapMode(hdc, MM_ISOTROPIC);
7467 SetWindowExtEx(hdc, 2, 2, NULL);
7468 SetViewportExtEx(hdc, 1, 1, NULL);
7470 memset(pt, 0, sizeof(pt));
7471 pt[0].y = otm.otmEMSquare;
7472 DPtoLP(hdc, pt, 1);
7474 memset(&lf, 0, sizeof(lf));
7475 lf.lfWeight = FW_NORMAL;
7476 lf.lfCharSet = ANSI_CHARSET;
7477 lf.lfHeight = -abs(pt[0].y);
7478 strcpy(lf.lfFaceName, "Tahoma");
7479 hfont = CreateFontIndirectA(&lf);
7480 hfont_prev = SelectObject(hdc, hfont);
7481 ok(hfont_prev != NULL, "SelectObject failed\n");
7483 memset(&info2, 0xaa, sizeof(info2));
7484 r = pGetCharWidthInfo(hdc, &info2);
7485 ok(r, "GetCharWidthInfo failed\n");
7486 pt[0].x = info.lsb; pt[0].y = 0;
7487 pt[1].x = info.rsb; pt[1].y = 0;
7488 DPtoLP(hdc, pt, 2);
7489 ok(pt[0].x == info2.lsb, "expected %ld, got %d\n", pt[0].x, info2.lsb);
7490 ok(pt[1].x == info2.rsb, "expected %ld, got %d\n", pt[1].x, info2.rsb);
7492 DeleteObject(SelectObject(hdc, hfont_prev));
7493 ReleaseDC(NULL, hdc);
7495 /* test with synthetic fonts */
7496 hdc = GetDC(NULL);
7497 for (i = 0; i < ARRAY_SIZE(face_list); i++)
7499 const char* face = face_list[i];
7500 if (!is_truetype_font_installed(face))
7502 skip("%s is not installed\n", face);
7503 continue;
7505 memset(&lf, 0, sizeof(lf));
7506 lf.lfWeight = FW_NORMAL;
7507 lf.lfItalic = FALSE;
7508 lf.lfCharSet = DEFAULT_CHARSET;
7509 lf.lfHeight = -256;
7510 strcpy(lf.lfFaceName, face);
7511 hfont = CreateFontIndirectA(&lf);
7512 hfont_prev = SelectObject(hdc, hfont);
7514 memset(&info, 0xaa, sizeof(info));
7515 r = pGetCharWidthInfo(hdc, &info);
7516 ok(r, "%s: GetCharWidthInfo failed\n", face);
7518 /* test with synthetic bold */
7519 lf.lfWeight = FW_BOLD;
7520 lf.lfItalic = FALSE;
7521 hfont = CreateFontIndirectA(&lf);
7522 DeleteObject(SelectObject(hdc, hfont));
7524 memset(&info2, 0xaa, sizeof(info2));
7525 r = pGetCharWidthInfo(hdc, &info2);
7526 ok(r, "%s: GetCharWidthInfo failed\n", face);
7527 ok(info.lsb == info2.lsb, "%s: expected %d, got %d\n", face, info.lsb, info2.lsb);
7528 ok(info.rsb == info2.rsb, "%s: expected %d, got %d\n", face, info.rsb, info2.rsb);
7530 /* test with synthetic italic */
7531 lf.lfWeight = FW_NORMAL;
7532 lf.lfItalic = TRUE;
7533 hfont = CreateFontIndirectA(&lf);
7534 DeleteObject(SelectObject(hdc, hfont));
7536 memset(&info2, 0xaa, sizeof(info2));
7537 r = pGetCharWidthInfo(hdc, &info2);
7538 ok(r, "%s: GetCharWidthInfo failed\n", face);
7539 todo_wine ok(info.lsb > info2.lsb, "%s: expected less than %d, got %d\n", face, info.lsb, info2.lsb);
7540 todo_wine ok(info.rsb > info2.rsb, "%s: expected less than %d, got %d\n", face, info.rsb, info2.rsb);
7541 DeleteObject(SelectObject(hdc, hfont_prev));
7544 ReleaseDC(NULL, hdc);
7547 static int CALLBACK get_char_width_proc(const LOGFONTA *lf,
7548 const TEXTMETRICA *tm, DWORD type, LPARAM ctx)
7550 HFONT font = CreateFontIndirectA(lf);
7551 HDC dc = GetDC(NULL);
7552 const char c = 'm';
7553 ABCFLOAT abcf;
7554 int i, i32;
7555 BOOL ret;
7556 float f;
7557 ABC abc;
7559 SelectObject(dc, font);
7561 ret = GetCharWidthFloatA(dc, c, c, &f);
7562 ok(ret, "%s: GetCharWidthFloat() failed\n", lf->lfFaceName);
7563 ret = GetCharWidth32A(dc, c, c, &i32);
7564 ok(ret, "%s: GetCharWidth32A() failed\n", lf->lfFaceName);
7565 ret = GetCharWidthA(dc, c, c, &i);
7566 ok(ret, "%s: GetCharWidthA() failed\n", lf->lfFaceName);
7567 ok(i == i32, "%s: mismatched widths %d/%d\n", lf->lfFaceName, i, i32);
7568 ok((float)i / 16.0f == f, "%s: mismatched widths %d/%.8e\n", lf->lfFaceName, i, f);
7570 ret = GetCharABCWidthsFloatA(dc, c, c, &abcf);
7571 ok(ret, "%s: GetCharABCWidths() failed\n", lf->lfFaceName);
7572 if (GetCharABCWidthsA(dc, c, c, &abc))
7573 ok((float)abc.abcB == abcf.abcfB, "%s: mismatched widths %d/%.8e\n",
7574 lf->lfFaceName, abc.abcB, abcf.abcfB);
7576 ReleaseDC(NULL, dc);
7577 DeleteObject(font);
7578 return 1;
7581 static void test_char_width(void)
7583 HDC dc = GetDC(NULL);
7584 LOGFONTA lf = {0};
7586 lf.lfCharSet = DEFAULT_CHARSET;
7587 EnumFontFamiliesExA(dc, &lf, get_char_width_proc, 0, 0);
7589 ReleaseDC(NULL, dc);
7592 static void test_GetCharacterPlacement_kerning(void)
7594 LOGFONTA lf;
7595 HFONT hfont, hfont_old;
7596 KERNINGPAIR *kp;
7597 HDC hdc;
7598 DWORD count, ret, i, size, width, width_kern, idx;
7599 WCHAR str[30];
7600 GCP_RESULTSW result;
7601 int kern[30], pos[30], pos_kern[30], dx[30], dx_kern[30], kern_amount;
7603 if (!is_font_installed("Arial"))
7605 skip("Arial is not installed, skipping the test\n");
7606 return;
7609 hdc = GetDC(0);
7611 memset(&lf, 0, sizeof(lf));
7612 strcpy(lf.lfFaceName, "Arial");
7613 lf.lfHeight = 120;
7614 hfont = CreateFontIndirectA(&lf);
7615 ok(hfont != NULL, "CreateFontIndirect failed\n");
7617 hfont_old = SelectObject(hdc, hfont);
7619 count = GetKerningPairsW(hdc, 0, NULL);
7620 kp = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*kp));
7622 ret = GetKerningPairsW(hdc, count, kp);
7623 ok(ret == count, "got %lu, expected %lu\n", ret, count);
7625 size = kern_amount = idx = 0;
7626 for (i = 0; i < count; i++)
7628 if (kp[i].wFirst >= 'A' && kp[i].wFirst <= 'z' &&
7629 kp[i].wSecond >= 'A' && kp[i].wSecond <= 'z')
7631 str[size++] = kp[i].wFirst;
7632 str[size++] = kp[i].wSecond;
7633 str[size++] = 0;
7634 kern[idx] = kp[i].iKernAmount;
7635 idx++;
7636 kern_amount += kp[i].iKernAmount;
7637 if (size >= ARRAY_SIZE(str)) break;
7641 HeapFree(GetProcessHeap(), 0, kp);
7643 count = size;
7645 memset(&result, 0, sizeof(result));
7646 result.lStructSize = sizeof(result);
7647 result.lpCaretPos = pos;
7648 result.lpDx = dx;
7649 result.nGlyphs = count;
7650 ret = GetCharacterPlacementW(hdc, str, count, 0, &result, 0);
7651 ok(ret, "GetCharacterPlacement failed\n");
7652 ok(result.nGlyphs == count, "got %u\n", result.nGlyphs);
7653 width = LOWORD(ret);
7655 memset(&result, 0, sizeof(result));
7656 result.lStructSize = sizeof(result);
7657 result.lpCaretPos = pos_kern;
7658 result.lpDx = dx_kern;
7659 result.nGlyphs = count;
7660 ret = GetCharacterPlacementW(hdc, str, count, 0, &result, GCP_USEKERNING);
7661 ok(ret, "GetCharacterPlacement failed\n");
7662 ok(result.nGlyphs == count, "got %u\n", result.nGlyphs);
7663 width_kern = LOWORD(ret);
7665 if (width == width_kern)
7667 win_skip("GCP_USEKERNING is broken on this platform\n");
7668 goto done;
7671 ok(width + kern_amount == width_kern, "%ld + %d != %ld\n", width, kern_amount, width_kern);
7673 kern_amount = idx = 0;
7674 for (i = 0; i < count; i += 3, idx++)
7676 ok(pos[i] + kern_amount == pos_kern[i], "%ld: %d + %d != %d\n", i, pos[i], kern_amount, pos_kern[i]);
7677 kern_amount += kern[idx];
7678 ok(pos[i+1] + kern_amount == pos_kern[i+1], "%ld: %d + %d != %d\n", i, pos[i+1], kern_amount, pos_kern[i+1]);
7679 ok(pos[i+2] + kern_amount == pos_kern[i+2], "%ld: %d + %d != %d\n", i, pos[i+2], kern_amount, pos_kern[i+2]);
7681 ok(dx[i] + kern[idx] == dx_kern[i], "%ld: %d + %d != %d\n", i, dx[i], kern[idx], dx_kern[i]);
7682 ok(dx[i+1] == dx_kern[i+1], "%ld: %d != %d\n", i, dx[i+1], dx_kern[i+1]);
7683 ok(dx[i+2] == dx_kern[i+2], "%ld: %d != %d\n", i, dx[i+2], dx_kern[i+2]);
7686 done:
7687 SelectObject(hdc, hfont_old);
7688 DeleteObject(hfont);
7689 ReleaseDC(0, hdc);
7692 static void test_select_object(void)
7694 HFONT hfont, old_font;
7695 LOGFONTA lf;
7697 memset(&lf, 0, sizeof lf);
7699 lf.lfCharSet = ANSI_CHARSET;
7700 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
7701 lf.lfWeight = FW_DONTCARE;
7702 lf.lfHeight = 16;
7703 lf.lfWidth = 16;
7704 lf.lfQuality = DEFAULT_QUALITY;
7706 lstrcpyA(lf.lfFaceName, "Arial");
7707 hfont = create_font("Arial", &lf);
7709 SetLastError(0xdeadbeef);
7710 old_font = SelectObject(NULL, hfont);
7711 ok(!old_font, "SelectObject returned %p\n", old_font);
7712 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError() = %lu\n",
7713 GetLastError());
7715 DeleteObject(hfont);
7718 static void test_GetOutlineTextMetrics_subst(void)
7720 OUTLINETEXTMETRICA *otm;
7721 LOGFONTA lf;
7722 HFONT hfont, hfont_old;
7723 HDC hdc;
7724 DWORD ret;
7725 char face_name[LF_FACESIZE];
7726 const char* family_name;
7728 if (!is_font_installed("MS SHELL DLG"))
7730 skip("MS Shell Dlg is not installed\n");
7731 return;
7734 hdc = GetDC(0);
7735 memset(&lf, 0, sizeof(lf));
7736 strcpy(lf.lfFaceName, "MS SHELL DLG");
7737 lf.lfCharSet = DEFAULT_CHARSET;
7738 hfont = CreateFontIndirectA(&lf);
7739 ok(hfont != NULL, "failed to create a font\n");
7740 hfont_old = SelectObject(hdc, hfont);
7742 /* face name */
7743 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
7744 ok(ret, "GetTextFace failed\n");
7745 ok(!lstrcmpiA(lf.lfFaceName, face_name), "expected %s, got %s\n", lf.lfFaceName, face_name);
7747 ret = GetOutlineTextMetricsA(hdc, 0, NULL);
7748 otm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret);
7749 ret = GetOutlineTextMetricsA(hdc, ret, otm);
7750 ok(ret != 0, "GetOutlineTextMetrics failed\n");
7752 /* family name */
7753 family_name = (const char*)otm + (UINT_PTR)otm->otmpFamilyName;
7754 ok(lstrcmpiA(lf.lfFaceName, family_name), "expected a real family name (e.g. Tahoma), got %s\n", family_name);
7756 HeapFree(GetProcessHeap(), 0, otm);
7757 SelectObject(hdc, hfont_old);
7758 DeleteObject(hfont);
7760 ReleaseDC(0, hdc);
7763 START_TEST(font)
7765 static const char *test_names[] =
7767 "AddFontMemResource",
7769 char path_name[MAX_PATH];
7770 STARTUPINFOA startup;
7771 char **argv;
7772 int argc, i;
7774 init();
7776 argc = winetest_get_mainargs(&argv);
7777 if (argc >= 3)
7779 if (!strcmp(argv[2], "AddFontMemResource"))
7780 test_AddFontMemResource();
7781 return;
7784 test_stock_fonts();
7785 test_logfont();
7786 test_bitmap_font();
7787 test_outline_font();
7788 test_bitmap_font_metrics();
7789 test_GdiGetCharDimensions();
7790 test_GetCharABCWidths();
7791 test_text_extents();
7792 test_GetGlyphIndices();
7793 test_GetKerningPairs();
7794 test_GetOutlineTextMetrics();
7795 test_GetOutlineTextMetrics_subst();
7796 test_SetTextJustification();
7797 test_TranslateCharsetInfo();
7798 test_font_charset();
7799 test_GdiGetCodePage();
7800 test_GetFontUnicodeRanges();
7801 test_nonexistent_font();
7802 test_orientation();
7803 test_height_selection();
7804 test_EnumFonts();
7805 test_EnumFonts_subst();
7807 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
7808 * I'd like to avoid them in this test.
7810 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
7811 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
7812 if (is_truetype_font_installed("Arial Black") &&
7813 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
7815 test_EnumFontFamilies("", ANSI_CHARSET);
7816 test_EnumFontFamilies("", SYMBOL_CHARSET);
7817 test_EnumFontFamilies("", DEFAULT_CHARSET);
7819 else
7820 skip("Arial Black or Symbol/Wingdings is not installed\n");
7821 test_EnumFontFamiliesEx_default_charset();
7822 test_GetTextMetrics();
7823 test_RealizationInfo();
7824 test_GetTextFace();
7825 test_GetGlyphOutline();
7826 test_GetTextMetrics2("Tahoma", -11);
7827 test_GetTextMetrics2("Tahoma", -55);
7828 test_GetTextMetrics2("Tahoma", -110);
7829 test_GetTextMetrics2("Arial", -11);
7830 test_GetTextMetrics2("Arial", -55);
7831 test_GetTextMetrics2("Arial", -110);
7832 test_GetCharacterPlacement();
7833 test_GetCharacterPlacement_kerning();
7834 test_GetCharWidthInfo();
7835 test_CreateFontIndirect();
7836 test_CreateFontIndirectEx();
7837 test_oemcharset();
7838 test_fullname();
7839 test_fullname2();
7840 test_east_asian_font_selection();
7841 test_max_height();
7842 test_vertical_order();
7843 test_GetCharWidth32();
7844 test_fake_bold_font();
7845 test_bitmap_font_glyph_index();
7846 test_GetCharWidthI();
7847 test_long_names();
7848 test_ttf_names();
7849 test_lang_names();
7850 test_char_width();
7851 test_select_object();
7853 /* These tests should be last test until RemoveFontResource
7854 * is properly implemented.
7856 test_vertical_font();
7857 test_CreateScalableFontResource();
7859 winetest_get_mainargs( &argv );
7860 for (i = 0; i < ARRAY_SIZE(test_names); ++i)
7862 PROCESS_INFORMATION info;
7864 memset(&startup, 0, sizeof(startup));
7865 startup.cb = sizeof(startup);
7866 sprintf(path_name, "%s font %s", argv[0], test_names[i]);
7867 ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info),
7868 "CreateProcess failed.\n");
7869 wait_child_process(info.hProcess);
7870 CloseHandle(info.hProcess);
7871 CloseHandle(info.hThread);