ReactOS 0.4.16-dev-122-g325d74c
font.c
Go to the documentation of this file.
1/*
2 * Unit test suite for fonts
3 *
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
6 *
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.
11 *
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.
16 *
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
20 */
21
22#include <stdarg.h>
23#include <assert.h>
24
25#include "windef.h"
26#include "winbase.h"
27#include "wingdi.h"
28#include "winuser.h"
29#include "winnls.h"
30
31#include "wine/heap.h"
32#include "wine/test.h"
33
34static inline BOOL match_off_by_n(int a, int b, unsigned int n)
35{
36 return abs(a - b) <= n;
37}
38#define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
39#define near_match(a, b) match_off_by_n((a), (b), 6)
40#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
41
42static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
43static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
44static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
45static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
46static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
47static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
48static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
49static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
50static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
51static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
52static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
53static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
55static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
56static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
57static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
58static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
59static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
60static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
61static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
62static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *);
63static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
64
65static HMODULE hgdi32 = 0;
66static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
68
69#ifdef WORDS_BIGENDIAN
70#define GET_BE_WORD(x) (x)
71#define GET_BE_DWORD(x) (x)
72#else
73#define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
74#define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
75#endif
76
77#define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
78 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
79 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
80#define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
81#define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
82#define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
83
84static void init(void)
85{
86 hgdi32 = GetModuleHandleA("gdi32.dll");
87
88 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
89 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
90 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
91 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
92 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
93 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
94 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
95 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
96 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
97 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
98 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
99 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
100 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
101 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
102 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
103 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
104 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
105 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
106 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
107 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
108 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
109
111}
112
114{
115 if (type != TRUETYPE_FONTTYPE) return 1;
116
117 return 0;
118}
119
121{
122 HDC hdc = GetDC(0);
123 BOOL ret = FALSE;
124
126 ret = TRUE;
127
128 ReleaseDC(0, hdc);
129 return ret;
130}
131
133{
134 return 0;
135}
136
137static BOOL is_font_installed(const char *name)
138{
139 HDC hdc = GetDC(0);
140 BOOL ret = FALSE;
141
143 ret = TRUE;
144
145 ReleaseDC(0, hdc);
146 return ret;
147}
148
149static void *get_res_data(const char *fontname, DWORD *rsrc_size)
150{
151 HRSRC rsrc;
152 void *rsrc_data;
153
155 if (!rsrc) return NULL;
156
157 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
158 if (!rsrc_data) return NULL;
159
160 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
161 if (!*rsrc_size) return NULL;
162
163 return rsrc_data;
164}
165
166static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
167{
168 char tmp_path[MAX_PATH];
169 HANDLE hfile;
170 BOOL ret;
171
172 GetTempPathA(MAX_PATH, tmp_path);
173 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
174
176 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
177
178 ret = WriteFile(hfile, data, *size, size, NULL);
179
180 CloseHandle(hfile);
181 return ret;
182}
183
184static BOOL write_ttf_file(const char *fontname, char *tmp_name)
185{
186 void *rsrc_data;
187 DWORD rsrc_size;
188
189 rsrc_data = get_res_data( fontname, &rsrc_size );
190 if (!rsrc_data) return FALSE;
191
192 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
193}
194
195static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
196{
197 LOGFONTA getobj_lf;
198 int ret, minlen = 0;
199
200 if (!hfont)
201 return;
202
203 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
204 /* NT4 tries to be clever and only returns the minimum length */
205 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
206 minlen++;
207 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
208 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
209 ok(lf->lfHeight == getobj_lf.lfHeight ||
210 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
211 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
212 ok(lf->lfWidth == getobj_lf.lfWidth ||
213 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
214 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
215 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
216 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
217 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
218 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
219 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
220 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
221 ok(lf->lfWeight == getobj_lf.lfWeight ||
222 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
223 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
224 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
225 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
226 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
227 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
228 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
229 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
230 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
231 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
232 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
233 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
234 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
235}
236
237static HFONT create_font(const char* test, const LOGFONTA* lf)
238{
240 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
241 if (hfont)
242 check_font(test, lf, hfont);
243 return hfont;
244}
245
246static void test_logfont(void)
247{
248 LOGFONTA lf;
249 HFONT hfont;
250
251 memset(&lf, 0, sizeof lf);
252
256 lf.lfHeight = 16;
257 lf.lfWidth = 16;
259
260 lstrcpyA(lf.lfFaceName, "Arial");
261 hfont = create_font("Arial", &lf);
263
264 memset(&lf, 'A', sizeof(lf));
266 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
267
268 lf.lfFaceName[LF_FACESIZE - 1] = 0;
269 check_font("AAA...", &lf, hfont);
271}
272
274{
275 if (type & RASTER_FONTTYPE)
276 {
277 LOGFONTA *lf = (LOGFONTA *)lParam;
278 *lf = *elf;
279 return 0; /* stop enumeration */
280 }
281
282 return 1; /* continue enumeration */
283}
284
285static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
286{
287 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
288 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
289 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
290 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
291 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
292 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
293 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
294 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
295 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
296 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
297 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
298 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
299 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
300 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
301 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
302 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
303 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
304 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
305 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
306 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
307}
308
309static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
310 LONG lfWidth, const char *test_str,
311 INT test_str_len, const TEXTMETRICA *tm_orig,
312 const SIZE *size_orig, INT width_of_A_orig,
313 INT scale_x, INT scale_y)
314{
315 LOGFONTA lf;
318 SIZE size;
319 INT width_of_A, cx, cy;
320 UINT ret;
321
322 if (!hfont)
323 return;
324
325 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
326
327 GetObjectA(hfont, sizeof(lf), &lf);
328
330 {
331 otm.otmSize = sizeof(otm) / 2;
333 ok(ret == sizeof(otm)/2 /* XP */ ||
334 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
335
336 memset(&otm, 0x1, sizeof(otm));
337 otm.otmSize = sizeof(otm);
339 ok(ret == sizeof(otm) /* XP */ ||
340 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
341
342 memset(&tm, 0x2, sizeof(tm));
344 ok(ret, "GetTextMetricsA failed\n");
345 /* the structure size is aligned */
346 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
347 {
348 ok(0, "tm != otm\n");
350 }
351
352 tm = otm.otmTextMetrics;
353if (0) /* these metrics are scaled too, but with rounding errors */
354{
355 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
356 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
357}
358 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
359 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
360 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
361 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
362 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
363 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
364 }
365 else
366 {
368 ok(ret, "GetTextMetricsA failed\n");
369 }
370
371 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
372 cy = tm.tmHeight / tm_orig->tmHeight;
373 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
374 lfHeight, scale_x, scale_y, cx, cy);
375 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
376 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
377 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
378 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
379 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
380
381 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
382 if (lf.lfHeight)
383 {
384 if (lf.lfWidth)
385 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
386 }
387 else
388 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
389
390 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
391
392 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
393 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
394
395 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
396
397 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);
398}
399
400/* Test how GDI scales bitmap font metrics */
401static void test_bitmap_font(void)
402{
403 static const char test_str[11] = "Test String";
404 HDC hdc;
405 LOGFONTA bitmap_lf;
406 HFONT hfont, old_hfont;
407 TEXTMETRICA tm_orig;
408 SIZE size_orig;
409 INT ret, i, width_orig, height_orig, scale, lfWidth;
410
412
413 /* "System" has only 1 pixel size defined, otherwise the test breaks */
414 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
415 if (ret)
416 {
417 ReleaseDC(0, hdc);
418 trace("no bitmap fonts were found, skipping the test\n");
419 return;
420 }
421
422 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
423
424 height_orig = bitmap_lf.lfHeight;
425 lfWidth = bitmap_lf.lfWidth;
426
427 hfont = create_font("bitmap", &bitmap_lf);
428 old_hfont = SelectObject(hdc, hfont);
429 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
430 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
431 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
432 SelectObject(hdc, old_hfont);
434
435 bitmap_lf.lfHeight = 0;
436 bitmap_lf.lfWidth = 4;
437 hfont = create_font("bitmap", &bitmap_lf);
438 old_hfont = SelectObject(hdc, hfont);
439 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
440 SelectObject(hdc, old_hfont);
442
443 bitmap_lf.lfHeight = height_orig;
444 bitmap_lf.lfWidth = lfWidth;
445
446 /* test fractional scaling */
447 for (i = 1; i <= height_orig * 6; i++)
448 {
449 INT nearest_height;
450
451 bitmap_lf.lfHeight = i;
452 hfont = create_font("fractional", &bitmap_lf);
453 scale = (i + height_orig - 1) / height_orig;
454 nearest_height = scale * height_orig;
455 /* Only jump to the next height if the difference <= 25% original height */
456 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
457 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
458 so we'll not test this particular height. */
459 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
460 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
461 old_hfont = SelectObject(hdc, hfont);
462 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
463 SelectObject(hdc, old_hfont);
465 }
466
467 /* test integer scaling 3x2 */
468 bitmap_lf.lfHeight = height_orig * 2;
469 bitmap_lf.lfWidth *= 3;
470 hfont = create_font("3x2", &bitmap_lf);
471 old_hfont = SelectObject(hdc, hfont);
472 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
473 SelectObject(hdc, old_hfont);
475
476 /* test integer scaling 3x3 */
477 bitmap_lf.lfHeight = height_orig * 3;
478 bitmap_lf.lfWidth = 0;
479 hfont = create_font("3x3", &bitmap_lf);
480 old_hfont = SelectObject(hdc, hfont);
481 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
482 SelectObject(hdc, old_hfont);
484
485 DeleteDC(hdc);
486}
487
488/* Test how GDI scales outline font metrics */
489static void test_outline_font(void)
490{
491 static const char test_str[11] = "Test String";
492 HDC hdc, hdc_2;
493 LOGFONTA lf;
494 HFONT hfont, old_hfont, old_hfont_2;
496 SIZE size_orig;
497 INT width_orig, height_orig, lfWidth;
498 XFORM xform;
499 GLYPHMETRICS gm;
500 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
501 POINT pt;
502 INT ret;
503
504 if (!is_truetype_font_installed("Arial"))
505 {
506 skip("Arial is not installed\n");
507 return;
508 }
509
511
512 memset(&lf, 0, sizeof(lf));
513 strcpy(lf.lfFaceName, "Arial");
514 lf.lfHeight = 72;
515 hfont = create_font("outline", &lf);
516 old_hfont = SelectObject(hdc, hfont);
517 otm.otmSize = sizeof(otm);
518 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
519 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
520 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
521
522 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
523 SelectObject(hdc, old_hfont);
525
526 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
527 lf.lfHeight = otm.otmEMSquare;
528 lf.lfHeight = -lf.lfHeight;
529 hfont = create_font("outline", &lf);
530 old_hfont = SelectObject(hdc, hfont);
531 otm.otmSize = sizeof(otm);
532 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
533 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
534 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
535 SelectObject(hdc, old_hfont);
537
538 height_orig = otm.otmTextMetrics.tmHeight;
539 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
540
541 /* test integer scaling 3x2 */
542 lf.lfHeight = height_orig * 2;
543 lf.lfWidth = lfWidth * 3;
544 hfont = create_font("3x2", &lf);
545 old_hfont = SelectObject(hdc, hfont);
546 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
547 SelectObject(hdc, old_hfont);
549
550 /* test integer scaling 3x3 */
551 lf.lfHeight = height_orig * 3;
552 lf.lfWidth = lfWidth * 3;
553 hfont = create_font("3x3", &lf);
554 old_hfont = SelectObject(hdc, hfont);
555 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
556 SelectObject(hdc, old_hfont);
558
559 /* test integer scaling 1x1 */
560 lf.lfHeight = height_orig * 1;
561 lf.lfWidth = lfWidth * 1;
562 hfont = create_font("1x1", &lf);
563 old_hfont = SelectObject(hdc, hfont);
564 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
565 SelectObject(hdc, old_hfont);
567
568 /* test integer scaling 1x1 */
569 lf.lfHeight = height_orig;
570 lf.lfWidth = 0;
571 hfont = create_font("1x1", &lf);
572 old_hfont = SelectObject(hdc, hfont);
573 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
574
575 /* with an identity matrix */
576 memset(&gm, 0, sizeof(gm));
577 SetLastError(0xdeadbeef);
578 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
582 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
583 /* with a custom matrix */
584 memset(&gm, 0, sizeof(gm));
585 SetLastError(0xdeadbeef);
586 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
587 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
588 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
589 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
591
592 /* Test that changing the DC transformation affects only the font
593 * selected on this DC and doesn't affect the same font selected on
594 * another DC.
595 */
596 hdc_2 = CreateCompatibleDC(0);
597 old_hfont_2 = SelectObject(hdc_2, hfont);
598 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
599
601
602 /* font metrics on another DC should be unchanged */
603 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
604
605 /* test restrictions of compatibility mode GM_COMPATIBLE */
606 /* part 1: rescaling only X should not change font scaling on screen.
607 So compressing the X axis by 2 is not done, and this
608 appears as X scaling of 2 that no one requested. */
609 SetWindowExtEx(hdc, 100, 100, NULL);
610 SetViewportExtEx(hdc, 50, 100, NULL);
611 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
614
615 /* part 2: rescaling only Y should change font scaling.
616 As also X is scaled by a factor of 2, but this is not
617 requested by the DC transformation, we get a scaling factor
618 of 2 in the X coordinate. */
619 SetViewportExtEx(hdc, 100, 200, NULL);
620 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
621 /* font metrics on another DC should be unchanged */
622 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
623
624 /* restore scaling */
626
627 /* font metrics on another DC should be unchanged */
628 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
629
630 SelectObject(hdc_2, old_hfont_2);
631 DeleteDC(hdc_2);
632
634 {
635 SelectObject(hdc, old_hfont);
637 DeleteDC(hdc);
638 skip("GM_ADVANCED is not supported on this platform\n");
639 return;
640 }
641
642 xform.eM11 = 20.0f;
643 xform.eM12 = 0.0f;
644 xform.eM21 = 0.0f;
645 xform.eM22 = 20.0f;
646 xform.eDx = 0.0f;
647 xform.eDy = 0.0f;
648
649 SetLastError(0xdeadbeef);
650 ret = SetWorldTransform(hdc, &xform);
651 ok(ret, "SetWorldTransform error %u\n", GetLastError());
652
653 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
654
655 /* with an identity matrix */
656 memset(&gm, 0, sizeof(gm));
657 SetLastError(0xdeadbeef);
658 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
659 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
660 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
661 pt.x = width_orig; pt.y = 0;
662 LPtoDP(hdc, &pt, 1);
663 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
664 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
665 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
666 /* with a custom matrix */
667 memset(&gm, 0, sizeof(gm));
668 SetLastError(0xdeadbeef);
669 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
670 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
671 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
672 pt.x = width_orig; pt.y = 0;
673 LPtoDP(hdc, &pt, 1);
674 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
675 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
676 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
677
678 SetLastError(0xdeadbeef);
680 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
681
682 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
683
684 /* with an identity matrix */
685 memset(&gm, 0, sizeof(gm));
686 SetLastError(0xdeadbeef);
687 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
688 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
689 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
690 pt.x = width_orig; pt.y = 0;
691 LPtoDP(hdc, &pt, 1);
692 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
693 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
694 /* with a custom matrix */
695 memset(&gm, 0, sizeof(gm));
696 SetLastError(0xdeadbeef);
697 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
698 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
699 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
700 pt.x = width_orig; pt.y = 0;
701 LPtoDP(hdc, &pt, 1);
702 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
703 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
704
705 SetLastError(0xdeadbeef);
707 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
708
709 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
710
711 /* with an identity matrix */
712 memset(&gm, 0, sizeof(gm));
713 SetLastError(0xdeadbeef);
714 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
715 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
716 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
717 pt.x = width_orig; pt.y = 0;
718 LPtoDP(hdc, &pt, 1);
719 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
720 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
721 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
722 /* with a custom matrix */
723 memset(&gm, 0, sizeof(gm));
724 SetLastError(0xdeadbeef);
725 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
726 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
727 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
728 pt.x = width_orig; pt.y = 0;
729 LPtoDP(hdc, &pt, 1);
730 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
731 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
732 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
733
734 SelectObject(hdc, old_hfont);
736 DeleteDC(hdc);
737}
738
740{
741 LOGFONTA *lf = (LOGFONTA *)lParam;
742
743 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
744 {
745 *lf = *elf;
746 return 0; /* stop enumeration */
747 }
748 return 1; /* continue enumeration */
749}
750
751static BOOL is_CJK(void)
752{
754}
755
756#define FH_SCALE 0x80000000
758{
759 static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
760 static const struct font_data
761 {
762 const char face_name[LF_FACESIZE];
764 int ave_char_width, max_char_width, dpi;
765 BYTE first_char, last_char, def_char, break_char;
766 DWORD ansi_bitfield;
767 const WORD *skip_lang_id;
768 int scaled_height;
769 } fd[] =
770 {
771 { "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 },
772 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
773 { "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 },
774 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
775 { "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 },
776 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
777 { "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 },
778 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
779 { "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 },
780 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
781
782 { "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 },
783 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
784 { "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 },
785 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
786 { "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 },
787 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
788 { "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 },
789 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
790 { "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 },
791 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
792
793 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
794 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
795 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
796 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
797 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
798 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
799 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
800 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
801 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
802 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
803 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
804 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
805 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
806 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
807 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
808 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
809
810 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
812 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
813 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
814 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
815 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
816 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
817 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
818 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
819 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
820 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
821 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
822
823 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
824 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
826 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
827 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
828 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
830 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
831 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
832 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
833 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
834 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
835 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
836 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
837 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
838 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
839 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
840
841 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
842 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
843 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
844 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
845 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
846 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
847 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
848 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
849 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
850 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
851 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
852
853 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
854 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
855 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
856
857 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
858 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
859 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
860
861 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
862 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
863 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
864
865 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
866 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
867
868 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
869 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
870 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
871 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
872 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
873 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
874 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
875 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
876 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
877 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
878 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
879 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
880 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
881 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
882 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
883 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
884 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
885 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
886 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
887 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
888 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
889
890 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
891 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
892 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
893 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
894 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
895 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
896 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
897 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
898 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
899 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
900 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
901 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
902
903 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
904 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
905 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
906
907 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
908
909 /* FIXME: add "Terminal" */
910 };
911 static const int font_log_pixels[] = { 96, 120 };
912 HDC hdc;
913 LOGFONTA lf;
914 HFONT hfont, old_hfont;
916 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
917 char face_name[LF_FACESIZE];
918 CHARSETINFO csi;
919
920 trace("system language id %04x\n", system_lang_id);
921
922 expected_cs = GetACP();
923 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
924 {
925 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
926 return;
927 }
928 expected_cs = csi.ciCharset;
929 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
930
932 ok(hdc != NULL, "failed to create hdc\n");
933
934 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
936
937 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
938 diff = 32768;
939 font_res = 0;
940 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
941 {
942 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
943 if (new_diff < diff)
944 {
945 diff = new_diff;
946 font_res = font_log_pixels[i];
947 }
948 }
949 trace("best font resolution is %d\n", font_res);
950
951 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
952 {
953 int bit, height;
954
955 memset(&lf, 0, sizeof(lf));
956
957 height = fd[i].height & ~FH_SCALE;
958 lf.lfHeight = height;
959 strcpy(lf.lfFaceName, fd[i].face_name);
960
961 for(bit = 0; bit < 32; bit++)
962 {
963 GLYPHMETRICS gm;
964 DWORD fs[2];
965 BOOL bRet;
966
967 fs[0] = 1L << bit;
968 fs[1] = 0;
969 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
970 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
971
972 lf.lfCharSet = csi.ciCharset;
974 if (fd[i].height & FH_SCALE)
975 ok(ret, "scaled font height %d should not be enumerated\n", height);
976 else
977 {
978 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
979 {
980 todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */
981 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
982 }
983 }
984 if (ret && !(fd[i].height & FH_SCALE))
985 continue;
986
987 hfont = create_font(lf.lfFaceName, &lf);
988 old_hfont = SelectObject(hdc, hfont);
989
990 SetLastError(0xdeadbeef);
991 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
992 ok(ret, "GetTextFace error %u\n", GetLastError());
993
994 if (strcmp(face_name, fd[i].face_name) != 0)
995 {
996 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
997 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
998 SelectObject(hdc, old_hfont);
1000 continue;
1001 }
1002
1003 memset(&gm, 0, sizeof(gm));
1004 SetLastError(0xdeadbeef);
1005 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1006 todo_wine {
1007 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1008 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1009 }
1010
1011 bRet = GetTextMetricsA(hdc, &tm);
1012 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1013
1014 SetLastError(0xdeadbeef);
1016 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1017 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1018 else
1019 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1020
1021 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1022 trace("expected %s, height %d scaled_height %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1023
1024 if(fd[i].dpi == tm.tmDigitizedAspectX)
1025 {
1026 int skipme = 0;
1027 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1028 if (fd[i].skip_lang_id)
1029 {
1030 int si = 0;
1031 skipme = 0;
1032 while(!skipme && fd[i].skip_lang_id[si])
1033 if (fd[i].skip_lang_id[si++] == system_lang_id)
1034 skipme = 1;
1035 }
1036 if (!skipme)
1037 {
1038 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1039 if (fd[i].height & FH_SCALE)
1040 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
1041 else
1042 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
1043 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1044 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1045 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
1046 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
1047 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
1048 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1049 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1050 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1051 make default char test fail */
1052 if (tm.tmCharSet == lf.lfCharSet)
1053 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1054 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1055 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
1056
1057 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1058 that make the max width bigger */
1059 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1060 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
1061 }
1062 else
1063 skip("Skipping font metrics test for system langid 0x%x\n",
1065 }
1066 SelectObject(hdc, old_hfont);
1068 }
1069 }
1070
1071 DeleteDC(hdc);
1072}
1073
1075{
1076 HDC hdc;
1078 LONG ret;
1079 SIZE size;
1080 LONG avgwidth, height;
1081 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1082
1083 if (!pGdiGetCharDimensions)
1084 {
1085 win_skip("GdiGetCharDimensions not available on this platform\n");
1086 return;
1087 }
1088
1090
1091 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1092 avgwidth = ((size.cx / 26) + 1) / 2;
1093
1094 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1095 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1096 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1097
1098 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1099 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1100
1101 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1102 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1103
1104 height = 0;
1105 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1106 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1107 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1108
1109 DeleteDC(hdc);
1110}
1111
1112static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1113 const TEXTMETRICA *lpntme,
1114 DWORD FontType, LPARAM lParam)
1115{
1116 if (FontType & TRUETYPE_FONTTYPE)
1117 {
1118 HFONT hfont;
1119
1120 hfont = CreateFontIndirectA(lpelfe);
1121 if (hfont)
1122 {
1123 *(HFONT *)lParam = hfont;
1124 return 0;
1125 }
1126 }
1127
1128 return 1;
1129}
1130
1131static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, const ABC *base_abci, const ABC *base_abcw, const ABCFLOAT *base_abcf)
1132{
1133 ABC abc[1];
1134 ABCFLOAT abcf[1];
1135 BOOL ret = FALSE;
1136
1137 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1138 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1139 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1140 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1141 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1142
1143 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1144 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1145 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1146 ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1147 ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1148
1149 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1150 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1151 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1152 ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1153 ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1154}
1155
1156static void test_GetCharABCWidths(void)
1157{
1158 static const WCHAR str[] = {'i',0};
1159 BOOL ret;
1160 HDC hdc;
1161 LOGFONTA lf;
1162 HFONT hfont;
1163 ABC abc[1];
1164 ABC abcw[1];
1165 ABCFLOAT abcf[1];
1166 WORD glyphs[1];
1167 DWORD nb;
1168 HWND hwnd;
1169 static const struct
1170 {
1171 UINT first;
1172 UINT last;
1173 } range[] =
1174 {
1175 {0xff, 0xff},
1176 {0x100, 0x100},
1177 {0xff, 0x100},
1178 {0x1ff, 0xff00},
1179 {0xffff, 0xffff},
1180 {0x10000, 0x10000},
1181 {0xffff, 0x10000},
1182 {0xffffff, 0xffffff},
1183 {0x1000000, 0x1000000},
1184 {0xffffff, 0x1000000},
1185 {0xffffffff, 0xffffffff},
1186 {0x00, 0xff}
1187 };
1188 static const struct
1189 {
1190 UINT cs;
1191 UINT a;
1192 UINT w;
1193 BOOL r[sizeof range / sizeof range[0]];
1194 } c[] =
1195 {
1196 {ANSI_CHARSET, 0x30, 0x30,
1198 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1200 {HANGEUL_CHARSET, 0x8141, 0xac02,
1202 {GB2312_CHARSET, 0x8141, 0x4e04,
1204 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1206 };
1207 UINT i;
1208
1209 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1210 {
1211 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1212 return;
1213 }
1214
1215 memset(&lf, 0, sizeof(lf));
1216 strcpy(lf.lfFaceName, "System");
1217 lf.lfHeight = 20;
1218
1220 hdc = GetDC(0);
1222
1223 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1224 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1225
1226 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1227 ok(!ret, "GetCharABCWidthsI should have failed\n");
1228
1229 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1230 ok(!ret, "GetCharABCWidthsI should have failed\n");
1231
1232 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1233 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1234
1235 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1236 ok(!ret, "GetCharABCWidthsW should have failed\n");
1237
1238 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1239 ok(!ret, "GetCharABCWidthsW should have failed\n");
1240
1241 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1242 ok(!ret, "GetCharABCWidthsW should have failed\n");
1243
1244 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1245 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1246
1247 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1248 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1249
1250 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1251 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1252
1255
1256 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1257 {
1258 ABC a[2], w[2];
1259 ABC full[256];
1260 UINT code = 0x41, j;
1261
1262 lf.lfFaceName[0] = '\0';
1263 lf.lfCharSet = c[i].cs;
1264 lf.lfPitchAndFamily = 0;
1266 {
1267 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1268 continue;
1269 }
1270
1271 memset(a, 0, sizeof a);
1272 memset(w, 0, sizeof w);
1274 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1275 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1276 memcmp(a, w, sizeof a) == 0,
1277 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1278
1279 memset(a, 0xbb, sizeof a);
1280 ret = pGetCharABCWidthsA(hdc, code, code, a);
1281 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1282 memset(full, 0xcc, sizeof full);
1283 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1284 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1285 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1286 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1287
1288 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1289 {
1290 memset(full, 0xdd, sizeof full);
1291 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1292 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1293 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1294 if (ret)
1295 {
1296 UINT last = range[j].last - range[j].first;
1297 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1298 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1299 "GetCharABCWidthsA %x should match. codepage = %u\n",
1300 range[j].last, c[i].cs);
1301 }
1302 }
1303
1306 }
1307
1308 memset(&lf, 0, sizeof(lf));
1309 strcpy(lf.lfFaceName, "Tahoma");
1310 lf.lfHeight = 200;
1312
1313 /* test empty glyph's metrics */
1315 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1316 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1317 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1318 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1319 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1320 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1321
1322 /* 1) prepare unrotated font metrics */
1323 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1324 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1326
1327 /* 2) get rotated font metrics */
1328 lf.lfEscapement = lf.lfOrientation = 900;
1331 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1332 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1333
1334 /* 3) compare ABC results */
1335 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1336 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1337 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1338 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1339 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1340 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1341
1343
1344 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1345 in various widths. */
1346 for (i = 1; i <= 2; i++)
1347 {
1348 UINT j;
1349 UINT code;
1350
1351 memset(&lf, 0, sizeof(lf));
1352 lf.lfHeight = 20;
1353 switch(i)
1354 {
1355 case 1:
1356 strcpy(lf.lfFaceName, "Tahoma");
1357 code = 'a';
1358 break;
1359 case 2:
1360 strcpy(lf.lfFaceName, "Times New Roman");
1361 lf.lfItalic = TRUE;
1362 code = 'f';
1363 break;
1364 }
1366 {
1367 skip("%s is not installed\n", lf.lfFaceName);
1368 continue;
1369 }
1370 for (j = 1; j <= 80; j++)
1371 {
1372 GLYPHMETRICS gm;
1373
1374 lf.lfWidth = j;
1377
1378 nb = GetGlyphOutlineA(hdc, code, GGO_METRICS, &gm, 0, NULL, &mat);
1379 ok(nb, "GetGlyphOutlineA should have succeeded at width %d\n", i);
1380
1382 ok(ret, "GetCharABCWidthsA should have succeeded at width %d\n", i);
1383
1384 ok(abc[0].abcA == gm.gmptGlyphOrigin.x,
1385 "abcA(%d) and gmptGlyphOrigin.x(%d) values are different at width %d\n",
1386 abc[0].abcA, gm.gmptGlyphOrigin.x, i);
1387 ok(abc[0].abcB == gm.gmBlackBoxX,
1388 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1389 abc[0].abcB, gm.gmBlackBoxX, i);
1391 }
1392 }
1393 ReleaseDC(NULL, hdc);
1394
1395 trace("ABC sign test for a variety of transforms:\n");
1396 memset(&lf, 0, sizeof(lf));
1397 strcpy(lf.lfFaceName, "Tahoma");
1398 lf.lfHeight = 20;
1400 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1401 0, 0, 0, NULL);
1402 hdc = GetDC(hwnd);
1405
1406 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1407 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1408
1409 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1410 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1411 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1412 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1413 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1414 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1415
1416 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf);
1417 SetWindowExtEx(hdc, -1, -1, NULL);
1419 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf);
1421 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf);
1422 SetWindowExtEx(hdc, 1, 1, NULL);
1424 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf);
1426 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf);
1427
1428 ReleaseDC(hwnd, hdc);
1430
1431 trace("RTL layout\n");
1432 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1433 0, 0, 0, NULL);
1434 hdc = GetDC(hwnd);
1437
1438 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf);
1439 SetWindowExtEx(hdc, -1, -1, NULL);
1441 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf);
1443 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf);
1444 SetWindowExtEx(hdc, 1, 1, NULL);
1446 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf);
1448 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf);
1449
1450 ReleaseDC(hwnd, hdc);
1453}
1454
1455static void test_text_extents(void)
1456{
1457 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1458 static const WCHAR emptyW[] = {0};
1459 LPINT extents;
1460 INT i, len, fit1, fit2, extents2[3];
1461 LOGFONTA lf;
1463 HDC hdc;
1464 HFONT hfont;
1465 SIZE sz;
1466 SIZE sz1, sz2;
1467 BOOL ret;
1468
1469 memset(&lf, 0, sizeof(lf));
1470 strcpy(lf.lfFaceName, "Arial");
1471 lf.lfHeight = 20;
1472
1474 hdc = GetDC(0);
1477 ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1478 ok(ret, "got %d\n", ret);
1479 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1480
1481 memset(&sz, 0xcc, sizeof(sz));
1482 ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1483 ok(ret, "got %d\n", ret);
1484 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1485
1486 memset(&sz, 0xcc, sizeof(sz));
1487 ret = GetTextExtentPointA(hdc, "", 0, &sz);
1488 ok(ret, "got %d\n", ret);
1489 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1490
1491 SetLastError(0xdeadbeef);
1492 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1494 {
1495 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1498 ReleaseDC(0, hdc);
1499 return;
1500 }
1501
1502 memset(&sz, 0xcc, sizeof(sz));
1503 ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1504 ok(ret, "got %d\n", ret);
1505 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1506
1507 memset(&sz, 0xcc, sizeof(sz));
1508 ret = GetTextExtentPointW(hdc, emptyW, 0, &sz);
1509 ok(ret, "got %d\n", ret);
1510 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1511
1512 len = lstrlenW(wt);
1513 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1514 extents[0] = 1; /* So that the increasing sequence test will fail
1515 if the extents array is untouched. */
1516 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1517 GetTextExtentPointW(hdc, wt, len, &sz2);
1518 ok(sz1.cy == sz2.cy,
1519 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1520 /* Because of the '\n' in the string GetTextExtentExPoint and
1521 GetTextExtentPoint return different widths under Win2k, but
1522 under WinXP they return the same width. So we don't test that
1523 here. */
1524
1525 for (i = 1; i < len; ++i)
1526 ok(extents[i-1] <= extents[i],
1527 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1528 i);
1529 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1530 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1531 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1532 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1533 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1534 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1535 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1536 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1537 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1538 ok(extents[0] == extents[2] && extents[1] == extents[3],
1539 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1540 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1541 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1542 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1543
1544 /* extents functions fail with -ve counts (the interesting case being -1) */
1545 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1546 ok(ret == FALSE, "got %d\n", ret);
1547 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1548 ok(ret == FALSE, "got %d\n", ret);
1549 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1550 ok(ret == FALSE, "got %d\n", ret);
1551
1552 /* max_extent = 0 succeeds and returns zero */
1553 fit1 = fit2 = -215;
1554 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1555 ok(ret == TRUE ||
1556 broken(ret == FALSE), /* NT4, 2k */
1557 "got %d\n", ret);
1558 ok(fit1 == 0 ||
1559 broken(fit1 == -215), /* NT4, 2k */
1560 "fit = %d\n", fit1);
1561 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1562 ok(ret == TRUE, "got %d\n", ret);
1563 ok(fit2 == 0, "fit = %d\n", fit2);
1564
1565 /* max_extent = -1 is interpreted as a very large width that will
1566 * definitely fit our three characters */
1567 fit1 = fit2 = -215;
1568 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1569 ok(ret == TRUE, "got %d\n", ret);
1570 ok(fit1 == 3, "fit = %d\n", fit1);
1571 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1572 ok(ret == TRUE, "got %d\n", ret);
1573 ok(fit2 == 3, "fit = %d\n", fit2);
1574
1575 /* max_extent = -2 is interpreted similarly, but the Ansi version
1576 * rejects it while the Unicode one accepts it */
1577 fit1 = fit2 = -215;
1578 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1579 ok(ret == FALSE, "got %d\n", ret);
1580 ok(fit1 == -215, "fit = %d\n", fit1);
1581 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1582 ok(ret == TRUE, "got %d\n", ret);
1583 ok(fit2 == 3, "fit = %d\n", fit2);
1584
1587
1588 /* non-MM_TEXT mapping mode */
1589 lf.lfHeight = 2000;
1592
1594 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1595 ok(ret, "got %d\n", ret);
1596 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1597
1598 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1599 ok(ret, "got %d\n", ret);
1600 ok(fit1 == 2, "got %d\n", fit1);
1601 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1602 for(i = 0; i < 2; i++)
1603 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1604
1607 HeapFree(GetProcessHeap(), 0, extents);
1608 ReleaseDC(NULL, hdc);
1609}
1610
1611static void test_GetGlyphIndices(void)
1612{
1613 HDC hdc;
1614 HFONT hfont;
1615 DWORD charcount;
1616 LOGFONTA lf;
1617 DWORD flags = 0;
1618 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1619 WORD glyphs[(sizeof(testtext)/2)-1];
1620 TEXTMETRICA textm;
1621 HFONT hOldFont;
1622
1623 if (!pGetGlyphIndicesW) {
1624 win_skip("GetGlyphIndicesW not available on platform\n");
1625 return;
1626 }
1627
1628 hdc = GetDC(0);
1629
1630 memset(&lf, 0, sizeof(lf));
1631 strcpy(lf.lfFaceName, "System");
1632 lf.lfHeight = 16;
1634
1636 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1637 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1638 if (textm.tmCharSet == ANSI_CHARSET)
1639 {
1641 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1642 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1643 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1644 flags = 0;
1645 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1646 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1647 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1648 textm.tmDefaultChar, glyphs[4]);
1649 }
1650 else
1651 /* FIXME: Write tests for non-ANSI charsets. */
1652 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1653
1654 if(!is_font_installed("Tahoma"))
1655 {
1656 skip("Tahoma is not installed so skipping this test\n");
1657 return;
1658 }
1659 memset(&lf, 0, sizeof(lf));
1660 strcpy(lf.lfFaceName, "Tahoma");
1661 lf.lfHeight = 20;
1662
1664 hOldFont = SelectObject(hdc, hfont);
1665 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1667 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1668 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1669 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1670 flags = 0;
1671 testtext[0] = textm.tmDefaultChar;
1672 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1673 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1674 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1675 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1676 DeleteObject(SelectObject(hdc, hOldFont));
1677}
1678
1679static void test_GetKerningPairs(void)
1680{
1681 static const struct kerning_data
1682 {
1683 const char face_name[LF_FACESIZE];
1684 LONG height;
1685 /* some interesting fields from OUTLINETEXTMETRIC */
1686 LONG tmHeight, tmAscent, tmDescent;
1687 UINT otmEMSquare;
1688 INT otmAscent;
1689 INT otmDescent;
1690 UINT otmLineGap;
1691 UINT otmsCapEmHeight;
1692 UINT otmsXHeight;
1693 INT otmMacAscent;
1694 INT otmMacDescent;
1695 UINT otmMacLineGap;
1696 UINT otmusMinimumPPEM;
1697 /* small subset of kerning pairs to test */
1698 DWORD total_kern_pairs;
1699 const KERNINGPAIR kern_pair[26];
1700 } kd[] =
1701 {
1702 {"Arial", 12, 12, 9, 3,
1703 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1704 26,
1705 {
1706 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1707 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1708 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1709 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1710 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1711 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1712 {933,970,+1},{933,972,-1}
1713 }
1714 },
1715 {"Arial", -34, 39, 32, 7,
1716 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1717 26,
1718 {
1719 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1720 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1721 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1722 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1723 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1724 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1725 {933,970,+2},{933,972,-3}
1726 }
1727 },
1728 { "Arial", 120, 120, 97, 23,
1729 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1730 26,
1731 {
1732 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1733 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1734 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1735 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1736 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1737 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1738 {933,970,+6},{933,972,-10}
1739 }
1740 },
1741#if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1742 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1743 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1744 26,
1745 {
1746 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1747 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1748 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1749 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1750 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1751 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1752 {933,970,+54},{933,972,-83}
1753 }
1754 }
1755#endif
1756 };
1757 LOGFONTA lf;
1758 HFONT hfont, hfont_old;
1759 KERNINGPAIR *kern_pair;
1760 HDC hdc;
1761 DWORD total_kern_pairs, ret, i, n, matches;
1762
1763 hdc = GetDC(0);
1764
1765 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1766 * which may render this test unusable, so we're trying to avoid that.
1767 */
1768 SetLastError(0xdeadbeef);
1771 {
1772 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1773 ReleaseDC(0, hdc);
1774 return;
1775 }
1776
1777 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1778 {
1780 UINT uiRet;
1781
1782 if (!is_font_installed(kd[i].face_name))
1783 {
1784 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1785 continue;
1786 }
1787
1788 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1789
1790 memset(&lf, 0, sizeof(lf));
1791 strcpy(lf.lfFaceName, kd[i].face_name);
1792 lf.lfHeight = kd[i].height;
1794 ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name);
1795
1796 hfont_old = SelectObject(hdc, hfont);
1797
1798 SetLastError(0xdeadbeef);
1799 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1800 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1801 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1802
1803 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1804 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1805 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1806 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1807 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1808 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1809
1810 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1811 kd[i].otmEMSquare, otm.otmEMSquare);
1812 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1813 kd[i].otmAscent, otm.otmAscent);
1814 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1815 kd[i].otmDescent, otm.otmDescent);
1816 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1817 kd[i].otmLineGap, otm.otmLineGap);
1818 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1819 kd[i].otmMacDescent, otm.otmMacDescent);
1820 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1821 kd[i].otmMacAscent, otm.otmMacAscent);
1823 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1824 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1826 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1827 kd[i].otmsXHeight, otm.otmsXHeight);
1828 ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1829 kd[i].otmMacLineGap, otm.otmMacLineGap);
1831 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1832 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1833
1834 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1835 trace("total_kern_pairs %u\n", total_kern_pairs);
1836 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1837
1838 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1839 * passes on XP.
1840 */
1841 SetLastError(0xdeadbeef);
1842 ret = GetKerningPairsW(hdc, 0, kern_pair);
1844 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1845 ok(ret == 0, "got %u, expected 0\n", ret);
1846
1847 ret = GetKerningPairsW(hdc, 100, NULL);
1848 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1849
1850 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1851 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1852
1853 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1854 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1855
1856 matches = 0;
1857
1858 for (n = 0; n < ret; n++)
1859 {
1860 DWORD j;
1861 /* Disabled to limit console spam */
1862 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1863 trace("{'%c','%c',%d},\n",
1864 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1865 for (j = 0; j < kd[i].total_kern_pairs; j++)
1866 {
1867 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1868 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1869 {
1870 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1871 "pair %d:%d got %d, expected %d\n",
1872 kern_pair[n].wFirst, kern_pair[n].wSecond,
1873 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1874 matches++;
1875 }
1876 }
1877 }
1878
1879 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1880 matches, kd[i].total_kern_pairs);
1881
1882 HeapFree(GetProcessHeap(), 0, kern_pair);
1883
1884 SelectObject(hdc, hfont_old);
1886 }
1887
1888 ReleaseDC(0, hdc);
1889}
1890
1892{
1897};
1898
1899static void test_height( HDC hdc, const struct font_data *fd )
1900{
1901 LOGFONTA lf;
1902 HFONT hfont, old_hfont;
1904 INT ret, i;
1905
1906 for (i = 0; fd[i].face_name[0]; i++)
1907 {
1908 if (!is_truetype_font_installed(fd[i].face_name))
1909 {
1910 skip("%s is not installed\n", fd[i].face_name);
1911 continue;
1912 }
1913
1914 memset(&lf, 0, sizeof(lf));
1915 lf.lfHeight = fd[i].requested_height;
1916 lf.lfWeight = fd[i].weight;
1917 strcpy(lf.lfFaceName, fd[i].face_name);
1918
1920 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
1921
1922 old_hfont = SelectObject(hdc, hfont);
1924 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1925 if(fd[i].dpi == tm.tmDigitizedAspectX)
1926 {
1927 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1928 ok(match_off_by_1(tm.tmHeight, fd[i].height, fd[i].exact), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1929 ok(match_off_by_1(tm.tmAscent, fd[i].ascent, fd[i].exact), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1930 ok(match_off_by_1(tm.tmDescent, fd[i].descent, fd[i].exact), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1931 ok(match_off_by_1(tm.tmInternalLeading, fd[i].int_leading, fd[i].exact), "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1932 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1933 }
1934
1935 SelectObject(hdc, old_hfont);
1936 /* force GDI to use new font, otherwise Windows leaks the font reference */
1939 }
1940}
1941
1942static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1943{
1944 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1945 DWORD *table = (DWORD *)ttf + 3;
1946
1947 for (i = 0; i < num_tables; i++)
1948 {
1949 if (table[0] == tag)
1950 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1951 table += 4;
1952 }
1953 return NULL;
1954}
1955
1957{
1958 static const struct font_data charset_0[] = /* doesn't use VDMX */
1959 {
1960 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1961 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1962 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1963 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1964 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1965 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1966 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1967 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1968 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1969 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1970 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1971 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1972 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1973 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1974 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1975 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1976 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1977 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1978 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1979 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1980 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1981 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1982 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1983 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1984 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1985 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1986 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1987 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1988 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1989 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1990 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1991 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1992 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1993 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1994 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1995 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1996 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1997 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1998 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1999 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
2000 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2001 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
2002 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
2003 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
2004 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
2005 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
2006 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
2007 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
2008 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
2009 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2010 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
2011 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2012 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2013 };
2014
2015 static const struct font_data charset_1[] = /* Uses VDMX */
2016 {
2017 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
2018 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
2019 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2020 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2021 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2022 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2023 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2024 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2025 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2026 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2027 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2028 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2029 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2030 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2031 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2032 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2033 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2034 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2035 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2036 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2037 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2038 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2039 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2040 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
2041 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
2042 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
2043 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2044 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2045 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2046 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2047 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2048 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2049 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2050 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2051 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2052 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2053 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2054 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2055 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2056 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2057 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2058 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2059 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2060 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2061 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2062 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2063 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2064 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2065 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2066 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2067 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2068 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2069 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2070 };
2071
2072 static const struct vdmx_data
2073 {
2074 WORD version;
2075 BYTE bCharSet;
2076 const struct font_data *fd;
2077 } data[] =
2078 {
2079 { 0, 0, charset_0 },
2080 { 0, 1, charset_1 },
2081 { 1, 0, charset_0 },
2082 { 1, 1, charset_1 }
2083 };
2084 int i;
2085 DWORD size, num;
2086 WORD *vdmx_header;
2087 BYTE *ratio_rec;
2088 char ttf_name[MAX_PATH];
2089 void *res, *copy;
2090 BOOL ret;
2091
2092 if (!pAddFontResourceExA)
2093 {
2094 win_skip("AddFontResourceExA unavailable\n");
2095 return;
2096 }
2097
2098 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2099 {
2100 res = get_res_data( "wine_vdmx.ttf", &size );
2101
2102 copy = HeapAlloc( GetProcessHeap(), 0, size );
2103 memcpy( copy, res, size );
2104 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2105 vdmx_header[0] = GET_BE_WORD( data[i].version );
2106 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2107 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2108 ratio_rec = (BYTE *)&vdmx_header[3];
2109 ratio_rec[0] = data[i].bCharSet;
2110
2111 write_tmp_file( copy, &size, ttf_name );
2112 HeapFree( GetProcessHeap(), 0, copy );
2113
2114 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2115 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2116 if (!num) win_skip("Unable to add ttf font resource\n");
2117 else
2118 {
2119 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2120 test_height( hdc, data[i].fd );
2121 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2122 }
2123 ret = DeleteFileA( ttf_name );
2125 "DeleteFile error %d\n", GetLastError());
2126 }
2127}
2128
2129static void test_height_selection(void)
2130{
2131 static const struct font_data tahoma[] =
2132 {
2133 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2134 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2135 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2136 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2137 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2138 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2139 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2140 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2141 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2142 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2143 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2144 };
2146 ok(hdc != NULL, "failed to create hdc\n");
2147
2148 test_height( hdc, tahoma );
2150
2151 DeleteDC(hdc);
2152}
2153
2155{
2156 OUTLINETEXTMETRICA *otm;
2157 HFONT hfont, hfont_old;
2158 DWORD ret, otm_size;
2159 UINT fsSelection;
2160 HDC hdc;
2161
2162 hdc = GetDC(0);
2164 ok(hfont != NULL, "failed to create a font\n");
2165
2166 hfont_old = SelectObject(hdc, hfont);
2167
2168 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2169 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2170 otm->otmSize = sizeof(*otm);
2171 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2172 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2173 fsSelection = otm->otmfsSelection;
2174 HeapFree(GetProcessHeap(), 0, otm);
2175 SelectObject(hdc, hfont_old);
2177 ReleaseDC(0, hdc);
2178
2179 return fsSelection;
2180}
2181
2183{
2184 OUTLINETEXTMETRICA *otm;
2185 LOGFONTA lf;
2186 HFONT hfont, hfont_old;
2187 HDC hdc;
2188 DWORD ret, otm_size;
2189 LPSTR unset_ptr;
2190 UINT fsSelection;
2191
2192 /* check fsSelection field with bold simulation */
2193 memset(&lf, 0, sizeof(lf));
2194 strcpy(lf.lfFaceName, "Wingdings");
2196
2197 /* regular face */
2198 fsSelection = get_font_fsselection(&lf);
2199 ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection);
2200
2201 /* face with bold simulation */
2202 lf.lfWeight = FW_BOLD;
2203 fsSelection = get_font_fsselection(&lf);
2204 ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection);
2205
2206 /* check fsSelection field with oblique simulation */
2207 memset(&lf, 0, sizeof(lf));
2208 strcpy(lf.lfFaceName, "Tahoma");
2209 lf.lfHeight = -13;
2210 lf.lfWeight = FW_NORMAL;
2213
2214 /* regular face */
2215 fsSelection = get_font_fsselection(&lf);
2216 ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection);
2217
2218 lf.lfItalic = 1;
2219 /* face with oblique simulation */
2220 fsSelection = get_font_fsselection(&lf);
2221 ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection);
2222
2223 if (!is_font_installed("Arial"))
2224 {
2225 skip("Arial is not installed\n");
2226 return;
2227 }
2228
2229 hdc = GetDC(0);
2230
2231 memset(&lf, 0, sizeof(lf));
2232 strcpy(lf.lfFaceName, "Arial");
2233 lf.lfHeight = -13;
2234 lf.lfWeight = FW_NORMAL;
2238 ok(hfont != NULL, "failed to create a font\n");
2239
2240 hfont_old = SelectObject(hdc, hfont);
2241 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2242 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2243
2244 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2245
2246 memset(otm, 0xAA, otm_size);
2247 SetLastError(0xdeadbeef);
2248 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2249 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2250 ok(ret == 1 /* Win9x */ ||
2251 ret == otm->otmSize /* XP*/,
2252 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2253 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2254 {
2255 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2256 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2257 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2258 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2259 }
2260
2261 memset(otm, 0xAA, otm_size);
2262 SetLastError(0xdeadbeef);
2263 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2264 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2265 ok(ret == 1 /* Win9x */ ||
2266 ret == otm->otmSize /* XP*/,
2267 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2268 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2269 {
2270 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2271 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2272 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2273 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2274 }
2275
2276 /* ask about truncated data */
2277 memset(otm, 0xAA, otm_size);
2278 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2279 SetLastError(0xdeadbeef);
2280 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2281 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2282 ok(ret == 1 /* Win9x */ ||
2283 ret == otm->otmSize /* XP*/,
2284 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2285 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2286 {
2287 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2288 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2289 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2290 }
2291 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2292
2293 /* check handling of NULL pointer */
2294 SetLastError(0xdeadbeef);
2295 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2296 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2297
2298 HeapFree(GetProcessHeap(), 0, otm);
2299
2300 SelectObject(hdc, hfont_old);
2302
2303 ReleaseDC(0, hdc);
2304}
2305
2306static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2307{
2308 INT y,
2309 breakCount,
2310 areaWidth = clientArea->right - clientArea->left,
2311 nErrors = 0, e;
2312 const char *pFirstChar, *pLastChar;
2313 SIZE size;
2315 struct err
2316 {
2317 const char *start;
2318 int len;
2319 int GetTextExtentExPointWWidth;
2320 } error[20];
2321
2323 y = clientArea->top;
2324 do {
2325 breakCount = 0;
2326 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2327 pFirstChar = str;
2328
2329 do {
2330 pLastChar = str;
2331
2332 /* if not at the end of the string, ... */
2333 if (*str == '\0') break;
2334 /* ... add the next word to the current extent */
2335 while (*str != '\0' && *str++ != tm.tmBreakChar);
2336 breakCount++;
2338 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2339 } while ((int) size.cx < areaWidth);
2340
2341 /* ignore trailing break chars */
2342 breakCount--;
2343 while (*(pLastChar - 1) == tm.tmBreakChar)
2344 {
2345 pLastChar--;
2346 breakCount--;
2347 }
2348
2349 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2350
2352 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2353
2354 /* do not justify the last extent */
2355 if (*str != '\0' && breakCount > 0)
2356 {
2357 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2358 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2359 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2360 {
2361 error[nErrors].start = pFirstChar;
2362 error[nErrors].len = pLastChar - pFirstChar;
2363 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2364 nErrors++;
2365 }
2366 }
2367
2368 y += size.cy;
2369 str = pLastChar;
2370 } while (*str && y < clientArea->bottom);
2371
2372 for (e = 0; e < nErrors; e++)
2373 {
2374 /* The width returned by GetTextExtentPoint32() is exactly the same
2375 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2376 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2377 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2378 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2379 }
2380}
2381
2383{
2384 HDC hdc;
2385 RECT clientArea;
2386 LOGFONTA lf;
2387 HFONT hfont;
2388 HWND hwnd;
2389 SIZE size, expect;
2390 int i;
2391 WORD indices[2];
2392 static const char testText[] =
2393 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2394 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2395 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2396 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2397 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2398 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2399 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2400
2401 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2402 GetClientRect( hwnd, &clientArea );
2403 hdc = GetDC( hwnd );
2404
2405 if (!is_font_installed("Times New Roman"))
2406 {
2407 skip("Times New Roman is not installed\n");
2408 return;
2409 }
2410
2411 memset(&lf, 0, sizeof lf);
2414 lf.lfWeight = FW_DONTCARE;
2415 lf.lfHeight = 20;
2417 lstrcpyA(lf.lfFaceName, "Times New Roman");
2418 hfont = create_font("Times New Roman", &lf);
2420
2421 testJustification(hdc, testText, &clientArea);
2422
2423 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2424 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2425
2427 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2428 GetTextExtentPoint32A(hdc, " ", 3, &size);
2429 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2431 GetTextExtentPoint32A(hdc, " ", 1, &size);
2432 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2434 GetTextExtentPoint32A(hdc, " ", 2, &size);
2435 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2437 GetTextExtentPoint32A(hdc, " ", 3, &size);
2438 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2441 GetTextExtentPoint32A(hdc, " ", 3, &size);
2442 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2445 size.cx = size.cy = 1234;
2446 GetTextExtentPoint32A(hdc, " ", 0, &size);
2447 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2448 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2450 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2451 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2453
2455 SetWindowExtEx( hdc, 2, 2, NULL );
2456 GetClientRect( hwnd, &clientArea );
2457 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2458 testJustification(hdc, testText, &clientArea);
2459
2460 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2461 for (i = 0; i < 10; i++)
2462 {
2464 GetTextExtentPoint32A(hdc, "A", 1, &size);
2465 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2466 }
2468 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2469 for (i = 0; i < 10; i++)
2470 {
2472 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2473 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2474 }
2476
2477 SetViewportExtEx( hdc, 3, 3, NULL );
2478 GetClientRect( hwnd, &clientArea );
2479 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2480 testJustification(hdc, testText, &clientArea);
2481
2482 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2483 for (i = 0; i < 10; i++)
2484 {
2486 GetTextExtentPoint32A(hdc, "A", 1, &size);
2487 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2488 }
2489
2490done:
2492 ReleaseDC(hwnd, hdc);
2494}
2495
2496static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2497{
2498 HDC hdc;
2499 LOGFONTA lf;
2500 HFONT hfont, hfont_old;
2501 CHARSETINFO csi;
2503 INT cs;
2504 DWORD i, ret;
2505 char name[64];
2506
2507 assert(count <= 128);
2508
2509 memset(&lf, 0, sizeof(lf));
2510
2511 lf.lfCharSet = charset;
2512 lf.lfHeight = 10;
2513 lstrcpyA(lf.lfFaceName, "Arial");
2514 SetLastError(0xdeadbeef);
2516 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2517
2518 hdc = GetDC(0);
2519 hfont_old = SelectObject(hdc, hfont);
2520
2521 cs = GetTextCharsetInfo(hdc, &fs, 0);
2522 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2523
2524 SetLastError(0xdeadbeef);
2525 ret = GetTextFaceA(hdc, sizeof(name), name);
2526 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2527
2528 if (charset == SYMBOL_CHARSET)
2529 {
2530 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2531 ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n");
2532 }
2533 else
2534 {
2535 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2536 ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2537 }
2538
2540 {
2541 trace("Can't find codepage for charset %d\n", cs);
2542 ReleaseDC(0, hdc);
2543 return FALSE;
2544 }
2545 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2546
2547 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2548 {
2549 skip("Font code page %d, looking for code page %d\n",
2550 pGdiGetCodePage(hdc), code_page);
2551 ReleaseDC(0, hdc);
2552 return FALSE;
2553 }
2554
2555 if (unicode)
2556 {
2557 char ansi_buf[128];
2558 WCHAR unicode_buf[128];
2559
2560 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2561
2562 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2563
2564 SetLastError(0xdeadbeef);
2565 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2566 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2567 count, ret, GetLastError());
2568 }
2569 else
2570 {
2571 char ansi_buf[128];
2572
2573 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2574
2575 SetLastError(0xdeadbeef);
2576 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2577 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2578 count, ret, GetLastError());
2579 }
2580
2581 SelectObject(hdc, hfont_old);
2583
2584 ReleaseDC(0, hdc);
2585
2586 return TRUE;
2587}
2588
2589static void test_font_charset(void)
2590{
2591 static struct charset_data
2592 {
2593 INT charset;
2594 UINT code_page;
2595 WORD font_idxA[128], font_idxW[128];
2596 } cd[] =
2597 {
2598 { ANSI_CHARSET, 1252 },
2599 { RUSSIAN_CHARSET, 1251 },
2600 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2601 };
2602 int i;
2603
2604 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2605 {
2606 win_skip("Skipping the font charset test on a Win9x platform\n");
2607 return;
2608 }
2609
2610 if (!is_font_installed("Arial"))
2611 {
2612 skip("Arial is not installed\n");
2613 return;
2614 }
2615
2616 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2617 {
2618 if (cd[i].charset == SYMBOL_CHARSET)
2619 {
2620 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2621 {
2622 skip("Symbol or Wingdings is not installed\n");
2623 break;
2624 }
2625 }
2626 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2627 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2628 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2629 }
2630
2631 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2632 if (i > 2)
2633 {
2634 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2635 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2636 }
2637 else
2638 skip("Symbol or Wingdings is not installed\n");
2639}
2640
2641static void test_GdiGetCodePage(void)
2642{
2643 static const struct _matching_data
2644 {
2645 UINT current_codepage;
2646 LPCSTR lfFaceName;
2647 UCHAR lfCharSet;
2648 UINT expected_codepage;
2649 } matching_data[] = {
2650 {1251, "Arial", ANSI_CHARSET, 1252},
2651 {1251, "Tahoma", ANSI_CHARSET, 1252},
2652
2653 {1252, "Arial", ANSI_CHARSET, 1252},
2654 {1252, "Tahoma", ANSI_CHARSET, 1252},
2655
2656 {1253, "Arial", ANSI_CHARSET, 1252},
2657 {1253, "Tahoma", ANSI_CHARSET, 1252},
2658
2659 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2660 { 932, "Tahoma", ANSI_CHARSET, 1252},
2661 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2662
2663 { 936, "Arial", ANSI_CHARSET, 936},
2664 { 936, "Tahoma", ANSI_CHARSET, 936},
2665 { 936, "Simsun", ANSI_CHARSET, 936},
2666
2667 { 949, "Arial", ANSI_CHARSET, 949},
2668 { 949, "Tahoma", ANSI_CHARSET, 949},
2669 { 949, "Gulim", ANSI_CHARSET, 949},
2670
2671 { 950, "Arial", ANSI_CHARSET, 950},
2672 { 950, "Tahoma", ANSI_CHARSET, 950},
2673 { 950, "PMingLiU", ANSI_CHARSET, 950},
2674 };
2675 HDC hdc;
2676 LOGFONTA lf;
2677 HFONT hfont;
2678 UINT charset, acp;
2680 int i;
2681
2682 if (!pGdiGetCodePage)
2683 {
2684 skip("GdiGetCodePage not available on this platform\n");
2685 return;
2686 }
2687
2688 acp = GetACP();
2689
2690 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2691 {
2692 /* only test data matched current locale codepage */
2693 if (matching_data[i].current_codepage != acp)
2694 continue;
2695
2696 if (!is_font_installed(matching_data[i].lfFaceName))
2697 {
2698 skip("%s is not installed\n", matching_data[i].lfFaceName);
2699 continue;
2700 }
2701
2702 hdc = GetDC(0);
2703
2704 memset(&lf, 0, sizeof(lf));
2705 lf.lfHeight = -16;
2706 lf.lfCharSet = matching_data[i].lfCharSet;
2707 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2709 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2710
2713 codepage = pGdiGetCodePage(hdc);
2714 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2715 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2716 ok(codepage == matching_data[i].expected_codepage,
2717 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2718
2721
2722 /* CLIP_DFA_DISABLE turns off the font association */
2725 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2726
2729 codepage = pGdiGetCodePage(hdc);
2730 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2731 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2732 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2733
2736
2737 ReleaseDC(NULL, hdc);
2738 }
2739}
2740
2742{
2743 LOGFONTA lf;
2744 HDC hdc;
2745 HFONT hfont, hfont_old;
2746 DWORD size;
2747 GLYPHSET *gs;
2748 DWORD i;
2749
2750 if (!pGetFontUnicodeRanges)
2751 {
2752 win_skip("GetFontUnicodeRanges not available before W2K\n");
2753 return;
2754 }
2755
2756 memset(&lf, 0, sizeof(lf));
2757 lstrcpyA(lf.lfFaceName, "Arial");
2758 hfont = create_font("Arial", &lf);
2759
2760 hdc = GetDC(0);
2761 hfont_old = SelectObject(hdc, hfont);
2762
2763 size = pGetFontUnicodeRanges(NULL, NULL);
2764 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2765
2766 size = pGetFontUnicodeRanges(hdc, NULL);
2767 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2768
2770
2771 size = pGetFontUnicodeRanges(hdc, gs);
2772 ok(size, "GetFontUnicodeRanges failed\n");
2773
2774 if (0) /* Disabled to limit console spam */
2775 for (i = 0; i < gs->cRanges; i++)
2776 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2777 trace("found %u ranges\n", gs->cRanges);
2778
2779 HeapFree(GetProcessHeap(), 0, gs);
2780
2781 SelectObject(hdc, hfont_old);
2783 ReleaseDC(NULL, hdc);
2784}
2785
2787{
2790};
2791
2793{
2796};
2797
2799{
2802};
2803
2805{
2806 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2807 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2808
2809 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2810 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2811
2812 if (type != TRUETYPE_FONTTYPE) return 1;
2813
2814 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2815
2816 if (0) /* Disabled to limit console spam */
2817 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2819 if (efd->total >= efd->size)
2820 {
2821 efd->size = max( (efd->total + 1) * 2, 256 );
2822 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2823 if (!efd->lf) return 0;
2824 }
2825 efd->lf[efd->total++] = *lf;
2826
2827 return 1;
2828}
2829
2831{
2832 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2833 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2834
2835 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2836 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2837
2838 if (type != TRUETYPE_FONTTYPE) return 1;
2839
2840 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2841
2842 if (0) /* Disabled to limit console spam */
2843 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2845 if (efd->total >= efd->size)
2846 {
2847 efd->size = max( (efd->total + 1) * 2, 256 );
2848 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2849 if (!efd->lf) return 0;
2850 }
2851 efd->lf[efd->total++] = *lf;
2852
2853 return 1;
2854}
2855
2856static void get_charset_stats(struct enum_font_data *efd,
2857 int *ansi_charset, int *symbol_charset,
2858 int *russian_charset)
2859{
2860 int i;
2861
2862 *ansi_charset = 0;
2863 *symbol_charset = 0;
2864 *russian_charset = 0;
2865
2866 for (i = 0; i < efd->total; i++)
2867 {
2868 switch (efd->lf[i].lfCharSet)
2869 {
2870 case ANSI_CHARSET:
2871 (*ansi_charset)++;
2872 break;
2873 case SYMBOL_CHARSET:
2874 (*symbol_charset)++;
2875 break;
2876 case RUSSIAN_CHARSET:
2877 (*russian_charset)++;
2878 break;
2879 }
2880 }
2881}
2882
2883static void get_charset_statsW(struct enum_font_dataW *efd,
2884 int *ansi_charset, int *symbol_charset,
2885 int *russian_charset)
2886{
2887 int i;
2888
2889 *ansi_charset = 0;
2890 *symbol_charset = 0;
2891 *russian_charset = 0;
2892
2893 for (i = 0; i < efd->total; i++)
2894 {
2895 switch (efd->lf[i].lfCharSet)
2896 {
2897 case ANSI_CHARSET:
2898 (*ansi_charset)++;
2899 break;
2900 case SYMBOL_CHARSET:
2901 (*symbol_charset)++;
2902 break;
2903 case RUSSIAN_CHARSET:
2904 (*russian_charset)++;
2905 break;
2906 }
2907 }
2908}
2909
2910static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2911{
2912 struct enum_font_data efd;
2913 struct enum_font_dataW efdw;
2914 LOGFONTA lf;
2915 HDC hdc;
2916 int i, ret, ansi_charset, symbol_charset, russian_charset;
2917
2918 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2919
2920 if (*font_name && !is_truetype_font_installed(font_name))
2921 {
2922 skip("%s is not installed\n", font_name);
2923 return;
2924 }
2925 memset( &efd, 0, sizeof(efd) );
2926 memset( &efdw, 0, sizeof(efdw) );
2927
2928 hdc = GetDC(0);
2929
2930 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2931 * while EnumFontFamiliesEx doesn't.
2932 */
2933 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2934 {
2935 /*
2936 * Use EnumFontFamiliesW since win98 crashes when the
2937 * second parameter is NULL using EnumFontFamilies
2938 */
2939 efdw.total = 0;
2940 SetLastError(0xdeadbeef);
2942 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2943 if(ret)
2944 {
2945 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2946 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2947 ansi_charset, symbol_charset, russian_charset);
2948 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2949 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2950 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2951 ok(russian_charset > 0 ||
2952 broken(russian_charset == 0), /* NT4 */
2953 "NULL family should enumerate RUSSIAN_CHARSET\n");
2954 }
2955
2956 efdw.total = 0;
2957 SetLastError(0xdeadbeef);
2959 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2960 if(ret)
2961 {
2962 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2963 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2964 ansi_charset, symbol_charset, russian_charset);
2965 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2966