[NTOS:KD] Use Zw* syscall variants
[reactos.git] / modules / rostests / winetests / gdi32 / font.c
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
34 static 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
42 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
43 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
44 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
45 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
46 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
47 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
48 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
49 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
50 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
51 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
52 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
53 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
54 LPINT nfit, LPINT dxs, LPSIZE size );
55 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
56 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
57 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
58 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
59 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
60 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
61 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
62 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *);
63 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
64
65 static HMODULE hgdi32 = 0;
66 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
67 static WORD system_lang_id;
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
84 static 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
110 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
111 }
112
113 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
114 {
115 if (type != TRUETYPE_FONTTYPE) return 1;
116
117 return 0;
118 }
119
120 static BOOL is_truetype_font_installed(const char *name)
121 {
122 HDC hdc = GetDC(0);
123 BOOL ret = FALSE;
124
125 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
126 ret = TRUE;
127
128 ReleaseDC(0, hdc);
129 return ret;
130 }
131
132 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
133 {
134 return 0;
135 }
136
137 static BOOL is_font_installed(const char *name)
138 {
139 HDC hdc = GetDC(0);
140 BOOL ret = FALSE;
141
142 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
143 ret = TRUE;
144
145 ReleaseDC(0, hdc);
146 return ret;
147 }
148
149 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
150 {
151 HRSRC rsrc;
152 void *rsrc_data;
153
154 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
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
166 static 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
175 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
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
184 static 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
195 static 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
237 static HFONT create_font(const char* test, const LOGFONTA* lf)
238 {
239 HFONT hfont = CreateFontIndirectA(lf);
240 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
241 if (hfont)
242 check_font(test, lf, hfont);
243 return hfont;
244 }
245
246 static void test_logfont(void)
247 {
248 LOGFONTA lf;
249 HFONT hfont;
250
251 memset(&lf, 0, sizeof lf);
252
253 lf.lfCharSet = ANSI_CHARSET;
254 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
255 lf.lfWeight = FW_DONTCARE;
256 lf.lfHeight = 16;
257 lf.lfWidth = 16;
258 lf.lfQuality = DEFAULT_QUALITY;
259
260 lstrcpyA(lf.lfFaceName, "Arial");
261 hfont = create_font("Arial", &lf);
262 DeleteObject(hfont);
263
264 memset(&lf, 'A', sizeof(lf));
265 hfont = CreateFontIndirectA(&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);
270 DeleteObject(hfont);
271 }
272
273 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
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
285 static 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
309 static 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;
316 OUTLINETEXTMETRICA otm;
317 TEXTMETRICA tm;
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
329 if (GetOutlineTextMetricsA(hdc, 0, NULL))
330 {
331 otm.otmSize = sizeof(otm) / 2;
332 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
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);
338 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &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));
343 ret = GetTextMetricsA(hdc, &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");
349 compare_tm(&tm, &otm.otmTextMetrics);
350 }
351
352 tm = otm.otmTextMetrics;
353 if (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 {
367 ret = GetTextMetricsA(hdc, &tm);
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 */
401 static 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
411 hdc = CreateCompatibleDC(0);
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);
433 DeleteObject(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);
441 DeleteObject(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);
464 DeleteObject(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);
474 DeleteObject(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);
483 DeleteObject(hfont);
484
485 DeleteDC(hdc);
486 }
487
488 /* Test how GDI scales outline font metrics */
489 static 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;
495 OUTLINETEXTMETRICA otm;
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
510 hdc = CreateCompatibleDC(0);
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);
524 DeleteObject(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);
536 DeleteObject(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);
548 DeleteObject(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);
557 DeleteObject(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);
566 DeleteObject(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
600 SetMapMode(hdc, MM_ANISOTROPIC);
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 */
625 SetMapMode(hdc, MM_TEXT);
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
633 if (!SetGraphicsMode(hdc, GM_ADVANCED))
634 {
635 SelectObject(hdc, old_hfont);
636 DeleteObject(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);
679 ret = SetMapMode(hdc, MM_LOMETRIC);
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);
706 ret = SetMapMode(hdc, MM_TEXT);
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);
735 DeleteObject(hfont);
736 DeleteDC(hdc);
737 }
738
739 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
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
751 static BOOL is_CJK(void)
752 {
753 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
754 }
755
756 #define FH_SCALE 0x80000000
757 static void test_bitmap_font_metrics(void)
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];
763 int weight, height, ascent, descent, int_leading, ext_leading;
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;
915 TEXTMETRICA tm;
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
931 hdc = CreateCompatibleDC(0);
932 ok(hdc != NULL, "failed to create hdc\n");
933
934 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
935 GetDeviceCaps(hdc, LOGPIXELSY));
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;
973 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
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);
999 DeleteObject(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);
1015 ret = GetTextCharset(hdc);
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",
1064 system_lang_id);
1065 }
1066 SelectObject(hdc, old_hfont);
1067 DeleteObject(hfont);
1068 }
1069 }
1070
1071 DeleteDC(hdc);
1072 }
1073
1074 static void test_GdiGetCharDimensions(void)
1075 {
1076 HDC hdc;
1077 TEXTMETRICW tm;
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
1089 hdc = CreateCompatibleDC(NULL);
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
1112 static 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
1131 static 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
1156 static 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,
1197 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1198 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1199 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1200 {HANGEUL_CHARSET, 0x8141, 0xac02,
1201 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1202 {GB2312_CHARSET, 0x8141, 0x4e04,
1203 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1204 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1205 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
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
1219 hfont = CreateFontIndirectA(&lf);
1220 hdc = GetDC(0);
1221 hfont = SelectObject(hdc, hfont);
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
1253 hfont = SelectObject(hdc, hfont);
1254 DeleteObject(hfont);
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;
1265 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 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);
1273 hfont = SelectObject(hdc, hfont);
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
1304 hfont = SelectObject(hdc, hfont);
1305 DeleteObject(hfont);
1306 }
1307
1308 memset(&lf, 0, sizeof(lf));
1309 strcpy(lf.lfFaceName, "Tahoma");
1310 lf.lfHeight = 200;
1311 hfont = CreateFontIndirectA(&lf);
1312
1313 /* test empty glyph's metrics */
1314 hfont = SelectObject(hdc, hfont);
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");
1325 DeleteObject(SelectObject(hdc, hfont));
1326
1327 /* 2) get rotated font metrics */
1328 lf.lfEscapement = lf.lfOrientation = 900;
1329 hfont = CreateFontIndirectA(&lf);
1330 hfont = SelectObject(hdc, hfont);
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
1342 DeleteObject(SelectObject(hdc, hfont));
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 }
1365 if (!is_truetype_font_installed(lf.lfFaceName))
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;
1375 hfont = CreateFontIndirectA(&lf);
1376 hfont = SelectObject(hdc, hfont);
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
1381 ret = GetCharABCWidthsA(hdc, code, code, abc);
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);
1390 DeleteObject(SelectObject(hdc, hfont));
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;
1399 hfont = CreateFontIndirectA(&lf);
1400 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1401 0, 0, 0, NULL);
1402 hdc = GetDC(hwnd);
1403 SetMapMode(hdc, MM_ANISOTROPIC);
1404 SelectObject(hdc, hfont);
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);
1418 SetGraphicsMode(hdc, GM_COMPATIBLE);
1419 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf);
1420 SetGraphicsMode(hdc, GM_ADVANCED);
1421 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf);
1422 SetWindowExtEx(hdc, 1, 1, NULL);
1423 SetGraphicsMode(hdc, GM_COMPATIBLE);
1424 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf);
1425 SetGraphicsMode(hdc, GM_ADVANCED);
1426 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf);
1427
1428 ReleaseDC(hwnd, hdc);
1429 DestroyWindow(hwnd);
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);
1435 SetMapMode(hdc, MM_ANISOTROPIC);
1436 SelectObject(hdc, hfont);
1437
1438 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf);
1439 SetWindowExtEx(hdc, -1, -1, NULL);
1440 SetGraphicsMode(hdc, GM_COMPATIBLE);
1441 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf);
1442 SetGraphicsMode(hdc, GM_ADVANCED);
1443 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf);
1444 SetWindowExtEx(hdc, 1, 1, NULL);
1445 SetGraphicsMode(hdc, GM_COMPATIBLE);
1446 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf);
1447 SetGraphicsMode(hdc, GM_ADVANCED);
1448 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf);
1449
1450 ReleaseDC(hwnd, hdc);
1451 DestroyWindow(hwnd);
1452 DeleteObject(hfont);
1453 }
1454
1455 static 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;
1462 TEXTMETRICA tm;
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
1473 hfont = CreateFontIndirectA(&lf);
1474 hdc = GetDC(0);
1475 hfont = SelectObject(hdc, hfont);
1476 GetTextMetricsA(hdc, &tm);
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);
1493 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1494 {
1495 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1496 hfont = SelectObject(hdc, hfont);
1497 DeleteObject(hfont);
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
1585 hfont = SelectObject(hdc, hfont);
1586 DeleteObject(hfont);
1587
1588 /* non-MM_TEXT mapping mode */
1589 lf.lfHeight = 2000;
1590 hfont = CreateFontIndirectA(&lf);
1591 hfont = SelectObject(hdc, hfont);
1592
1593 SetMapMode( hdc, MM_HIMETRIC );
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
1605 hfont = SelectObject(hdc, hfont);
1606 DeleteObject(hfont);
1607 HeapFree(GetProcessHeap(), 0, extents);
1608 ReleaseDC(NULL, hdc);
1609 }
1610
1611 static 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;
1633 lf.lfCharSet = ANSI_CHARSET;
1634
1635 hfont = CreateFontIndirectA(&lf);
1636 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1637 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1638 if (textm.tmCharSet == ANSI_CHARSET)
1639 {
1640 flags |= GGI_MARK_NONEXISTING_GLYPHS;
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
1663 hfont = CreateFontIndirectA(&lf);
1664 hOldFont = SelectObject(hdc, hfont);
1665 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1666 flags |= GGI_MARK_NONEXISTING_GLYPHS;
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
1679 static 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);
1769 GetKerningPairsW(hdc, 0, NULL);
1770 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
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 {
1779 OUTLINETEXTMETRICW otm;
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;
1793 hfont = CreateFontIndirectA(&lf);
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);
1822 todo_wine
1823 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1824 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1825 todo_wine
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);
1830 todo_wine
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);
1843 ok(GetLastError() == ERROR_INVALID_PARAMETER,
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);
1885 DeleteObject(hfont);
1886 }
1887
1888 ReleaseDC(0, hdc);
1889 }
1890
1891 struct font_data
1892 {
1893 const char face_name[LF_FACESIZE];
1894 int requested_height;
1895 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1896 BOOL exact;
1897 };
1898
1899 static void test_height( HDC hdc, const struct font_data *fd )
1900 {
1901 LOGFONTA lf;
1902 HFONT hfont, old_hfont;
1903 TEXTMETRICA tm;
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
1919 hfont = CreateFontIndirectA(&lf);
1920 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
1921
1922 old_hfont = SelectObject(hdc, hfont);
1923 ret = GetTextMetricsA(hdc, &tm);
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 */
1937 GetTextMetricsA(hdc, &tm);
1938 DeleteObject(hfont);
1939 }
1940 }
1941
1942 static 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
1956 static void test_height_selection_vdmx( HDC hdc )
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 );
2124 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2125 "DeleteFile error %d\n", GetLastError());
2126 }
2127 }
2128
2129 static 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 };
2145 HDC hdc = CreateCompatibleDC(0);
2146 ok(hdc != NULL, "failed to create hdc\n");
2147
2148 test_height( hdc, tahoma );
2149 test_height_selection_vdmx( hdc );
2150
2151 DeleteDC(hdc);
2152 }
2153
2154 static UINT get_font_fsselection(LOGFONTA *lf)
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);
2163 hfont = CreateFontIndirectA(lf);
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);
2176 DeleteObject(hfont);
2177 ReleaseDC(0, hdc);
2178
2179 return fsSelection;
2180 }
2181
2182 static void test_GetOutlineTextMetrics(void)
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");
2195 lf.lfCharSet = SYMBOL_CHARSET;
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;
2211 lf.lfPitchAndFamily = DEFAULT_PITCH;
2212 lf.lfQuality = PROOF_QUALITY;
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;
2235 lf.lfPitchAndFamily = DEFAULT_PITCH;
2236 lf.lfQuality = PROOF_QUALITY;
2237 hfont = CreateFontIndirectA(&lf);
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);
2301 DeleteObject(hfont);
2302
2303 ReleaseDC(0, hdc);
2304 }
2305
2306 static 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;
2314 TEXTMETRICA tm;
2315 struct err
2316 {
2317 const char *start;
2318 int len;
2319 int GetTextExtentExPointWWidth;
2320 } error[20];
2321
2322 GetTextMetricsA(hdc, &tm);
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++;
2337 SetTextJustification(hdc, 0, 0);
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
2351 SetTextJustification(hdc, 0, 0);
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);