70708d5438552bc0340fc88fc323f482729d20d8
[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/test.h"
32
33 static inline BOOL match_off_by_n(int a, int b, unsigned int n)
34 {
35 return abs(a - b) <= n;
36 }
37 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
38 #define near_match(a, b) match_off_by_n((a), (b), 6)
39 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
40
41 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
42 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
43 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
45 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
46 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
47 static BOOL (WINAPI *pGetCharWidth32A)(HDC hdc, UINT first, UINT last, LPINT buffer);
48 static BOOL (WINAPI *pGetCharWidth32W)(HDC hdc, UINT first, UINT last, LPINT buffer);
49 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
50 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
51 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
52 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
53 LPINT nfit, LPINT dxs, LPSIZE size );
54 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
55 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *);
56 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
57 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
58 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
59 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
60 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, DWORD *);
61 static BOOL (WINAPI *pGetFontFileInfo)(DWORD, DWORD, void *, DWORD, DWORD *);
62 static BOOL (WINAPI *pGetFontFileData)(DWORD, DWORD, ULONGLONG, void *, DWORD);
63
64 static HMODULE hgdi32 = 0;
65 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
66 static WORD system_lang_id;
67
68 #ifdef WORDS_BIGENDIAN
69 #define GET_BE_WORD(x) (x)
70 #define GET_BE_DWORD(x) (x)
71 #else
72 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
73 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
74 #endif
75
76 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
77 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
78 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
79 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
80 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
81 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
82
83 static void init(void)
84 {
85 hgdi32 = GetModuleHandleA("gdi32.dll");
86
87 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
88 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
89 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
90 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
91 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
92 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
93 pGetCharWidth32A = (void *)GetProcAddress(hgdi32, "GetCharWidth32A");
94 pGetCharWidth32W = (void *)GetProcAddress(hgdi32, "GetCharWidth32W");
95 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
96 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
97 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
98 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
99 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
100 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
101 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
102 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
103 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
104 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
105 pGetFontRealizationInfo = (void *)GetProcAddress(hgdi32, "GetFontRealizationInfo");
106 pGetFontFileInfo = (void *)GetProcAddress(hgdi32, "GetFontFileInfo");
107 pGetFontFileData = (void *)GetProcAddress(hgdi32, "GetFontFileData");
108
109 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
110 }
111
112 static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size)
113 {
114 return HeapAlloc(GetProcessHeap(), 0, size);
115 }
116
117 static inline void* __WINE_ALLOC_SIZE(2) heap_realloc(void *mem, size_t size)
118 {
119 if (!mem) return heap_alloc(size);
120 return HeapReAlloc(GetProcessHeap(), 0, mem, size);
121 }
122
123 static inline BOOL heap_free(void *mem)
124 {
125 return HeapFree(GetProcessHeap(), 0, mem);
126 }
127
128 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
129 {
130 if (type != TRUETYPE_FONTTYPE) return 1;
131
132 return 0;
133 }
134
135 static BOOL is_truetype_font_installed(const char *name)
136 {
137 HDC hdc = GetDC(0);
138 BOOL ret = FALSE;
139
140 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
141 ret = TRUE;
142
143 ReleaseDC(0, hdc);
144 return ret;
145 }
146
147 static INT CALLBACK is_font_installed_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
148 {
149 return 0;
150 }
151
152 static BOOL is_font_installed(const char *name)
153 {
154 HDC hdc = GetDC(0);
155 BOOL ret = FALSE;
156
157 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
158 ret = TRUE;
159
160 ReleaseDC(0, hdc);
161 return ret;
162 }
163
164 static void *get_res_data(const char *fontname, DWORD *rsrc_size)
165 {
166 HRSRC rsrc;
167 void *rsrc_data;
168
169 rsrc = FindResourceA(GetModuleHandleA(NULL), fontname, (LPCSTR)RT_RCDATA);
170 if (!rsrc) return NULL;
171
172 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
173 if (!rsrc_data) return NULL;
174
175 *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
176 if (!*rsrc_size) return NULL;
177
178 return rsrc_data;
179 }
180
181 static BOOL write_tmp_file( const void *data, DWORD *size, char *tmp_name )
182 {
183 char tmp_path[MAX_PATH];
184 HANDLE hfile;
185 BOOL ret;
186
187 GetTempPathA(MAX_PATH, tmp_path);
188 GetTempFileNameA(tmp_path, "ttf", 0, tmp_name);
189
190 hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
191 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
192
193 ret = WriteFile(hfile, data, *size, size, NULL);
194
195 CloseHandle(hfile);
196 return ret;
197 }
198
199 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
200 {
201 void *rsrc_data;
202 DWORD rsrc_size;
203
204 rsrc_data = get_res_data( fontname, &rsrc_size );
205 if (!rsrc_data) return FALSE;
206
207 return write_tmp_file( rsrc_data, &rsrc_size, tmp_name );
208 }
209
210 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
211 {
212 LOGFONTA getobj_lf;
213 int ret, minlen = 0;
214
215 if (!hfont)
216 return;
217
218 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
219 /* NT4 tries to be clever and only returns the minimum length */
220 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
221 minlen++;
222 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
223 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
224 ok(lf->lfHeight == getobj_lf.lfHeight ||
225 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
226 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
227 ok(lf->lfWidth == getobj_lf.lfWidth ||
228 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
229 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
230 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
231 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
232 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
233 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
234 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
235 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
236 ok(lf->lfWeight == getobj_lf.lfWeight ||
237 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
238 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
239 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
240 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
241 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
242 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
243 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
244 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
245 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
246 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
247 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
248 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
249 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
250 }
251
252 static HFONT create_font(const char* test, const LOGFONTA* lf)
253 {
254 HFONT hfont = CreateFontIndirectA(lf);
255 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
256 if (hfont)
257 check_font(test, lf, hfont);
258 return hfont;
259 }
260
261 static void test_logfont(void)
262 {
263 LOGFONTA lf;
264 HFONT hfont;
265
266 memset(&lf, 0, sizeof lf);
267
268 lf.lfCharSet = ANSI_CHARSET;
269 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
270 lf.lfWeight = FW_DONTCARE;
271 lf.lfHeight = 16;
272 lf.lfWidth = 16;
273 lf.lfQuality = DEFAULT_QUALITY;
274
275 lstrcpyA(lf.lfFaceName, "Arial");
276 hfont = create_font("Arial", &lf);
277 DeleteObject(hfont);
278
279 memset(&lf, 'A', sizeof(lf));
280 hfont = CreateFontIndirectA(&lf);
281 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
282
283 lf.lfFaceName[LF_FACESIZE - 1] = 0;
284 check_font("AAA...", &lf, hfont);
285 DeleteObject(hfont);
286 }
287
288 static INT CALLBACK font_enum_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
289 {
290 if (type & RASTER_FONTTYPE)
291 {
292 LOGFONTA *lf = (LOGFONTA *)lParam;
293 *lf = *elf;
294 return 0; /* stop enumeration */
295 }
296
297 return 1; /* continue enumeration */
298 }
299
300 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
301 {
302 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
303 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
304 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
305 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
306 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
307 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
308 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
309 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
310 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
311 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
312 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
313 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
314 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
315 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
316 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
317 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
318 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
319 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
320 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
321 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
322 }
323
324 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
325 LONG lfWidth, const char *test_str,
326 INT test_str_len, const TEXTMETRICA *tm_orig,
327 const SIZE *size_orig, INT width_of_A_orig,
328 INT scale_x, INT scale_y)
329 {
330 LOGFONTA lf;
331 OUTLINETEXTMETRICA otm;
332 TEXTMETRICA tm;
333 SIZE size;
334 INT width_of_A, cx, cy;
335 UINT ret;
336
337 if (!hfont)
338 return;
339
340 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
341
342 GetObjectA(hfont, sizeof(lf), &lf);
343
344 if (GetOutlineTextMetricsA(hdc, 0, NULL))
345 {
346 otm.otmSize = sizeof(otm) / 2;
347 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
348 ok(ret == sizeof(otm)/2 /* XP */ ||
349 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
350
351 memset(&otm, 0x1, sizeof(otm));
352 otm.otmSize = sizeof(otm);
353 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
354 ok(ret == sizeof(otm) /* XP */ ||
355 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
356
357 memset(&tm, 0x2, sizeof(tm));
358 ret = GetTextMetricsA(hdc, &tm);
359 ok(ret, "GetTextMetricsA failed\n");
360 /* the structure size is aligned */
361 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
362 {
363 ok(0, "tm != otm\n");
364 compare_tm(&tm, &otm.otmTextMetrics);
365 }
366
367 tm = otm.otmTextMetrics;
368 if (0) /* these metrics are scaled too, but with rounding errors */
369 {
370 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
371 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
372 }
373 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
374 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
375 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
376 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
377 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
378 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
379 }
380 else
381 {
382 ret = GetTextMetricsA(hdc, &tm);
383 ok(ret, "GetTextMetricsA failed\n");
384 }
385
386 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
387 cy = tm.tmHeight / tm_orig->tmHeight;
388 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
389 lfHeight, scale_x, scale_y, cx, cy);
390 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
391 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
392 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
393 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
394 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
395
396 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
397 if (lf.lfHeight)
398 {
399 if (lf.lfWidth)
400 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
401 }
402 else
403 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
404
405 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
406
407 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
408 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
409
410 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
411
412 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);
413 }
414
415 /* Test how GDI scales bitmap font metrics */
416 static void test_bitmap_font(void)
417 {
418 static const char test_str[11] = "Test String";
419 HDC hdc;
420 LOGFONTA bitmap_lf;
421 HFONT hfont, old_hfont;
422 TEXTMETRICA tm_orig;
423 SIZE size_orig;
424 INT ret, i, width_orig, height_orig, scale, lfWidth;
425
426 hdc = CreateCompatibleDC(0);
427
428 /* "System" has only 1 pixel size defined, otherwise the test breaks */
429 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
430 if (ret)
431 {
432 ReleaseDC(0, hdc);
433 trace("no bitmap fonts were found, skipping the test\n");
434 return;
435 }
436
437 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
438
439 height_orig = bitmap_lf.lfHeight;
440 lfWidth = bitmap_lf.lfWidth;
441
442 hfont = create_font("bitmap", &bitmap_lf);
443 old_hfont = SelectObject(hdc, hfont);
444 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
445 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
446 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
447 SelectObject(hdc, old_hfont);
448 DeleteObject(hfont);
449
450 bitmap_lf.lfHeight = 0;
451 bitmap_lf.lfWidth = 4;
452 hfont = create_font("bitmap", &bitmap_lf);
453 old_hfont = SelectObject(hdc, hfont);
454 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
455 SelectObject(hdc, old_hfont);
456 DeleteObject(hfont);
457
458 bitmap_lf.lfHeight = height_orig;
459 bitmap_lf.lfWidth = lfWidth;
460
461 /* test fractional scaling */
462 for (i = 1; i <= height_orig * 6; i++)
463 {
464 INT nearest_height;
465
466 bitmap_lf.lfHeight = i;
467 hfont = create_font("fractional", &bitmap_lf);
468 scale = (i + height_orig - 1) / height_orig;
469 nearest_height = scale * height_orig;
470 /* Only jump to the next height if the difference <= 25% original height */
471 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
472 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
473 so we'll not test this particular height. */
474 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
475 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
476 old_hfont = SelectObject(hdc, hfont);
477 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
478 SelectObject(hdc, old_hfont);
479 DeleteObject(hfont);
480 }
481
482 /* test integer scaling 3x2 */
483 bitmap_lf.lfHeight = height_orig * 2;
484 bitmap_lf.lfWidth *= 3;
485 hfont = create_font("3x2", &bitmap_lf);
486 old_hfont = SelectObject(hdc, hfont);
487 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
488 SelectObject(hdc, old_hfont);
489 DeleteObject(hfont);
490
491 /* test integer scaling 3x3 */
492 bitmap_lf.lfHeight = height_orig * 3;
493 bitmap_lf.lfWidth = 0;
494 hfont = create_font("3x3", &bitmap_lf);
495 old_hfont = SelectObject(hdc, hfont);
496 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
497 SelectObject(hdc, old_hfont);
498 DeleteObject(hfont);
499
500 DeleteDC(hdc);
501 }
502
503 /* Test how GDI scales outline font metrics */
504 static void test_outline_font(void)
505 {
506 static const char test_str[11] = "Test String";
507 HDC hdc, hdc_2;
508 LOGFONTA lf;
509 HFONT hfont, old_hfont, old_hfont_2;
510 OUTLINETEXTMETRICA otm;
511 SIZE size_orig;
512 INT width_orig, height_orig, lfWidth;
513 XFORM xform;
514 GLYPHMETRICS gm;
515 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
516 POINT pt;
517 INT ret;
518
519 if (!is_truetype_font_installed("Arial"))
520 {
521 skip("Arial is not installed\n");
522 return;
523 }
524
525 hdc = CreateCompatibleDC(0);
526
527 memset(&lf, 0, sizeof(lf));
528 strcpy(lf.lfFaceName, "Arial");
529 lf.lfHeight = 72;
530 hfont = create_font("outline", &lf);
531 old_hfont = SelectObject(hdc, hfont);
532 otm.otmSize = sizeof(otm);
533 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
534 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
535 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
536
537 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
538 SelectObject(hdc, old_hfont);
539 DeleteObject(hfont);
540
541 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
542 lf.lfHeight = otm.otmEMSquare;
543 lf.lfHeight = -lf.lfHeight;
544 hfont = create_font("outline", &lf);
545 old_hfont = SelectObject(hdc, hfont);
546 otm.otmSize = sizeof(otm);
547 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
548 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
549 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
550 SelectObject(hdc, old_hfont);
551 DeleteObject(hfont);
552
553 height_orig = otm.otmTextMetrics.tmHeight;
554 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
555
556 /* test integer scaling 3x2 */
557 lf.lfHeight = height_orig * 2;
558 lf.lfWidth = lfWidth * 3;
559 hfont = create_font("3x2", &lf);
560 old_hfont = SelectObject(hdc, hfont);
561 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
562 SelectObject(hdc, old_hfont);
563 DeleteObject(hfont);
564
565 /* test integer scaling 3x3 */
566 lf.lfHeight = height_orig * 3;
567 lf.lfWidth = lfWidth * 3;
568 hfont = create_font("3x3", &lf);
569 old_hfont = SelectObject(hdc, hfont);
570 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
571 SelectObject(hdc, old_hfont);
572 DeleteObject(hfont);
573
574 /* test integer scaling 1x1 */
575 lf.lfHeight = height_orig * 1;
576 lf.lfWidth = lfWidth * 1;
577 hfont = create_font("1x1", &lf);
578 old_hfont = SelectObject(hdc, hfont);
579 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
580 SelectObject(hdc, old_hfont);
581 DeleteObject(hfont);
582
583 /* test integer scaling 1x1 */
584 lf.lfHeight = height_orig;
585 lf.lfWidth = 0;
586 hfont = create_font("1x1", &lf);
587 old_hfont = SelectObject(hdc, hfont);
588 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
589
590 /* with an identity matrix */
591 memset(&gm, 0, sizeof(gm));
592 SetLastError(0xdeadbeef);
593 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
594 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
595 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
596 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
597 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598 /* with a custom matrix */
599 memset(&gm, 0, sizeof(gm));
600 SetLastError(0xdeadbeef);
601 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
602 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
604 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
605 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
606
607 /* Test that changing the DC transformation affects only the font
608 * selected on this DC and doesn't affect the same font selected on
609 * another DC.
610 */
611 hdc_2 = CreateCompatibleDC(0);
612 old_hfont_2 = SelectObject(hdc_2, hfont);
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 SetMapMode(hdc, MM_ANISOTROPIC);
616
617 /* font metrics on another DC should be unchanged */
618 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
619
620 /* test restrictions of compatibility mode GM_COMPATIBLE */
621 /* part 1: rescaling only X should not change font scaling on screen.
622 So compressing the X axis by 2 is not done, and this
623 appears as X scaling of 2 that no one requested. */
624 SetWindowExtEx(hdc, 100, 100, NULL);
625 SetViewportExtEx(hdc, 50, 100, NULL);
626 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
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 /* part 2: rescaling only Y should change font scaling.
631 As also X is scaled by a factor of 2, but this is not
632 requested by the DC transformation, we get a scaling factor
633 of 2 in the X coordinate. */
634 SetViewportExtEx(hdc, 100, 200, NULL);
635 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
636 /* font metrics on another DC should be unchanged */
637 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
638
639 /* restore scaling */
640 SetMapMode(hdc, MM_TEXT);
641
642 /* font metrics on another DC should be unchanged */
643 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
644
645 SelectObject(hdc_2, old_hfont_2);
646 DeleteDC(hdc_2);
647
648 if (!SetGraphicsMode(hdc, GM_ADVANCED))
649 {
650 SelectObject(hdc, old_hfont);
651 DeleteObject(hfont);
652 DeleteDC(hdc);
653 skip("GM_ADVANCED is not supported on this platform\n");
654 return;
655 }
656
657 xform.eM11 = 20.0f;
658 xform.eM12 = 0.0f;
659 xform.eM21 = 0.0f;
660 xform.eM22 = 20.0f;
661 xform.eDx = 0.0f;
662 xform.eDy = 0.0f;
663
664 SetLastError(0xdeadbeef);
665 ret = SetWorldTransform(hdc, &xform);
666 ok(ret, "SetWorldTransform error %u\n", GetLastError());
667
668 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
669
670 /* with an identity matrix */
671 memset(&gm, 0, sizeof(gm));
672 SetLastError(0xdeadbeef);
673 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
674 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
675 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
676 pt.x = width_orig; pt.y = 0;
677 LPtoDP(hdc, &pt, 1);
678 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
679 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
680 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
681 /* with a custom matrix */
682 memset(&gm, 0, sizeof(gm));
683 SetLastError(0xdeadbeef);
684 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
685 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
686 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
687 pt.x = width_orig; pt.y = 0;
688 LPtoDP(hdc, &pt, 1);
689 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
690 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
691 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
692
693 SetLastError(0xdeadbeef);
694 ret = SetMapMode(hdc, MM_LOMETRIC);
695 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
696
697 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
698
699 /* with an identity matrix */
700 memset(&gm, 0, sizeof(gm));
701 SetLastError(0xdeadbeef);
702 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
703 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
704 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
705 pt.x = width_orig; pt.y = 0;
706 LPtoDP(hdc, &pt, 1);
707 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
708 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
709 /* with a custom matrix */
710 memset(&gm, 0, sizeof(gm));
711 SetLastError(0xdeadbeef);
712 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
713 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
714 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
715 pt.x = width_orig; pt.y = 0;
716 LPtoDP(hdc, &pt, 1);
717 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
718 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
719
720 SetLastError(0xdeadbeef);
721 ret = SetMapMode(hdc, MM_TEXT);
722 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
723
724 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
725
726 /* with an identity matrix */
727 memset(&gm, 0, sizeof(gm));
728 SetLastError(0xdeadbeef);
729 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
730 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
731 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
732 pt.x = width_orig; pt.y = 0;
733 LPtoDP(hdc, &pt, 1);
734 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
735 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
736 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
737 /* with a custom matrix */
738 memset(&gm, 0, sizeof(gm));
739 SetLastError(0xdeadbeef);
740 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
741 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
742 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
743 pt.x = width_orig; pt.y = 0;
744 LPtoDP(hdc, &pt, 1);
745 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
746 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
747 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
748
749 SelectObject(hdc, old_hfont);
750 DeleteObject(hfont);
751 DeleteDC(hdc);
752 }
753
754 static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
755 {
756 LOGFONTA *lf = (LOGFONTA *)lParam;
757
758 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
759 {
760 *lf = *elf;
761 return 0; /* stop enumeration */
762 }
763 return 1; /* continue enumeration */
764 }
765
766 static BOOL is_CJK(void)
767 {
768 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
769 }
770
771 #define FH_SCALE 0x80000000
772 static void test_bitmap_font_metrics(void)
773 {
774 static const WORD skip_rtl[] = {LANG_ARABIC, LANG_HEBREW, 0};
775 static const struct font_data
776 {
777 const char face_name[LF_FACESIZE];
778 int weight, height, ascent, descent, int_leading, ext_leading;
779 int ave_char_width, max_char_width, dpi;
780 BYTE first_char, last_char, def_char, break_char;
781 DWORD ansi_bitfield;
782 const WORD *skip_lang_id;
783 int scaled_height;
784 } fd[] =
785 {
786 { "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 },
787 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
788 { "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 },
789 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
790 { "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 },
791 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
792 { "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 },
793 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
794 { "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 },
795 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
796
797 { "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 },
798 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
799 { "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 },
800 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
801 { "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 },
802 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
803 { "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 },
804 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
805 { "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 },
806 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
807
808 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
809 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
810 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
811 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
812 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
813 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
814 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
815 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
816 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
817 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
818 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
819 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
820 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
821 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
822 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
823 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
824
825 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
826 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
827 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
828 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
829 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
830 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
831 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
832 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
833 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
834 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
835 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
836 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
837
838 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
839 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
840 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
841 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
842 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
843 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
844 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
845 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
846 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
847 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
848 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
849 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
850 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
851 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
852 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
853 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
854 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
855
856 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
857 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
858 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
859 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
860 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
861 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
862 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
863 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
864 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
865 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
866 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
867
868 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
869 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
870 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
871
872 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
873 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
874 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
875
876 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
877 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
878 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
879
880 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
881 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
882
883 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
884 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
885 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
886 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
887 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
888 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
889 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
890 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
891 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
892 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
893 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, skip_rtl},
894 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
895 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
896 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
897 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, skip_rtl},
898 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
899 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
900 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
901 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, skip_rtl},
902 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
903 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
904
905 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
906 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
907 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
908 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
909 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
910 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
911 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
912 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
913 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
914 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
915 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
916 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
917
918 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
919 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
920 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
921
922 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
923
924 /* FIXME: add "Terminal" */
925 };
926 static const int font_log_pixels[] = { 96, 120 };
927 HDC hdc;
928 LOGFONTA lf;
929 HFONT hfont, old_hfont;
930 TEXTMETRICA tm;
931 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
932 char face_name[LF_FACESIZE];
933 CHARSETINFO csi;
934
935 trace("system language id %04x\n", system_lang_id);
936
937 expected_cs = GetACP();
938 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
939 {
940 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
941 return;
942 }
943 expected_cs = csi.ciCharset;
944 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
945
946 hdc = CreateCompatibleDC(0);
947 ok(hdc != NULL, "failed to create hdc\n");
948
949 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
950 GetDeviceCaps(hdc, LOGPIXELSY));
951
952 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
953 diff = 32768;
954 font_res = 0;
955 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
956 {
957 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
958 if (new_diff < diff)
959 {
960 diff = new_diff;
961 font_res = font_log_pixels[i];
962 }
963 }
964 trace("best font resolution is %d\n", font_res);
965
966 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
967 {
968 int bit, height;
969
970 memset(&lf, 0, sizeof(lf));
971
972 height = fd[i].height & ~FH_SCALE;
973 lf.lfHeight = height;
974 strcpy(lf.lfFaceName, fd[i].face_name);
975
976 for(bit = 0; bit < 32; bit++)
977 {
978 GLYPHMETRICS gm;
979 DWORD fs[2];
980 BOOL bRet;
981
982 fs[0] = 1L << bit;
983 fs[1] = 0;
984 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
985 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
986
987 lf.lfCharSet = csi.ciCharset;
988 ret = EnumFontFamiliesExA(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
989 if (fd[i].height & FH_SCALE)
990 ok(ret, "scaled font height %d should not be enumerated\n", height);
991 else
992 {
993 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
994 {
995 todo_wine_if (ret) /* FIXME: Remove once Wine is fixed */
996 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
997 }
998 }
999 if (ret && !(fd[i].height & FH_SCALE))
1000 continue;
1001
1002 hfont = create_font(lf.lfFaceName, &lf);
1003 old_hfont = SelectObject(hdc, hfont);
1004
1005 SetLastError(0xdeadbeef);
1006 ret = GetTextFaceA(hdc, sizeof(face_name), face_name);
1007 ok(ret, "GetTextFace error %u\n", GetLastError());
1008
1009 if (strcmp(face_name, fd[i].face_name) != 0)
1010 {
1011 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
1012 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
1013 SelectObject(hdc, old_hfont);
1014 DeleteObject(hfont);
1015 continue;
1016 }
1017
1018 memset(&gm, 0, sizeof(gm));
1019 SetLastError(0xdeadbeef);
1020 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
1021 todo_wine {
1022 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
1023 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1024 }
1025
1026 bRet = GetTextMetricsA(hdc, &tm);
1027 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
1028
1029 SetLastError(0xdeadbeef);
1030 ret = GetTextCharset(hdc);
1031 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
1032 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
1033 else
1034 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
1035
1036 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
1037 trace("expected %s, height %d scaled_height %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
1038
1039 if(fd[i].dpi == tm.tmDigitizedAspectX)
1040 {
1041 int skipme = 0;
1042 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1043 if (fd[i].skip_lang_id)
1044 {
1045 int si = 0;
1046 skipme = 0;
1047 while(!skipme && fd[i].skip_lang_id[si])
1048 if (fd[i].skip_lang_id[si++] == system_lang_id)
1049 skipme = 1;
1050 }
1051 if (!skipme)
1052 {
1053 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
1054 if (fd[i].height & FH_SCALE)
1055 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);
1056 else
1057 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);
1058 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
1059 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
1060 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);
1061 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);
1062 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);
1063 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
1064 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
1065 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1066 make default char test fail */
1067 if (tm.tmCharSet == lf.lfCharSet)
1068 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
1069 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
1070 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);
1071
1072 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1073 that make the max width bigger */
1074 if ((strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) && tm.tmDigitizedAspectX == 96)
1075 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);
1076 }
1077 else
1078 skip("Skipping font metrics test for system langid 0x%x\n",
1079 system_lang_id);
1080 }
1081 SelectObject(hdc, old_hfont);
1082 DeleteObject(hfont);
1083 }
1084 }
1085
1086 DeleteDC(hdc);
1087 }
1088
1089 static void test_GdiGetCharDimensions(void)
1090 {
1091 HDC hdc;
1092 TEXTMETRICW tm;
1093 LONG ret;
1094 SIZE size;
1095 LONG avgwidth, height;
1096 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1097
1098 if (!pGdiGetCharDimensions)
1099 {
1100 win_skip("GdiGetCharDimensions not available on this platform\n");
1101 return;
1102 }
1103
1104 hdc = CreateCompatibleDC(NULL);
1105
1106 GetTextExtentPointA(hdc, szAlphabet, strlen(szAlphabet), &size);
1107 avgwidth = ((size.cx / 26) + 1) / 2;
1108
1109 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1110 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1111 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1112
1113 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1114 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1115
1116 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1117 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1118
1119 height = 0;
1120 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1121 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1122 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1123
1124 DeleteDC(hdc);
1125 }
1126
1127 static int CALLBACK create_font_proc(const LOGFONTA *lpelfe,
1128 const TEXTMETRICA *lpntme,
1129 DWORD FontType, LPARAM lParam)
1130 {
1131 if (FontType & TRUETYPE_FONTTYPE)
1132 {
1133 HFONT hfont;
1134
1135 hfont = CreateFontIndirectA(lpelfe);
1136 if (hfont)
1137 {
1138 *(HFONT *)lParam = hfont;
1139 return 0;
1140 }
1141 }
1142
1143 return 1;
1144 }
1145
1146 static void ABCWidths_helper(const char* description, HDC hdc, WORD *glyphs, ABC *base_abci, ABC *base_abcw, ABCFLOAT *base_abcf, INT todo)
1147 {
1148 ABC abc[1];
1149 ABCFLOAT abcf[1];
1150 BOOL ret = FALSE;
1151
1152 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1153 ok(ret, "%s: GetCharABCWidthsI should have succeeded\n", description);
1154 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1155 todo_wine_if (todo)
1156 ok(abc->abcA * base_abci->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1157 todo_wine_if (todo)
1158 ok(abc->abcC * base_abci->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1159
1160 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abc);
1161 ok(ret, "%s: GetCharABCWidthsW should have succeeded\n", description);
1162 ok ((INT)abc->abcB > 0, "%s: abcB should be positive\n", description);
1163 todo_wine_if (todo)
1164 ok(abc->abcA * base_abcw->abcA >= 0, "%s: abcA's sign should be unchanged\n", description);
1165 todo_wine_if (todo)
1166 ok(abc->abcC * base_abcw->abcC >= 0, "%s: abcC's sign should be unchanged\n", description);
1167
1168 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1169 ok(ret, "%s: GetCharABCWidthsFloatW should have succeeded\n", description);
1170 ok (abcf->abcfB > 0.0, "%s: abcfB should be positive\n", description);
1171 todo_wine_if (todo)
1172 ok(abcf->abcfA * base_abcf->abcfA >= 0.0, "%s: abcfA's sign should be unchanged\n", description);
1173 todo_wine_if (todo)
1174 ok(abcf->abcfC * base_abcf->abcfC >= 0.0, "%s: abcfC's sign should be unchanged\n", description);
1175 }
1176
1177 static void test_GetCharABCWidths(void)
1178 {
1179 static const WCHAR str[] = {'i',0};
1180 BOOL ret;
1181 HDC hdc;
1182 LOGFONTA lf;
1183 HFONT hfont;
1184 ABC abc[1];
1185 ABC abcw[1];
1186 ABCFLOAT abcf[1];
1187 WORD glyphs[1];
1188 DWORD nb;
1189 HWND hwnd;
1190 static const struct
1191 {
1192 UINT first;
1193 UINT last;
1194 } range[] =
1195 {
1196 {0xff, 0xff},
1197 {0x100, 0x100},
1198 {0xff, 0x100},
1199 {0x1ff, 0xff00},
1200 {0xffff, 0xffff},
1201 {0x10000, 0x10000},
1202 {0xffff, 0x10000},
1203 {0xffffff, 0xffffff},
1204 {0x1000000, 0x1000000},
1205 {0xffffff, 0x1000000},
1206 {0xffffffff, 0xffffffff},
1207 {0x00, 0xff}
1208 };
1209 static const struct
1210 {
1211 UINT cs;
1212 UINT a;
1213 UINT w;
1214 BOOL r[sizeof range / sizeof range[0]];
1215 } c[] =
1216 {
1217 {ANSI_CHARSET, 0x30, 0x30,
1218 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1219 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1220 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1221 {HANGEUL_CHARSET, 0x8141, 0xac02,
1222 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1223 {GB2312_CHARSET, 0x8141, 0x4e04,
1224 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1225 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1226 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1227 };
1228 UINT i;
1229
1230 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1231 {
1232 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1233 return;
1234 }
1235
1236 memset(&lf, 0, sizeof(lf));
1237 strcpy(lf.lfFaceName, "System");
1238 lf.lfHeight = 20;
1239
1240 hfont = CreateFontIndirectA(&lf);
1241 hdc = GetDC(0);
1242 hfont = SelectObject(hdc, hfont);
1243
1244 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1245 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1246
1247 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1248 ok(!ret, "GetCharABCWidthsI should have failed\n");
1249
1250 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1251 ok(!ret, "GetCharABCWidthsI should have failed\n");
1252
1253 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1254 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1255
1256 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1257 ok(!ret, "GetCharABCWidthsW should have failed\n");
1258
1259 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1260 ok(!ret, "GetCharABCWidthsW should have failed\n");
1261
1262 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1263 ok(!ret, "GetCharABCWidthsW should have failed\n");
1264
1265 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1266 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1267
1268 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1269 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1270
1271 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1272 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1273
1274 hfont = SelectObject(hdc, hfont);
1275 DeleteObject(hfont);
1276
1277 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1278 {
1279 ABC a[2], w[2];
1280 ABC full[256];
1281 UINT code = 0x41, j;
1282
1283 lf.lfFaceName[0] = '\0';
1284 lf.lfCharSet = c[i].cs;
1285 lf.lfPitchAndFamily = 0;
1286 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1287 {
1288 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1289 continue;
1290 }
1291
1292 memset(a, 0, sizeof a);
1293 memset(w, 0, sizeof w);
1294 hfont = SelectObject(hdc, hfont);
1295 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1296 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1297 memcmp(a, w, sizeof a) == 0,
1298 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1299
1300 memset(a, 0xbb, sizeof a);
1301 ret = pGetCharABCWidthsA(hdc, code, code, a);
1302 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1303 memset(full, 0xcc, sizeof full);
1304 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1305 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1306 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1307 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1308
1309 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1310 {
1311 memset(full, 0xdd, sizeof full);
1312 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1313 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1314 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1315 if (ret)
1316 {
1317 UINT last = range[j].last - range[j].first;
1318 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1319 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1320 "GetCharABCWidthsA %x should match. codepage = %u\n",
1321 range[j].last, c[i].cs);
1322 }
1323 }
1324
1325 hfont = SelectObject(hdc, hfont);
1326 DeleteObject(hfont);
1327 }
1328
1329 memset(&lf, 0, sizeof(lf));
1330 strcpy(lf.lfFaceName, "Tahoma");
1331 lf.lfHeight = 200;
1332 hfont = CreateFontIndirectA(&lf);
1333
1334 /* test empty glyph's metrics */
1335 hfont = SelectObject(hdc, hfont);
1336 ret = pGetCharABCWidthsFloatW(hdc, ' ', ' ', abcf);
1337 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1338 ok(abcf[0].abcfB == 1.0, "got %f\n", abcf[0].abcfB);
1339 ret = pGetCharABCWidthsW(hdc, ' ', ' ', abcw);
1340 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1341 ok(abcw[0].abcB == 1, "got %u\n", abcw[0].abcB);
1342
1343 /* 1) prepare unrotated font metrics */
1344 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abcw);
1345 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1346 DeleteObject(SelectObject(hdc, hfont));
1347
1348 /* 2) get rotated font metrics */
1349 lf.lfEscapement = lf.lfOrientation = 900;
1350 hfont = CreateFontIndirectA(&lf);
1351 hfont = SelectObject(hdc, hfont);
1352 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1353 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1354
1355 /* 3) compare ABC results */
1356 ok(match_off_by_1(abcw[0].abcA, abc[0].abcA, FALSE),
1357 "got %d, expected %d (A)\n", abc[0].abcA, abcw[0].abcA);
1358 ok(match_off_by_1(abcw[0].abcB, abc[0].abcB, FALSE),
1359 "got %d, expected %d (B)\n", abc[0].abcB, abcw[0].abcB);
1360 ok(match_off_by_1(abcw[0].abcC, abc[0].abcC, FALSE),
1361 "got %d, expected %d (C)\n", abc[0].abcC, abcw[0].abcC);
1362
1363 DeleteObject(SelectObject(hdc, hfont));
1364 ReleaseDC(NULL, hdc);
1365
1366 trace("ABC sign test for a variety of transforms:\n");
1367 memset(&lf, 0, sizeof(lf));
1368 strcpy(lf.lfFaceName, "Tahoma");
1369 lf.lfHeight = 20;
1370 hfont = CreateFontIndirectA(&lf);
1371 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1372 0, 0, 0, NULL);
1373 hdc = GetDC(hwnd);
1374 SetMapMode(hdc, MM_ANISOTROPIC);
1375 SelectObject(hdc, hfont);
1376
1377 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1378 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1379
1380 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1381 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1382 ret = pGetCharABCWidthsW(hdc, 'i', 'i', abcw);
1383 ok(ret, "GetCharABCWidthsW should have succeeded\n");
1384 ret = pGetCharABCWidthsFloatW(hdc, 'i', 'i', abcf);
1385 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1386
1387 ABCWidths_helper("LTR", hdc, glyphs, abc, abcw, abcf, 0);
1388 SetWindowExtEx(hdc, -1, -1, NULL);
1389 SetGraphicsMode(hdc, GM_COMPATIBLE);
1390 ABCWidths_helper("LTR -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1391 SetGraphicsMode(hdc, GM_ADVANCED);
1392 ABCWidths_helper("LTR -1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1393 SetWindowExtEx(hdc, 1, 1, NULL);
1394 SetGraphicsMode(hdc, GM_COMPATIBLE);
1395 ABCWidths_helper("LTR 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1396 SetGraphicsMode(hdc, GM_ADVANCED);
1397 ABCWidths_helper("LTR 1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1398
1399 ReleaseDC(hwnd, hdc);
1400 DestroyWindow(hwnd);
1401
1402 trace("RTL layout\n");
1403 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
1404 0, 0, 0, NULL);
1405 hdc = GetDC(hwnd);
1406 SetMapMode(hdc, MM_ANISOTROPIC);
1407 SelectObject(hdc, hfont);
1408
1409 ABCWidths_helper("RTL", hdc, glyphs, abc, abcw, abcf, 0);
1410 SetWindowExtEx(hdc, -1, -1, NULL);
1411 SetGraphicsMode(hdc, GM_COMPATIBLE);
1412 ABCWidths_helper("RTL -1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1413 SetGraphicsMode(hdc, GM_ADVANCED);
1414 ABCWidths_helper("RTL -1 advanced", hdc, glyphs, abc, abcw, abcf, 0);
1415 SetWindowExtEx(hdc, 1, 1, NULL);
1416 SetGraphicsMode(hdc, GM_COMPATIBLE);
1417 ABCWidths_helper("RTL 1 compatible", hdc, glyphs, abc, abcw, abcf, 0);
1418 SetGraphicsMode(hdc, GM_ADVANCED);
1419 ABCWidths_helper("RTL 1 advanced", hdc, glyphs, abc, abcw, abcf, 1);
1420
1421 ReleaseDC(hwnd, hdc);
1422 DestroyWindow(hwnd);
1423 DeleteObject(hfont);
1424 }
1425
1426 static void test_text_extents(void)
1427 {
1428 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1429 static const WCHAR emptyW[] = {0};
1430 LPINT extents;
1431 INT i, len, fit1, fit2, extents2[3];
1432 LOGFONTA lf;
1433 TEXTMETRICA tm;
1434 HDC hdc;
1435 HFONT hfont;
1436 SIZE sz;
1437 SIZE sz1, sz2;
1438 BOOL ret;
1439
1440 memset(&lf, 0, sizeof(lf));
1441 strcpy(lf.lfFaceName, "Arial");
1442 lf.lfHeight = 20;
1443
1444 hfont = CreateFontIndirectA(&lf);
1445 hdc = GetDC(0);
1446 hfont = SelectObject(hdc, hfont);
1447 GetTextMetricsA(hdc, &tm);
1448 ret = GetTextExtentPointA(hdc, "o", 1, &sz);
1449 ok(ret, "got %d\n", ret);
1450 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1451
1452 memset(&sz, 0xcc, sizeof(sz));
1453 ret = GetTextExtentPointA(hdc, "o", 0, &sz);
1454 ok(ret, "got %d\n", ret);
1455 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1456
1457 memset(&sz, 0xcc, sizeof(sz));
1458 ret = GetTextExtentPointA(hdc, "", 0, &sz);
1459 ok(ret, "got %d\n", ret);
1460 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1461
1462 SetLastError(0xdeadbeef);
1463 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1464 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1465 {
1466 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1467 hfont = SelectObject(hdc, hfont);
1468 DeleteObject(hfont);
1469 ReleaseDC(0, hdc);
1470 return;
1471 }
1472
1473 memset(&sz, 0xcc, sizeof(sz));
1474 ret = GetTextExtentPointW(hdc, wt, 0, &sz);
1475 ok(ret, "got %d\n", ret);
1476 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1477
1478 memset(&sz, 0xcc, sizeof(sz));
1479 ret = GetTextExtentPointW(hdc, emptyW, 0, &sz);
1480 ok(ret, "got %d\n", ret);
1481 ok(sz.cx == 0 && sz.cy == 0, "cx %d, cy %d\n", sz.cx, sz.cy);
1482
1483 len = lstrlenW(wt);
1484 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1485 extents[0] = 1; /* So that the increasing sequence test will fail
1486 if the extents array is untouched. */
1487 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1488 GetTextExtentPointW(hdc, wt, len, &sz2);
1489 ok(sz1.cy == sz2.cy,
1490 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1491 /* Because of the '\n' in the string GetTextExtentExPoint and
1492 GetTextExtentPoint return different widths under Win2k, but
1493 under WinXP they return the same width. So we don't test that
1494 here. */
1495
1496 for (i = 1; i < len; ++i)
1497 ok(extents[i-1] <= extents[i],
1498 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1499 i);
1500 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1501 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1502 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1503 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1504 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1505 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1506 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1507 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1508 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1509 ok(extents[0] == extents[2] && extents[1] == extents[3],
1510 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1511 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1512 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1513 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1514
1515 /* extents functions fail with -ve counts (the interesting case being -1) */
1516 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1517 ok(ret == FALSE, "got %d\n", ret);
1518 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1519 ok(ret == FALSE, "got %d\n", ret);
1520 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1521 ok(ret == FALSE, "got %d\n", ret);
1522
1523 /* max_extent = 0 succeeds and returns zero */
1524 fit1 = fit2 = -215;
1525 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1526 ok(ret == TRUE ||
1527 broken(ret == FALSE), /* NT4, 2k */
1528 "got %d\n", ret);
1529 ok(fit1 == 0 ||
1530 broken(fit1 == -215), /* NT4, 2k */
1531 "fit = %d\n", fit1);
1532 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1533 ok(ret == TRUE, "got %d\n", ret);
1534 ok(fit2 == 0, "fit = %d\n", fit2);
1535
1536 /* max_extent = -1 is interpreted as a very large width that will
1537 * definitely fit our three characters */
1538 fit1 = fit2 = -215;
1539 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1540 ok(ret == TRUE, "got %d\n", ret);
1541 ok(fit1 == 3, "fit = %d\n", fit1);
1542 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1543 ok(ret == TRUE, "got %d\n", ret);
1544 ok(fit2 == 3, "fit = %d\n", fit2);
1545
1546 /* max_extent = -2 is interpreted similarly, but the Ansi version
1547 * rejects it while the Unicode one accepts it */
1548 fit1 = fit2 = -215;
1549 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1550 ok(ret == FALSE, "got %d\n", ret);
1551 ok(fit1 == -215, "fit = %d\n", fit1);
1552 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1553 ok(ret == TRUE, "got %d\n", ret);
1554 ok(fit2 == 3, "fit = %d\n", fit2);
1555
1556 hfont = SelectObject(hdc, hfont);
1557 DeleteObject(hfont);
1558
1559 /* non-MM_TEXT mapping mode */
1560 lf.lfHeight = 2000;
1561 hfont = CreateFontIndirectA(&lf);
1562 hfont = SelectObject(hdc, hfont);
1563
1564 SetMapMode( hdc, MM_HIMETRIC );
1565 ret = GetTextExtentExPointW(hdc, wt, 3, 0, NULL, extents, &sz);
1566 ok(ret, "got %d\n", ret);
1567 ok(sz.cx == extents[2], "got %d vs %d\n", sz.cx, extents[2]);
1568
1569 ret = GetTextExtentExPointW(hdc, wt, 3, extents[1], &fit1, extents2, &sz2);
1570 ok(ret, "got %d\n", ret);
1571 ok(fit1 == 2, "got %d\n", fit1);
1572 ok(sz2.cx == sz.cx, "got %d vs %d\n", sz2.cx, sz.cx);
1573 for(i = 0; i < 2; i++)
1574 ok(extents2[i] == extents[i], "%d: %d, %d\n", i, extents2[i], extents[i]);
1575
1576 hfont = SelectObject(hdc, hfont);
1577 DeleteObject(hfont);
1578 HeapFree(GetProcessHeap(), 0, extents);
1579 ReleaseDC(NULL, hdc);
1580 }
1581
1582 static void test_GetGlyphIndices(void)
1583 {
1584 HDC hdc;
1585 HFONT hfont;
1586 DWORD charcount;
1587 LOGFONTA lf;
1588 DWORD flags = 0;
1589 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1590 WORD glyphs[(sizeof(testtext)/2)-1];
1591 TEXTMETRICA textm;
1592 HFONT hOldFont;
1593
1594 if (!pGetGlyphIndicesW) {
1595 win_skip("GetGlyphIndicesW not available on platform\n");
1596 return;
1597 }
1598
1599 hdc = GetDC(0);
1600
1601 memset(&lf, 0, sizeof(lf));
1602 strcpy(lf.lfFaceName, "System");
1603 lf.lfHeight = 16;
1604 lf.lfCharSet = ANSI_CHARSET;
1605
1606 hfont = CreateFontIndirectA(&lf);
1607 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1608 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1609 if (textm.tmCharSet == ANSI_CHARSET)
1610 {
1611 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1612 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1613 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1614 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1615 flags = 0;
1616 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1617 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1618 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1619 textm.tmDefaultChar, glyphs[4]);
1620 }
1621 else
1622 /* FIXME: Write tests for non-ANSI charsets. */
1623 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1624
1625 if(!is_font_installed("Tahoma"))
1626 {
1627 skip("Tahoma is not installed so skipping this test\n");
1628 return;
1629 }
1630 memset(&lf, 0, sizeof(lf));
1631 strcpy(lf.lfFaceName, "Tahoma");
1632 lf.lfHeight = 20;
1633
1634 hfont = CreateFontIndirectA(&lf);
1635 hOldFont = SelectObject(hdc, hfont);
1636 ok(GetTextMetricsA(hdc, &textm), "GetTextMetric failed\n");
1637 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1638 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1639 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1640 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1641 flags = 0;
1642 testtext[0] = textm.tmDefaultChar;
1643 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1644 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1645 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1646 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1647 DeleteObject(SelectObject(hdc, hOldFont));
1648 }
1649
1650 static void test_GetKerningPairs(void)
1651 {
1652 static const struct kerning_data
1653 {
1654 const char face_name[LF_FACESIZE];
1655 LONG height;
1656 /* some interesting fields from OUTLINETEXTMETRIC */
1657 LONG tmHeight, tmAscent, tmDescent;
1658 UINT otmEMSquare;
1659 INT otmAscent;
1660 INT otmDescent;
1661 UINT otmLineGap;
1662 UINT otmsCapEmHeight;
1663 UINT otmsXHeight;
1664 INT otmMacAscent;
1665 INT otmMacDescent;
1666 UINT otmMacLineGap;
1667 UINT otmusMinimumPPEM;
1668 /* small subset of kerning pairs to test */
1669 DWORD total_kern_pairs;
1670 const KERNINGPAIR kern_pair[26];
1671 } kd[] =
1672 {
1673 {"Arial", 12, 12, 9, 3,
1674 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1675 26,
1676 {
1677 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1678 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1679 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1680 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1681 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1682 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1683 {933,970,+1},{933,972,-1}
1684 }
1685 },
1686 {"Arial", -34, 39, 32, 7,
1687 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1688 26,
1689 {
1690 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1691 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1692 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1693 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1694 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1695 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1696 {933,970,+2},{933,972,-3}
1697 }
1698 },
1699 { "Arial", 120, 120, 97, 23,
1700 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1701 26,
1702 {
1703 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1704 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1705 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1706 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1707 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1708 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1709 {933,970,+6},{933,972,-10}
1710 }
1711 },
1712 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1713 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1714 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1715 26,
1716 {
1717 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1718 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1719 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1720 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1721 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1722 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1723 {933,970,+54},{933,972,-83}
1724 }
1725 }
1726 #endif
1727 };
1728 LOGFONTA lf;
1729 HFONT hfont, hfont_old;
1730 KERNINGPAIR *kern_pair;
1731 HDC hdc;
1732 DWORD total_kern_pairs, ret, i, n, matches;
1733
1734 hdc = GetDC(0);
1735
1736 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1737 * which may render this test unusable, so we're trying to avoid that.
1738 */
1739 SetLastError(0xdeadbeef);
1740 GetKerningPairsW(hdc, 0, NULL);
1741 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1742 {
1743 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1744 ReleaseDC(0, hdc);
1745 return;
1746 }
1747
1748 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1749 {
1750 OUTLINETEXTMETRICW otm;
1751 UINT uiRet;
1752
1753 if (!is_font_installed(kd[i].face_name))
1754 {
1755 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1756 continue;
1757 }
1758
1759 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1760
1761 memset(&lf, 0, sizeof(lf));
1762 strcpy(lf.lfFaceName, kd[i].face_name);
1763 lf.lfHeight = kd[i].height;
1764 hfont = CreateFontIndirectA(&lf);
1765 ok(hfont != NULL, "failed to create a font, name %s\n", kd[i].face_name);
1766
1767 hfont_old = SelectObject(hdc, hfont);
1768
1769 SetLastError(0xdeadbeef);
1770 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1771 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1772 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1773
1774 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight, FALSE), "expected %d, got %d\n",
1775 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1776 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent, FALSE), "expected %d, got %d\n",
1777 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1778 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1779 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1780
1781 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1782 kd[i].otmEMSquare, otm.otmEMSquare);
1783 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1784 kd[i].otmAscent, otm.otmAscent);
1785 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1786 kd[i].otmDescent, otm.otmDescent);
1787 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1788 kd[i].otmLineGap, otm.otmLineGap);
1789 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1790 kd[i].otmMacDescent, otm.otmMacDescent);
1791 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1792 kd[i].otmMacAscent, otm.otmMacAscent);
1793 todo_wine {
1794 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1795 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1796 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1797 kd[i].otmsXHeight, otm.otmsXHeight);
1798 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1799 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1800 kd[i].otmMacLineGap, otm.otmMacLineGap);
1801 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1802 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1803 }
1804
1805 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1806 trace("total_kern_pairs %u\n", total_kern_pairs);
1807 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1808
1809 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1810 * passes on XP.
1811 */
1812 SetLastError(0xdeadbeef);
1813 ret = GetKerningPairsW(hdc, 0, kern_pair);
1814 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1815 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1816 ok(ret == 0, "got %u, expected 0\n", ret);
1817
1818 ret = GetKerningPairsW(hdc, 100, NULL);
1819 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1820
1821 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1822 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1823
1824 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1825 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1826
1827 matches = 0;
1828
1829 for (n = 0; n < ret; n++)
1830 {
1831 DWORD j;
1832 /* Disabled to limit console spam */
1833 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1834 trace("{'%c','%c',%d},\n",
1835 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1836 for (j = 0; j < kd[i].total_kern_pairs; j++)
1837 {
1838 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1839 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1840 {
1841 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1842 "pair %d:%d got %d, expected %d\n",
1843 kern_pair[n].wFirst, kern_pair[n].wSecond,
1844 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1845 matches++;
1846 }
1847 }
1848 }
1849
1850 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1851 matches, kd[i].total_kern_pairs);
1852
1853 HeapFree(GetProcessHeap(), 0, kern_pair);
1854
1855 SelectObject(hdc, hfont_old);
1856 DeleteObject(hfont);
1857 }
1858
1859 ReleaseDC(0, hdc);
1860 }
1861
1862 struct font_data
1863 {
1864 const char face_name[LF_FACESIZE];
1865 int requested_height;
1866 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1867 BOOL exact;
1868 };
1869
1870 static void test_height( HDC hdc, const struct font_data *fd )
1871 {
1872 LOGFONTA lf;
1873 HFONT hfont, old_hfont;
1874 TEXTMETRICA tm;
1875 INT ret, i;
1876
1877 for (i = 0; fd[i].face_name[0]; i++)
1878 {
1879 if (!is_truetype_font_installed(fd[i].face_name))
1880 {
1881 skip("%s is not installed\n", fd[i].face_name);
1882 continue;
1883 }
1884
1885 memset(&lf, 0, sizeof(lf));
1886 lf.lfHeight = fd[i].requested_height;
1887 lf.lfWeight = fd[i].weight;
1888 strcpy(lf.lfFaceName, fd[i].face_name);
1889
1890 hfont = CreateFontIndirectA(&lf);
1891 ok(hfont != NULL, "failed to create a font, name %s\n", fd[i].face_name);
1892
1893 old_hfont = SelectObject(hdc, hfont);
1894 ret = GetTextMetricsA(hdc, &tm);
1895 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1896 if(fd[i].dpi == tm.tmDigitizedAspectX)
1897 {
1898 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);
1899 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);
1900 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);
1901 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);
1902 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);
1903 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);
1904 }
1905
1906 SelectObject(hdc, old_hfont);
1907 /* force GDI to use new font, otherwise Windows leaks the font reference */
1908 GetTextMetricsA(hdc, &tm);
1909 DeleteObject(hfont);
1910 }
1911 }
1912
1913 static void *find_ttf_table( void *ttf, DWORD size, DWORD tag )
1914 {
1915 WORD i, num_tables = GET_BE_WORD(*((WORD *)ttf + 2));
1916 DWORD *table = (DWORD *)ttf + 3;
1917
1918 for (i = 0; i < num_tables; i++)
1919 {
1920 if (table[0] == tag)
1921 return (BYTE *)ttf + GET_BE_DWORD(table[2]);
1922 table += 4;
1923 }
1924 return NULL;
1925 }
1926
1927 static void test_height_selection_vdmx( HDC hdc )
1928 {
1929 static const struct font_data charset_0[] = /* doesn't use VDMX */
1930 {
1931 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1932 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1933 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1934 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1935 { "wine_vdmx", 14, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1936 { "wine_vdmx", 15, FW_NORMAL, 15, 12, 3, 3, 0, 96, FALSE },
1937 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1938 { "wine_vdmx", 17, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1939 { "wine_vdmx", 18, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1940 { "wine_vdmx", 19, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1941 { "wine_vdmx", 20, FW_NORMAL, 20, 17, 3, 4, 0, 96, FALSE },
1942 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1943 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1944 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1945 { "wine_vdmx", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1946 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1947 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 5, 0, 96, FALSE },
1948 { "wine_vdmx", 27, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1949 { "wine_vdmx", 28, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1950 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1951 { "wine_vdmx", 30, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1952 { "wine_vdmx", 31, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1953 { "wine_vdmx", 32, FW_NORMAL, 32, 27, 5, 6, 0, 96, FALSE },
1954 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
1955 { "wine_vdmx", 64, FW_NORMAL, 64, 53, 11, 11, 0, 96, TRUE },
1956 { "wine_vdmx", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
1957 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1958 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1959 { "wine_vdmx", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
1960 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1961 { "wine_vdmx", -14, FW_NORMAL, 17, 14, 3, 3, 0, 96, TRUE },
1962 { "wine_vdmx", -15, FW_NORMAL, 18, 15, 3, 3, 0, 96, TRUE },
1963 { "wine_vdmx", -16, FW_NORMAL, 19, 16, 3, 3, 0, 96, TRUE },
1964 { "wine_vdmx", -17, FW_NORMAL, 21, 17, 4, 4, 0, 96, TRUE },
1965 { "wine_vdmx", -18, FW_NORMAL, 22, 18, 4, 4, 0, 96, TRUE },
1966 { "wine_vdmx", -19, FW_NORMAL, 23, 19, 4, 4, 0, 96, TRUE },
1967 { "wine_vdmx", -20, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
1968 { "wine_vdmx", -21, FW_NORMAL, 25, 21, 4, 4, 0, 96, TRUE },
1969 { "wine_vdmx", -22, FW_NORMAL, 27, 22, 5, 5, 0, 96, TRUE },
1970 { "wine_vdmx", -23, FW_NORMAL, 28, 23, 5, 5, 0, 96, TRUE },
1971 { "wine_vdmx", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
1972 { "wine_vdmx", -25, FW_NORMAL, 30, 25, 5, 5, 0, 96, TRUE },
1973 { "wine_vdmx", -26, FW_NORMAL, 31, 26, 5, 5, 0, 96, TRUE },
1974 { "wine_vdmx", -27, FW_NORMAL, 33, 27, 6, 6, 0, 96, TRUE },
1975 { "wine_vdmx", -28, FW_NORMAL, 34, 28, 6, 6, 0, 96, TRUE },
1976 { "wine_vdmx", -29, FW_NORMAL, 35, 29, 6, 6, 0, 96, TRUE },
1977 { "wine_vdmx", -30, FW_NORMAL, 36, 30, 6, 6, 0, 96, TRUE },
1978 { "wine_vdmx", -31, FW_NORMAL, 37, 31, 6, 6, 0, 96, TRUE },
1979 { "wine_vdmx", -32, FW_NORMAL, 39, 32, 7, 7, 0, 96, TRUE },
1980 { "wine_vdmx", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
1981 { "wine_vdmx", -64, FW_NORMAL, 77, 64, 13, 13, 0, 96, TRUE },
1982 { "wine_vdmx", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
1983 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1984 };
1985
1986 static const struct font_data charset_1[] = /* Uses VDMX */
1987 {
1988 { "wine_vdmx", 10, FW_NORMAL, 10, 8, 2, 2, 0, 96, TRUE },
1989 { "wine_vdmx", 11, FW_NORMAL, 11, 9, 2, 2, 0, 96, TRUE },
1990 { "wine_vdmx", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
1991 { "wine_vdmx", 13, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1992 { "wine_vdmx", 14, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1993 { "wine_vdmx", 15, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
1994 { "wine_vdmx", 16, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
1995 { "wine_vdmx", 17, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1996 { "wine_vdmx", 18, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
1997 { "wine_vdmx", 19, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
1998 { "wine_vdmx", 20, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
1999 { "wine_vdmx", 21, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2000 { "wine_vdmx", 22, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2001 { "wine_vdmx", 23, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2002 { "wine_vdmx", 24, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2003 { "wine_vdmx", 25, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2004 { "wine_vdmx", 26, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2005 { "wine_vdmx", 27, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2006 { "wine_vdmx", 28, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2007 { "wine_vdmx", 29, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2008 { "wine_vdmx", 30, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2009 { "wine_vdmx", 31, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2010 { "wine_vdmx", 32, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2011 { "wine_vdmx", 48, FW_NORMAL, 48, 40, 8, 10, 0, 96, TRUE },
2012 { "wine_vdmx", 64, FW_NORMAL, 64, 54, 10, 13, 0, 96, TRUE },
2013 { "wine_vdmx", 96, FW_NORMAL, 95, 79, 16, 18, 0, 96, TRUE },
2014 { "wine_vdmx", -10, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2015 { "wine_vdmx", -11, FW_NORMAL, 13, 11, 2, 2, 0, 96, TRUE },
2016 { "wine_vdmx", -12, FW_NORMAL, 16, 13, 3, 4, 0, 96, TRUE },
2017 { "wine_vdmx", -13, FW_NORMAL, 16, 13, 3, 3, 0, 96, TRUE },
2018 { "wine_vdmx", -14, FW_NORMAL, 19, 15, 4, 5, 0, 96, TRUE },
2019 { "wine_vdmx", -15, FW_NORMAL, 20, 16, 4, 5, 0, 96, TRUE },
2020 { "wine_vdmx", -16, FW_NORMAL, 21, 17, 4, 5, 0, 96, TRUE },
2021 { "wine_vdmx", -17, FW_NORMAL, 22, 18, 4, 5, 0, 96, TRUE },
2022 { "wine_vdmx", -18, FW_NORMAL, 23, 19, 4, 5, 0, 96, TRUE },
2023 { "wine_vdmx", -19, FW_NORMAL, 25, 21, 4, 6, 0, 96, TRUE },
2024 { "wine_vdmx", -20, FW_NORMAL, 26, 22, 4, 6, 0, 96, TRUE },
2025 { "wine_vdmx", -21, FW_NORMAL, 27, 23, 4, 6, 0, 96, TRUE },
2026 { "wine_vdmx", -22, FW_NORMAL, 27, 23, 4, 5, 0, 96, TRUE },
2027 { "wine_vdmx", -23, FW_NORMAL, 29, 24, 5, 6, 0, 96, TRUE },
2028 { "wine_vdmx", -24, FW_NORMAL, 32, 26, 6, 8, 0, 96, TRUE },
2029 { "wine_vdmx", -25, FW_NORMAL, 32, 26, 6, 7, 0, 96, TRUE },
2030 { "wine_vdmx", -26, FW_NORMAL, 33, 27, 6, 7, 0, 96, TRUE },
2031 { "wine_vdmx", -27, FW_NORMAL, 35, 29, 6, 8, 0, 96, TRUE },
2032 { "wine_vdmx", -28, FW_NORMAL, 36, 30, 6, 8, 0, 96, TRUE },
2033 { "wine_vdmx", -29, FW_NORMAL, 36, 30, 6, 7, 0, 96, TRUE },
2034 { "wine_vdmx", -30, FW_NORMAL, 38, 32, 6, 8, 0, 96, TRUE },
2035 { "wine_vdmx", -31, FW_NORMAL, 39, 33, 6, 8, 0, 96, TRUE },
2036 { "wine_vdmx", -32, FW_NORMAL, 40, 33, 7, 8, 0, 96, TRUE },
2037 { "wine_vdmx", -48, FW_NORMAL, 60, 50, 10, 12, 0, 96, TRUE },
2038 { "wine_vdmx", -64, FW_NORMAL, 81, 67, 14, 17, 0, 96, TRUE },
2039 { "wine_vdmx", -96, FW_NORMAL, 119, 99, 20, 23, 0, 96, TRUE },
2040 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2041 };
2042
2043 static const struct vdmx_data
2044 {
2045 WORD version;
2046 BYTE bCharSet;
2047 const struct font_data *fd;
2048 } data[] =
2049 {
2050 { 0, 0, charset_0 },
2051 { 0, 1, charset_1 },
2052 { 1, 0, charset_0 },
2053 { 1, 1, charset_1 }
2054 };
2055 int i;
2056 DWORD size, num;
2057 WORD *vdmx_header;
2058 BYTE *ratio_rec;
2059 char ttf_name[MAX_PATH];
2060 void *res, *copy;
2061 BOOL ret;
2062
2063 if (!pAddFontResourceExA)
2064 {
2065 win_skip("AddFontResourceExA unavailable\n");
2066 return;
2067 }
2068
2069 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
2070 {
2071 res = get_res_data( "wine_vdmx.ttf", &size );
2072
2073 copy = HeapAlloc( GetProcessHeap(), 0, size );
2074 memcpy( copy, res, size );
2075 vdmx_header = find_ttf_table( copy, size, MS_MAKE_TAG('V','D','M','X') );
2076 vdmx_header[0] = GET_BE_WORD( data[i].version );
2077 ok( GET_BE_WORD( vdmx_header[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[1] ) );
2078 ok( GET_BE_WORD( vdmx_header[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header[2] ) );
2079 ratio_rec = (BYTE *)&vdmx_header[3];
2080 ratio_rec[0] = data[i].bCharSet;
2081
2082 write_tmp_file( copy, &size, ttf_name );
2083 HeapFree( GetProcessHeap(), 0, copy );
2084
2085 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2086 num = pAddFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2087 if (!num) win_skip("Unable to add ttf font resource\n");
2088 else
2089 {
2090 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2091 test_height( hdc, data[i].fd );
2092 pRemoveFontResourceExA( ttf_name, FR_PRIVATE, 0 );
2093 }
2094 ret = DeleteFileA( ttf_name );
2095 ok(ret || broken(!ret && GetLastError() == ERROR_ACCESS_DENIED),
2096 "DeleteFile error %d\n", GetLastError());
2097 }
2098 }
2099
2100 static void test_height_selection(void)
2101 {
2102 static const struct font_data tahoma[] =
2103 {
2104 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96, TRUE },
2105 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96, TRUE },
2106 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96, TRUE },
2107 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96, TRUE },
2108 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96, TRUE },
2109 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96, TRUE },
2110 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96, TRUE },
2111 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96, TRUE },
2112 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96, FALSE },
2113 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96, TRUE },
2114 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2115 };
2116 HDC hdc = CreateCompatibleDC(0);
2117 ok(hdc != NULL, "failed to create hdc\n");
2118
2119 test_height( hdc, tahoma );
2120 test_height_selection_vdmx( hdc );
2121
2122 DeleteDC(hdc);
2123 }
2124
2125 static UINT get_font_fsselection(LOGFONTA *lf)
2126 {
2127 OUTLINETEXTMETRICA *otm;
2128 HFONT hfont, hfont_old;
2129 DWORD ret, otm_size;
2130 UINT fsSelection;
2131 HDC hdc;
2132
2133 hdc = GetDC(0);
2134 hfont = CreateFontIndirectA(lf);
2135 ok(hfont != NULL, "failed to create a font\n");
2136
2137 hfont_old = SelectObject(hdc, hfont);
2138
2139 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2140 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2141 otm->otmSize = sizeof(*otm);
2142 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2143 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2144 fsSelection = otm->otmfsSelection;
2145 HeapFree(GetProcessHeap(), 0, otm);
2146 SelectObject(hdc, hfont_old);
2147 DeleteObject(hfont);
2148 ReleaseDC(0, hdc);
2149
2150 return fsSelection;
2151 }
2152
2153 static void test_GetOutlineTextMetrics(void)
2154 {
2155 OUTLINETEXTMETRICA *otm;
2156 LOGFONTA lf;
2157 HFONT hfont, hfont_old;
2158 HDC hdc;
2159 DWORD ret, otm_size;
2160 LPSTR unset_ptr;
2161 UINT fsSelection;
2162
2163 /* check fsSelection field with bold simulation */
2164 memset(&lf, 0, sizeof(lf));
2165 strcpy(lf.lfFaceName, "Wingdings");
2166 lf.lfCharSet = SYMBOL_CHARSET;
2167
2168 /* regular face */
2169 fsSelection = get_font_fsselection(&lf);
2170 ok((fsSelection & (1 << 5)) == 0, "got 0x%x\n", fsSelection);
2171
2172 /* face with bold simulation */
2173 lf.lfWeight = FW_BOLD;
2174 fsSelection = get_font_fsselection(&lf);
2175 ok((fsSelection & (1 << 5)) != 0, "got 0x%x\n", fsSelection);
2176
2177 /* check fsSelection field with oblique simulation */
2178 memset(&lf, 0, sizeof(lf));
2179 strcpy(lf.lfFaceName, "Tahoma");
2180 lf.lfHeight = -13;
2181 lf.lfWeight = FW_NORMAL;
2182 lf.lfPitchAndFamily = DEFAULT_PITCH;
2183 lf.lfQuality = PROOF_QUALITY;
2184
2185 /* regular face */
2186 fsSelection = get_font_fsselection(&lf);
2187 ok((fsSelection & 1) == 0, "got 0x%x\n", fsSelection);
2188
2189 lf.lfItalic = 1;
2190 /* face with oblique simulation */
2191 fsSelection = get_font_fsselection(&lf);
2192 ok((fsSelection & 1) == 1, "got 0x%x\n", fsSelection);
2193
2194 if (!is_font_installed("Arial"))
2195 {
2196 skip("Arial is not installed\n");
2197 return;
2198 }
2199
2200 hdc = GetDC(0);
2201
2202 memset(&lf, 0, sizeof(lf));
2203 strcpy(lf.lfFaceName, "Arial");
2204 lf.lfHeight = -13;
2205 lf.lfWeight = FW_NORMAL;
2206 lf.lfPitchAndFamily = DEFAULT_PITCH;
2207 lf.lfQuality = PROOF_QUALITY;
2208 hfont = CreateFontIndirectA(&lf);
2209 ok(hfont != NULL, "failed to create a font\n");
2210
2211 hfont_old = SelectObject(hdc, hfont);
2212 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
2213 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
2214
2215 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
2216
2217 memset(otm, 0xAA, otm_size);
2218 SetLastError(0xdeadbeef);
2219 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
2220 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2221 ok(ret == 1 /* Win9x */ ||
2222 ret == otm->otmSize /* XP*/,
2223 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2224 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2225 {
2226 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2227 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2228 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2229 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
2230 }
2231
2232 memset(otm, 0xAA, otm_size);
2233 SetLastError(0xdeadbeef);
2234 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
2235 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2236 ok(ret == 1 /* Win9x */ ||
2237 ret == otm->otmSize /* XP*/,
2238 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2239 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2240 {
2241 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
2242 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
2243 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
2244 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
2245 }
2246
2247 /* ask about truncated data */
2248 memset(otm, 0xAA, otm_size);
2249 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
2250 SetLastError(0xdeadbeef);
2251 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
2252 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
2253 ok(ret == 1 /* Win9x */ ||
2254 ret == otm->otmSize /* XP*/,
2255 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
2256 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
2257 {
2258 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
2259 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
2260 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
2261 }
2262 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
2263
2264 /* check handling of NULL pointer */
2265 SetLastError(0xdeadbeef);
2266 ret = GetOutlineTextMetricsA(hdc, otm_size, NULL);
2267 ok(ret == otm_size, "expected %u, got %u, error %d\n", otm_size, ret, GetLastError());
2268
2269 HeapFree(GetProcessHeap(), 0, otm);
2270
2271 SelectObject(hdc, hfont_old);
2272 DeleteObject(hfont);
2273
2274 ReleaseDC(0, hdc);
2275 }
2276
2277 static void testJustification(HDC hdc, PCSTR str, RECT *clientArea)
2278 {
2279 INT y,
2280 breakCount,
2281 areaWidth = clientArea->right - clientArea->left,
2282 nErrors = 0, e;
2283 const char *pFirstChar, *pLastChar;
2284 SIZE size;
2285 TEXTMETRICA tm;
2286 struct err
2287 {
2288 const char *start;
2289 int len;
2290 int GetTextExtentExPointWWidth;
2291 } error[20];
2292
2293 GetTextMetricsA(hdc, &tm);
2294 y = clientArea->top;
2295 do {
2296 breakCount = 0;
2297 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
2298 pFirstChar = str;
2299
2300 do {
2301 pLastChar = str;
2302
2303 /* if not at the end of the string, ... */
2304 if (*str == '\0') break;
2305 /* ... add the next word to the current extent */
2306 while (*str != '\0' && *str++ != tm.tmBreakChar);
2307 breakCount++;
2308 SetTextJustification(hdc, 0, 0);
2309 GetTextExtentPoint32A(hdc, pFirstChar, str - pFirstChar - 1, &size);
2310 } while ((int) size.cx < areaWidth);
2311
2312 /* ignore trailing break chars */
2313 breakCount--;
2314 while (*(pLastChar - 1) == tm.tmBreakChar)
2315 {
2316 pLastChar--;
2317 breakCount--;
2318 }
2319
2320 if (*str == '\0' || breakCount <= 0) pLastChar = str;
2321
2322 SetTextJustification(hdc, 0, 0);
2323 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2324
2325 /* do not justify the last extent */
2326 if (*str != '\0' && breakCount > 0)
2327 {
2328 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
2329 GetTextExtentPoint32A(hdc, pFirstChar, pLastChar - pFirstChar, &size);
2330 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
2331 {
2332 error[nErrors].start = pFirstChar;
2333 error[nErrors].len = pLastChar - pFirstChar;
2334 error[nErrors].GetTextExtentExPointWWidth = size.cx;
2335 nErrors++;
2336 }
2337 }
2338
2339 y += size.cy;
2340 str = pLastChar;
2341 } while (*str && y < clientArea->bottom);
2342
2343 for (e = 0; e < nErrors; e++)
2344 {
2345 /* The width returned by GetTextExtentPoint32() is exactly the same
2346 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2347 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
2348 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2349 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
2350 }
2351 }
2352
2353 static void test_SetTextJustification(void)
2354 {
2355 HDC hdc;
2356 RECT clientArea;
2357 LOGFONTA lf;
2358 HFONT hfont;
2359 HWND hwnd;
2360 SIZE size, expect;
2361 int i;
2362 WORD indices[2];
2363 static const char testText[] =
2364 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2365 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2366 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2367 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2368 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2369 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2370 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2371
2372 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
2373 GetClientRect( hwnd, &clientArea );
2374 hdc = GetDC( hwnd );
2375
2376 if (!is_font_installed("Times New Roman"))
2377 {
2378 skip("Times New Roman is not installed\n");
2379 return;
2380 }
2381
2382 memset(&lf, 0, sizeof lf);
2383 lf.lfCharSet = ANSI_CHARSET;
2384 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
2385 lf.lfWeight = FW_DONTCARE;
2386 lf.lfHeight = 20;
2387 lf.lfQuality = DEFAULT_QUALITY;
2388 lstrcpyA(lf.lfFaceName, "Times New Roman");
2389 hfont = create_font("Times New Roman", &lf);
2390 SelectObject(hdc, hfont);
2391
2392 testJustification(hdc, testText, &clientArea);
2393
2394 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
2395 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
2396
2397 SetTextJustification(hdc, 0, 0);
2398 GetTextExtentPoint32A(hdc, " ", 1, &expect);
2399 GetTextExtentPoint32A(hdc, " ", 3, &size);
2400 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
2401 SetTextJustification(hdc, 4, 1);
2402 GetTextExtentPoint32A(hdc, " ", 1, &size);
2403 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
2404 SetTextJustification(hdc, 9, 2);
2405 GetTextExtentPoint32A(hdc, " ", 2, &size);
2406 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
2407 SetTextJustification(hdc, 7, 3);
2408 GetTextExtentPoint32A(hdc, " ", 3, &size);
2409 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2410 SetTextJustification(hdc, 7, 3);
2411 SetTextCharacterExtra(hdc, 2 );
2412 GetTextExtentPoint32A(hdc, " ", 3, &size);
2413 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
2414 SetTextJustification(hdc, 0, 0);
2415 SetTextCharacterExtra(hdc, 0);
2416 size.cx = size.cy = 1234;
2417 GetTextExtentPoint32A(hdc, " ", 0, &size);
2418 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
2419 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
2420 SetTextJustification(hdc, 5, 1);
2421 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
2422 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
2423 SetTextJustification(hdc, 0, 0);
2424
2425 SetMapMode( hdc, MM_ANISOTROPIC );
2426 SetWindowExtEx( hdc, 2, 2, NULL );
2427 GetClientRect( hwnd, &clientArea );
2428 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2429 testJustification(hdc, testText, &clientArea);
2430
2431 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2432 for (i = 0; i < 10; i++)
2433 {
2434 SetTextCharacterExtra(hdc, i);
2435 GetTextExtentPoint32A(hdc, "A", 1, &size);
2436 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2437 }
2438 SetTextCharacterExtra(hdc, 0);
2439 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
2440 for (i = 0; i < 10; i++)
2441 {
2442 SetTextCharacterExtra(hdc, i);
2443 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
2444 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2445 }
2446 SetTextCharacterExtra(hdc, 0);
2447
2448 SetViewportExtEx( hdc, 3, 3, NULL );
2449 GetClientRect( hwnd, &clientArea );
2450 DPtoLP( hdc, (POINT *)&clientArea, 2 );
2451 testJustification(hdc, testText, &clientArea);
2452
2453 GetTextExtentPoint32A(hdc, "A", 1, &expect);
2454 for (i = 0; i < 10; i++)
2455 {
2456 SetTextCharacterExtra(hdc, i);
2457 GetTextExtentPoint32A(hdc, "A", 1, &size);
2458 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
2459 }
2460
2461 done:
2462 DeleteObject(hfont);
2463 ReleaseDC(hwnd, hdc);
2464 DestroyWindow(hwnd);
2465 }
2466
2467 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
2468 {
2469 HDC hdc;
2470 LOGFONTA lf;
2471 HFONT hfont, hfont_old;
2472 CHARSETINFO csi;
2473 FONTSIGNATURE fs;
2474 INT cs;
2475 DWORD i, ret;
2476 char name[64];
2477
2478 assert(count <= 128);
2479
2480 memset(&lf, 0, sizeof(lf));
2481
2482 lf.lfCharSet = charset;
2483 lf.lfHeight = 10;
2484 lstrcpyA(lf.lfFaceName, "Arial");
2485 SetLastError(0xdeadbeef);
2486 hfont = CreateFontIndirectA(&lf);
2487 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2488
2489 hdc = GetDC(0);
2490 hfont_old = SelectObject(hdc, hfont);
2491
2492 cs = GetTextCharsetInfo(hdc, &fs, 0);
2493 ok(cs == charset, "expected %d, got %d\n", charset, cs);
2494
2495 SetLastError(0xdeadbeef);
2496 ret = GetTextFaceA(hdc, sizeof(name), name);
2497 ok(ret, "GetTextFaceA error %u\n", GetLastError());
2498
2499 if (charset == SYMBOL_CHARSET)
2500 {
2501 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
2502 ok(fs.fsCsb[0] & (1u << 31), "symbol encoding should be available\n");
2503 }
2504 else
2505 {
2506 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
2507 ok(!(fs.fsCsb[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2508 }
2509
2510 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
2511 {
2512 trace("Can't find codepage for charset %d\n", cs);
2513 ReleaseDC(0, hdc);
2514 return FALSE;
2515 }
2516 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2517
2518 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2519 {
2520 skip("Font code page %d, looking for code page %d\n",
2521 pGdiGetCodePage(hdc), code_page);
2522 ReleaseDC(0, hdc);
2523 return FALSE;
2524 }
2525
2526 if (unicode)
2527 {
2528 char ansi_buf[128];
2529 WCHAR unicode_buf[128];
2530
2531 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2532
2533 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2534
2535 SetLastError(0xdeadbeef);
2536 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2537 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2538 count, ret, GetLastError());
2539 }
2540 else
2541 {
2542 char ansi_buf[128];
2543
2544 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2545
2546 SetLastError(0xdeadbeef);
2547 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2548 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2549 count, ret, GetLastError());
2550 }
2551
2552 SelectObject(hdc, hfont_old);
2553 DeleteObject(hfont);
2554
2555 ReleaseDC(0, hdc);
2556
2557 return TRUE;
2558 }
2559
2560 static void test_font_charset(void)
2561 {
2562 static struct charset_data
2563 {
2564 INT charset;
2565 UINT code_page;
2566 WORD font_idxA[128], font_idxW[128];
2567 } cd[] =
2568 {
2569 { ANSI_CHARSET, 1252 },
2570 { RUSSIAN_CHARSET, 1251 },
2571 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2572 };
2573 int i;
2574
2575 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2576 {
2577 win_skip("Skipping the font charset test on a Win9x platform\n");
2578 return;
2579 }
2580
2581 if (!is_font_installed("Arial"))
2582 {
2583 skip("Arial is not installed\n");
2584 return;
2585 }
2586
2587 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2588 {
2589 if (cd[i].charset == SYMBOL_CHARSET)
2590 {
2591 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2592 {
2593 skip("Symbol or Wingdings is not installed\n");
2594 break;
2595 }
2596 }
2597 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2598 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2599 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2600 }
2601
2602 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2603 if (i > 2)
2604 {
2605 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2606 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2607 }
2608 else
2609 skip("Symbol or Wingdings is not installed\n");
2610 }
2611
2612 static void test_GdiGetCodePage(void)
2613 {
2614 static const struct _matching_data
2615 {
2616 UINT current_codepage;
2617 LPCSTR lfFaceName;
2618 UCHAR lfCharSet;
2619 UINT expected_codepage;
2620 } matching_data[] = {
2621 {1251, "Arial", ANSI_CHARSET, 1252},
2622 {1251, "Tahoma", ANSI_CHARSET, 1252},
2623
2624 {1252, "Arial", ANSI_CHARSET, 1252},
2625 {1252, "Tahoma", ANSI_CHARSET, 1252},
2626
2627 {1253, "Arial", ANSI_CHARSET, 1252},
2628 {1253, "Tahoma", ANSI_CHARSET, 1252},
2629
2630 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2631 { 932, "Tahoma", ANSI_CHARSET, 1252},
2632 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2633
2634 { 936, "Arial", ANSI_CHARSET, 936},
2635 { 936, "Tahoma", ANSI_CHARSET, 936},
2636 { 936, "Simsun", ANSI_CHARSET, 936},
2637
2638 { 949, "Arial", ANSI_CHARSET, 949},
2639 { 949, "Tahoma", ANSI_CHARSET, 949},
2640 { 949, "Gulim", ANSI_CHARSET, 949},
2641
2642 { 950, "Arial", ANSI_CHARSET, 950},
2643 { 950, "Tahoma", ANSI_CHARSET, 950},
2644 { 950, "PMingLiU", ANSI_CHARSET, 950},
2645 };
2646 HDC hdc;
2647 LOGFONTA lf;
2648 HFONT hfont;
2649 UINT charset, acp;
2650 DWORD codepage;
2651 int i;
2652
2653 if (!pGdiGetCodePage)
2654 {
2655 skip("GdiGetCodePage not available on this platform\n");
2656 return;
2657 }
2658
2659 acp = GetACP();
2660
2661 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2662 {
2663 /* only test data matched current locale codepage */
2664 if (matching_data[i].current_codepage != acp)
2665 continue;
2666
2667 if (!is_font_installed(matching_data[i].lfFaceName))
2668 {
2669 skip("%s is not installed\n", matching_data[i].lfFaceName);
2670 continue;
2671 }
2672
2673 hdc = GetDC(0);
2674
2675 memset(&lf, 0, sizeof(lf));
2676 lf.lfHeight = -16;
2677 lf.lfCharSet = matching_data[i].lfCharSet;
2678 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2679 hfont = CreateFontIndirectA(&lf);
2680 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2681
2682 hfont = SelectObject(hdc, hfont);
2683 charset = GetTextCharset(hdc);
2684 codepage = pGdiGetCodePage(hdc);
2685 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2686 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2687 ok(codepage == matching_data[i].expected_codepage,
2688 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2689
2690 hfont = SelectObject(hdc, hfont);
2691 DeleteObject(hfont);
2692
2693 /* CLIP_DFA_DISABLE turns off the font association */
2694 lf.lfClipPrecision = CLIP_DFA_DISABLE;
2695 hfont = CreateFontIndirectA(&lf);
2696 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2697
2698 hfont = SelectObject(hdc, hfont);
2699 charset = GetTextCharset(hdc);
2700 codepage = pGdiGetCodePage(hdc);
2701 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2702 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage);
2703 ok(codepage == 1252, "GdiGetCodePage returned %d\n", codepage);
2704
2705 hfont = SelectObject(hdc, hfont);
2706 DeleteObject(hfont);
2707
2708 ReleaseDC(NULL, hdc);
2709 }
2710 }
2711
2712 static void test_GetFontUnicodeRanges(void)
2713 {
2714 LOGFONTA lf;
2715 HDC hdc;
2716 HFONT hfont, hfont_old;
2717 DWORD size;
2718 GLYPHSET *gs;
2719 DWORD i;
2720
2721 if (!pGetFontUnicodeRanges)
2722 {
2723 win_skip("GetFontUnicodeRanges not available before W2K\n");
2724 return;
2725 }
2726
2727 memset(&lf, 0, sizeof(lf));
2728 lstrcpyA(lf.lfFaceName, "Arial");
2729 hfont = create_font("Arial", &lf);
2730
2731 hdc = GetDC(0);
2732 hfont_old = SelectObject(hdc, hfont);
2733
2734 size = pGetFontUnicodeRanges(NULL, NULL);
2735 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2736
2737 size = pGetFontUnicodeRanges(hdc, NULL);
2738 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2739
2740 gs = HeapAlloc(GetProcessHeap(), 0, size);
2741
2742 size = pGetFontUnicodeRanges(hdc, gs);
2743 ok(size, "GetFontUnicodeRanges failed\n");
2744
2745 if (0) /* Disabled to limit console spam */
2746 for (i = 0; i < gs->cRanges; i++)
2747 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2748 trace("found %u ranges\n", gs->cRanges);
2749
2750 HeapFree(GetProcessHeap(), 0, gs);
2751
2752 SelectObject(hdc, hfont_old);
2753 DeleteObject(hfont);
2754 ReleaseDC(NULL, hdc);
2755 }
2756
2757 struct enum_font_data
2758 {
2759 int total, size;
2760 LOGFONTA *lf;
2761 };
2762
2763 struct enum_fullname_data
2764 {
2765 int total, size;
2766 ENUMLOGFONTA *elf;
2767 };
2768
2769 struct enum_font_dataW
2770 {
2771 int total, size;
2772 LOGFONTW *lf;
2773 };
2774
2775 static INT CALLBACK arial_enum_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
2776 {
2777 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2778 const NEWTEXTMETRICA *ntm = (const NEWTEXTMETRICA *)tm;
2779
2780 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2781 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2782
2783 if (type != TRUETYPE_FONTTYPE) return 1;
2784
2785 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2786
2787 if (0) /* Disabled to limit console spam */
2788 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2789 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2790 if (efd->total >= efd->size)
2791 {
2792 efd->size = max( (efd->total + 1) * 2, 256 );
2793 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2794 if (!efd->lf) return 0;
2795 }
2796 efd->lf[efd->total++] = *lf;
2797
2798 return 1;
2799 }
2800
2801 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2802 {
2803 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2804 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2805
2806 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2807 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2808
2809 if (type != TRUETYPE_FONTTYPE) return 1;
2810
2811 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2812
2813 if (0) /* Disabled to limit console spam */
2814 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2815 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2816 if (efd->total >= efd->size)
2817 {
2818 efd->size = max( (efd->total + 1) * 2, 256 );
2819 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
2820 if (!efd->lf) return 0;
2821 }
2822 efd->lf[efd->total++] = *lf;
2823
2824 return 1;
2825 }
2826
2827 static void get_charset_stats(struct enum_font_data *efd,
2828 int *ansi_charset, int *symbol_charset,
2829 int *russian_charset)
2830 {
2831 int i;
2832
2833 *ansi_charset = 0;
2834 *symbol_charset = 0;
2835 *russian_charset = 0;
2836
2837 for (i = 0; i < efd->total; i++)
2838 {
2839 switch (efd->lf[i].lfCharSet)
2840 {
2841 case ANSI_CHARSET:
2842 (*ansi_charset)++;
2843 break;
2844 case SYMBOL_CHARSET:
2845 (*symbol_charset)++;
2846 break;
2847 case RUSSIAN_CHARSET:
2848 (*russian_charset)++;
2849 break;
2850 }
2851 }
2852 }
2853
2854 static void get_charset_statsW(struct enum_font_dataW *efd,
2855 int *ansi_charset, int *symbol_charset,
2856 int *russian_charset)
2857 {
2858 int i;
2859
2860 *ansi_charset = 0;
2861 *symbol_charset = 0;
2862 *russian_charset = 0;
2863
2864 for (i = 0; i < efd->total; i++)
2865 {
2866 switch (efd->lf[i].lfCharSet)
2867 {
2868 case ANSI_CHARSET:
2869 (*ansi_charset)++;
2870 break;
2871 case SYMBOL_CHARSET:
2872 (*symbol_charset)++;
2873 break;
2874 case RUSSIAN_CHARSET:
2875 (*russian_charset)++;
2876 break;
2877 }
2878 }
2879 }
2880
2881 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2882 {
2883 struct enum_font_data efd;
2884 struct enum_font_dataW efdw;
2885 LOGFONTA lf;
2886 HDC hdc;
2887 int i, ret, ansi_charset, symbol_charset, russian_charset;
2888
2889 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2890
2891 if (*font_name && !is_truetype_font_installed(font_name))
2892 {
2893 skip("%s is not installed\n", font_name);
2894 return;
2895 }
2896 memset( &efd, 0, sizeof(efd) );
2897 memset( &efdw, 0, sizeof(efdw) );
2898
2899 hdc = GetDC(0);
2900
2901 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2902 * while EnumFontFamiliesEx doesn't.
2903 */
2904 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2905 {
2906 /*
2907 * Use EnumFontFamiliesW since win98 crashes when the
2908 * second parameter is NULL using EnumFontFamilies
2909 */
2910 efdw.total = 0;
2911 SetLastError(0xdeadbeef);
2912 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2913 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2914 if(ret)
2915 {
2916 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2917 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2918 ansi_charset, symbol_charset, russian_charset);
2919 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2920 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2921 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2922 ok(russian_charset > 0 ||
2923 broken(russian_charset == 0), /* NT4 */
2924 "NULL family should enumerate RUSSIAN_CHARSET\n");
2925 }
2926
2927 efdw.total = 0;
2928 SetLastError(0xdeadbeef);
2929 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2930 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2931 if(ret)
2932 {
2933 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2934 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2935 ansi_charset, symbol_charset, russian_charset);
2936 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2937 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2938 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2939 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2940 }
2941 }
2942
2943 efd.total = 0;
2944 SetLastError(0xdeadbeef);
2945 ret = EnumFontFamiliesA(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2946 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2947 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2948 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2949 ansi_charset, symbol_charset, russian_charset,
2950 *font_name ? font_name : "<empty>");
2951 if (*font_name)
2952 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2953 else
2954 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2955 for (i = 0; i < efd.total; i++)
2956 {
2957 /* FIXME: remove completely once Wine is fixed */
2958 todo_wine_if(efd.lf[i].lfCharSet != font_charset)
2959 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2960 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2961 font_name, efd.lf[i].lfFaceName);
2962 }
2963
2964 memset(&lf, 0, sizeof(lf));
2965 lf.lfCharSet = ANSI_CHARSET;
2966 strcpy(lf.lfFaceName, font_name);
2967 efd.total = 0;
2968 SetLastError(0xdeadbeef);
2969 ret = EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2970 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2971 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2972 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2973 ansi_charset, symbol_charset, russian_charset,
2974 *font_name ? font_name : "<empty>");
2975 if (font_charset == SYMBOL_CHARSET)
2976 {
2977 if (*font_name)
2978 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2979 else
2980 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2981 }
2982 else
2983 {
2984 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2985 for (i = 0; i < efd.total; i++)
2986 {
2987 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2988 if (*font_name)
2989 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2990 font_name, efd.lf[i].lfFaceName);
2991 }
2992 }
2993
2994 /* DEFAULT_CHARSET should enumerate all available charsets */
2995 memset(&lf, 0, sizeof(lf));
2996 lf.lfCharSet = DEFAULT_CHARSET;
2997 strcpy(lf.lfFaceName, font_name);
2998 efd.total = 0;
2999 SetLastError(0xdeadbeef);
3000 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3001 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3002 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3003 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
3004 ansi_charset, symbol_charset, russian_charset,
3005 *font_name ? font_name : "<empty>");
3006 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
3007 for (i = 0; i < efd.total; i++)
3008 {
3009 if (*font_name)
3010 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3011 font_name, efd.lf[i].lfFaceName);
3012 }
3013 if (*font_name)
3014 {
3015 switch (font_charset)
3016 {
3017 case ANSI_CHARSET:
3018 ok(ansi_charset > 0,
3019 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3020 ok(!symbol_charset,
3021 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
3022 ok(russian_charset > 0,
3023 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3024 break;
3025 case SYMBOL_CHARSET:
3026 ok(!ansi_charset,
3027 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
3028 ok(symbol_charset,
3029 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3030 ok(!russian_charset,
3031 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
3032 break;
3033 case DEFAULT_CHARSET:
3034 ok(ansi_charset > 0,
3035 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
3036 ok(symbol_charset > 0,
3037 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
3038 ok(russian_charset > 0,
3039 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
3040 break;
3041 }
3042 }
3043 else
3044 {
3045 ok(ansi_charset > 0,
3046 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3047 ok(symbol_charset > 0,
3048 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3049 ok(russian_charset > 0,
3050 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3051 }
3052
3053 memset(&lf, 0, sizeof(lf));
3054 lf.lfCharSet = SYMBOL_CHARSET;
3055 strcpy(lf.lfFaceName, font_name);
3056 efd.total = 0;
3057 SetLastError(0xdeadbeef);
3058 EnumFontFamiliesExA(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
3059 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
3060 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
3061 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
3062 ansi_charset, symbol_charset, russian_charset,
3063 *font_name ? font_name : "<empty>");
3064 if (*font_name && font_charset == ANSI_CHARSET)
3065 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
3066 else
3067 {
3068 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
3069 for (i = 0; i < efd.total; i++)
3070 {
3071 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
3072 if (*font_name)
3073 ok(!strcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
3074 font_name, efd.lf[i].lfFaceName);
3075 }
3076
3077 ok(!ansi_charset,
3078 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3079 ok(symbol_charset > 0,
3080 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3081 ok(!russian_charset,
3082 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
3083 }
3084
3085 ReleaseDC(0, hdc);
3086
3087 heap_free( efd.lf );
3088 heap_free( efdw.lf );
3089 }
3090
3091 static INT CALLBACK enum_multi_charset_font_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM lParam)
3092 {
3093 const NEWTEXTMETRICEXA *ntm = (const NEWTEXTMETRICEXA *)tm;
3094 LOGFONTA *target = (LOGFONTA *)lParam;
3095 const DWORD valid_bits = 0x003f01ff;
3096 CHARSETINFO csi;
3097 DWORD fs;
3098
3099 if (type != TRUETYPE_FONTTYPE) return TRUE;
3100
3101 if (TranslateCharsetInfo(ULongToPtr(target->lfCharSet), &csi, TCI_SRCCHARSET)) {
3102 fs = ntm->ntmFontSig.fsCsb[0] & valid_bits;
3103 if ((fs & csi.fs.fsCsb[0]) && (fs & ~csi.fs.fsCsb[0]) && (fs & FS_LATIN1)) {
3104 *target = *lf;
3105 return FALSE;
3106 }
3107 }
3108
3109 return TRUE;
3110 }
3111
3112 static INT CALLBACK enum_font_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3113 {
3114 struct enum_font_data *efd = (struct enum_font_data *)lParam;
3115
3116 if (type != TRUETYPE_FONTTYPE) return 1;
3117
3118 if (efd->total >= efd->size)
3119 {
3120 efd->size = max( (efd->total + 1) * 2, 256 );
3121 efd->lf = heap_realloc( efd->lf, efd->size * sizeof(*efd->lf) );
3122 if (!efd->lf) return 0;
3123 }
3124 efd->lf[efd->total++] = *lf;
3125
3126 return 1;
3127 }
3128
3129 static INT CALLBACK enum_fullname_data_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
3130 {
3131 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
3132
3133 if (type != TRUETYPE_FONTTYPE) return 1;
3134
3135 if (efnd->total >= efnd->size)
3136 {
3137 efnd->size = max( (efnd->total + 1) * 2, 256 );
3138 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
3139 if (!efnd->elf) return 0;
3140 }
3141 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
3142
3143 return 1;
3144 }
3145
3146 static void test_EnumFontFamiliesEx_default_charset(void)
3147 {
3148 struct enum_font_data efd;
3149 LOGFONTA target, enum_font;
3150 UINT acp;
3151 HDC hdc;
3152 CHARSETINFO csi;
3153
3154 acp = GetACP();
3155 if (!TranslateCharsetInfo(ULongToPtr(acp), &csi, TCI_SRCCODEPAGE)) {
3156 skip("TranslateCharsetInfo failed for code page %u.\n", acp);
3157 return;
3158 }
3159
3160 hdc = GetDC(0);
3161 memset(&enum_font, 0, sizeof(enum_font));
3162 enum_font.lfCharSet = csi.ciCharset;
3163 target.lfFaceName[0] = '\0';
3164 target.lfCharSet = csi.ciCharset;
3165 EnumFontFamiliesExA(hdc, &enum_font, enum_multi_charset_font_proc, (LPARAM)&target, 0);
3166 if (target.lfFaceName[0] == '\0') {
3167 skip("suitable font isn't found for charset %d.\n", enum_font.lfCharSet);
3168 return;
3169 }
3170 if (acp == 874 || acp == 1255 || acp == 1256) {
3171 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3172 target.lfCharSet = ANSI_CHARSET;
3173 }
3174
3175 memset(&efd, 0, sizeof(efd));
3176 memset(&enum_font, 0, sizeof(enum_font));
3177 strcpy(enum_font.lfFaceName, target.lfFaceName);
3178 enum_font.lfCharSet = DEFAULT_CHARSET;
3179 EnumFontFamiliesExA(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
3180 ReleaseDC(0, hdc);
3181
3182 trace("'%s' has %d charsets.\n", target.lfFaceName, efd.total);
3183 if (efd.total < 2)
3184 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd.total);
3185 else
3186 ok(efd.lf[0].lfCharSet == target.lfCharSet,
3187 "(%s) got charset %d expected %d\n",
3188 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, target.lfCharSet);
3189
3190 heap_free(efd.lf);
3191 return;
3192 }
3193
3194 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
3195 {
3196 HFONT hfont, hfont_prev;
3197 DWORD ret;
3198 GLYPHMETRICS gm1, gm2;
3199 LOGFONTA lf2 = *lf;
3200 WORD idx;
3201
3202 if(!pGetGlyphIndicesA)
3203 return;
3204
3205 /* negative widths are handled just as positive ones */
3206 lf2.lfWidth = -lf->lfWidth;
3207
3208 SetLastError(0xdeadbeef);
3209 hfont = CreateFontIndirectA(lf);
3210 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3211 check_font("original", lf, hfont);
3212
3213 hfont_prev = SelectObject(hdc, hfont);
3214
3215 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
3216 if (ret == GDI_ERROR || idx == 0xffff)
3217 {
3218 SelectObject(hdc, hfont_prev);
3219 DeleteObject(hfont);
3220 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
3221 return;
3222 }
3223
3224 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3225 memset(&gm1, 0xab, sizeof(gm1));
3226 SetLastError(0xdeadbeef);
3227 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
3228 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3229
3230 SelectObject(hdc, hfont_prev);
3231 DeleteObject(hfont);
3232
3233 SetLastError(0xdeadbeef);
3234 hfont = CreateFontIndirectA(&lf2);
3235 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3236 check_font("negative width", &lf2, hfont);
3237
3238 hfont_prev = SelectObject(hdc, hfont);
3239
3240 memset(&gm2, 0xbb, sizeof(gm2));
3241 SetLastError(0xdeadbeef);
3242 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
3243 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
3244
3245 SelectObject(hdc, hfont_prev);
3246 DeleteObject(hfont);
3247
3248 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
3249 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
3250 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
3251 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
3252 gm1.gmCellIncX == gm2.gmCellIncX &&
3253 gm1.gmCellIncY == gm2.gmCellIncY,
3254 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3255 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
3256 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
3257 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
3258 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
3259 }
3260
3261 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3262 #include "pshpack2.h"
3263 typedef struct
3264 {
3265 USHORT version;
3266 SHORT xAvgCharWidth;
3267 USHORT usWeightClass;
3268 USHORT usWidthClass;
3269 SHORT fsType;
3270 SHORT ySubscriptXSize;
3271 SHORT ySubscriptYSize;
3272 SHORT ySubscriptXOffset;
3273 SHORT ySubscriptYOffset;
3274 SHORT ySuperscriptXSize;
3275 SHORT ySuperscriptYSize;
3276 SHORT ySuperscriptXOffset;
3277 SHORT ySuperscriptYOffset;
3278 SHORT yStrikeoutSize;
3279 SHORT yStrikeoutPosition;
3280 SHORT sFamilyClass;
3281 PANOSE panose;
3282 ULONG ulUnicodeRange1;
3283 ULONG ulUnicodeRange2;
3284 ULONG ulUnicodeRange3;
3285 ULONG ulUnicodeRange4;
3286 CHAR achVendID[4];
3287 USHORT fsSelection;
3288 USHORT usFirstCharIndex;
3289 USHORT usLastCharIndex;
3290 /* According to the Apple spec, original version didn't have the below fields,
3291 * version numbers were taken from the OpenType spec.
3292 */
3293 /* version 0 (TrueType 1.5) */
3294 USHORT sTypoAscender;
3295 USHORT sTypoDescender;
3296 USHORT sTypoLineGap;
3297 USHORT usWinAscent;
3298 USHORT usWinDescent;
3299 /* version 1 (TrueType 1.66) */
3300 ULONG ulCodePageRange1;
3301 ULONG ulCodePageRange2;
3302 /* version 2 (OpenType 1.2) */
3303 SHORT sxHeight;
3304 SHORT sCapHeight;
3305 USHORT usDefaultChar;
3306 USHORT usBreakChar;
3307 USHORT usMaxContext;
3308 /* version 4 (OpenType 1.6) */
3309 USHORT usLowerOpticalPointSize;
3310 USHORT usUpperOpticalPointSize;
3311 } TT_OS2_V4;
3312 #include "poppack.h"
3313
3314 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3315
3316 typedef struct
3317 {
3318 USHORT version;
3319 USHORT num_tables;
3320 } cmap_header;
3321
3322 typedef struct
3323 {
3324 USHORT plat_id;
3325 USHORT enc_id;
3326 ULONG offset;
3327 } cmap_encoding_record;
3328
3329 typedef struct
3330 {
3331 USHORT format;
3332 USHORT length;
3333 USHORT language;
3334
3335 BYTE glyph_ids[256];
3336 } cmap_format_0;
3337
3338 typedef struct
3339 {
3340 USHORT format;
3341 USHORT length;
3342 USHORT language;
3343
3344 USHORT seg_countx2;
3345 USHORT search_range;
3346 USHORT entry_selector;
3347 USHORT range_shift;
3348
3349 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3350 /* Then follows:
3351 USHORT pad;
3352 USHORT start_count[seg_countx2 / 2];
3353 USHORT id_delta[seg_countx2 / 2];
3354 USHORT id_range_offset[seg_countx2 / 2];
3355 USHORT glyph_ids[];
3356 */
3357 } cmap_format_4;
3358
3359 typedef struct
3360 {
3361 USHORT end_count;
3362 USHORT start_count;
3363 USHORT id_delta;
3364 USHORT id_range_offset;
3365 } cmap_format_4_seg;
3366
3367 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V4 *os2, WORD family, const char *name)
3368 {
3369 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
3370 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
3371 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3372 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
3373 os2->panose.bWeight, os2->panose.bProportion);
3374 }
3375
3376 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
3377 {
3378 int i;
3379 cmap_format_0 *cmap = (cmap_format_0*)ptr;
3380
3381 *first = 256;
3382
3383 for(i = 0; i < 256; i++)
3384 {
3385 if(cmap->glyph_ids[i] == 0) continue;
3386 *last = i;
3387 if(*first == 256) *first = i;
3388 }
3389 if(*first == 256) return FALSE;
3390 return TRUE;
3391 }
3392
3393 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
3394 {
3395 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
3396 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
3397 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
3398 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
3399 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
3400 }
3401
3402 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
3403 {
3404 int i;
3405 cmap_format_4 *cmap = (cmap_format_4*)ptr;
3406 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
3407
3408 *first = 0x10000;
3409
3410 for(i = 0; i < seg_count; i++)
3411 {
3412 cmap_format_4_seg seg;
3413
3414 get_seg4(cmap, i, &seg);
3415
3416 if(seg.start_count > 0xfffe) break;
3417
3418 if(*first == 0x10000) *first = seg.start_count;
3419
3420 *last = min(seg.end_count, 0xfffe);
3421 }
3422
3423 if(*first == 0x10000) return FALSE;
3424 return TRUE;
3425 }
3426
3427 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
3428 {
3429 USHORT i;
3430 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
3431
3432 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
3433 {
3434 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
3435 return (BYTE *)header + GET_BE_DWORD(record->offset);
3436 record++;
3437 }
3438 return NULL;
3439 }
3440
3441 typedef enum
3442 {
3443 cmap_none,
3444 cmap_ms_unicode,
3445 cmap_ms_symbol
3446 } cmap_type;
3447
3448 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
3449 {
3450 LONG size, ret;
3451 cmap_header *header;
3452 void *cmap;
3453 BOOL r = FALSE;
3454 WORD format;
3455
3456 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
3457 ok(size != GDI_ERROR, "no cmap table found\n");
3458 if(size == GDI_ERROR) return FALSE;
3459
3460 header = HeapAlloc(GetProcessHeap(), 0, size);
3461 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
3462 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3463 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
3464
3465 cmap = get_cmap(header, 3, 1);
3466 if(cmap)
3467 *cmap_type = cmap_ms_unicode;
3468 else
3469 {
3470 cmap = get_cmap(header, 3, 0);
3471 if(cmap) *cmap_type = cmap_ms_symbol;
3472 }
3473 if(!cmap)
3474 {
3475 *cmap_type = cmap_none;
3476 goto end;
3477 }
3478
3479 format = GET_BE_WORD(*(WORD *)cmap);
3480 switch(format)
3481 {
3482 case 0:
3483 r = get_first_last_from_cmap0(cmap, first, last);
3484 break;
3485 case 4:
3486 r = get_first_last_from_cmap4(cmap, first, last, size);
3487 break;
3488 default:
3489 trace("unhandled cmap format %d\n", format);
3490 break;
3491 }
3492
3493 end:
3494 HeapFree(GetProcessHeap(), 0, header);
3495 return r;
3496 }
3497
3498 #define TT_PLATFORM_APPLE_UNICODE 0
3499 #define TT_PLATFORM_MACINTOSH 1
3500 #define TT_PLATFORM_MICROSOFT 3
3501 #define TT_APPLE_ID_DEFAULT 0
3502 #define TT_APPLE_ID_ISO_10646 2
3503 #define TT_APPLE_ID_UNICODE_2_0 3
3504 #define TT_MS_ID_SYMBOL_CS 0
3505 #define TT_MS_ID_UNICODE_CS 1
3506 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3507 #define TT_NAME_ID_FONT_FAMILY 1
3508 #define TT_NAME_ID_FONT_SUBFAMILY 2
3509 #define TT_NAME_ID_UNIQUE_ID 3
3510 #define TT_NAME_ID_FULL_NAME 4
3511 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3512
3513 typedef struct sfnt_name
3514 {
3515 USHORT platform_id;
3516 USHORT encoding_id;
3517 USHORT language_id;
3518 USHORT name_id;
3519 USHORT length;
3520 USHORT offset;
3521 } sfnt_name;
3522
3523 static const LANGID mac_langid_table[] =
3524 {
3525 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
3526 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
3527 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
3528 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
3529 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
3530 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
3531 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
3532 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
3533 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
3534 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
3535 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
3536 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
3537 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
3538 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
3539 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
3540 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
3541 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
3542 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
3543 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
3544 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3545 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
3546 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
3547 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
3548 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
3549 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
3550 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
3551 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
3552 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
3553 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
3554 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
3555 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
3556 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
3557 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
3558 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3559 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
3560 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
3561 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
3562 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
3563 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
3564 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
3565 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
3566 0, /* TT_MAC_LANGID_YIDDISH */
3567 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
3568 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
3569 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
3570 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
3571 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
3572 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
3573 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
3574 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
3575 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3576 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
3577 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
3578 0, /* TT_MAC_LANGID_MOLDAVIAN */
3579 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
3580 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
3581 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
3582 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
3583 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3584 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
3585 0, /* TT_MAC_LANGID_KURDISH */
3586 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
3587 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
3588 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
3589 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
3590 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
3591 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
3592 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
3593 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
3594 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
3595 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
3596 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
3597 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
3598 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
3599 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
3600 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
3601 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
3602 0, /* TT_MAC_LANGID_BURMESE */
3603 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
3604 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
3605 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
3606 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
3607 0, /* TT_MAC_LANGID_TAGALOG */
3608 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3609 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3610 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
3611 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
3612 0, /* TT_MAC_LANGID_GALLA */
3613 0, /* TT_MAC_LANGID_SOMALI */
3614 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
3615 0, /* TT_MAC_LANGID_RUANDA */
3616 0, /* TT_MAC_LANGID_RUNDI */
3617 0, /* TT_MAC_LANGID_CHEWA */
3618 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
3619 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
3620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3621 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3622 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
3623 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
3624 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
3625 0, /* TT_MAC_LANGID_LATIN */
3626 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
3627 0, /* TT_MAC_LANGID_GUARANI */
3628 0, /* TT_MAC_LANGID_AYMARA */
3629 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
3630 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
3631 0, /* TT_MAC_LANGID_DZONGKHA */
3632 0, /* TT_MAC_LANGID_JAVANESE */
3633 0, /* TT_MAC_LANGID_SUNDANESE */
3634 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
3635 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
3636 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
3637 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
3638 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3639 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
3640 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
3641 0, /* TT_MAC_LANGID_TONGAN */
3642 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3643 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
3644 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3645 };
3646
3647 static inline WORD get_mac_code_page( const sfnt_name *name )
3648 {
3649 if (GET_BE_WORD(name->encoding_id) == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
3650 return 10000 + GET_BE_WORD(name->encoding_id);
3651 }
3652
3653 static int match_name_table_language( const sfnt_name *name, LANGID lang )
3654 {
3655 LANGID name_lang;
3656 int res = 0;
3657
3658 switch (GET_BE_WORD(name->platform_id))
3659 {
3660 case TT_PLATFORM_MICROSOFT:
3661 res += 5; /* prefer the Microsoft name */
3662 switch (GET_BE_WORD(name->encoding_id))
3663 {
3664 case TT_MS_ID_UNICODE_CS:
3665 case TT_MS_ID_SYMBOL_CS:
3666 name_lang = GET_BE_WORD(name->language_id);
3667 break;
3668 default:
3669 return 0;
3670 }
3671 break;
3672 case TT_PLATFORM_MACINTOSH:
3673 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
3674 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3675 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3676 break;
3677 case TT_PLATFORM_APPLE_UNICODE:
3678 res += 2; /* prefer Unicode encodings */
3679 switch (GET_BE_WORD(name->encoding_id))
3680 {
3681 case TT_APPLE_ID_DEFAULT:
3682 case TT_APPLE_ID_ISO_10646:
3683 case TT_APPLE_ID_UNICODE_2_0:
3684 if (GET_BE_WORD(name->language_id) >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
3685 name_lang = mac_langid_table[GET_BE_WORD(name->language_id)];
3686 break;
3687 default:
3688 return 0;
3689 }
3690 break;
3691 default:
3692 return 0;
3693 }
3694 if (name_lang == lang) res += 30;
3695 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
3696 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
3697 return res;
3698 }
3699
3700 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
3701 {
3702 struct sfnt_name_header
3703 {
3704 USHORT format;
3705 USHORT number_of_record;
3706 USHORT storage_offset;
3707 } *header;
3708 sfnt_name *entry;
3709 BOOL r = FALSE;
3710 LONG size, offset, length;
3711 LONG c, ret;
3712 WCHAR *name;
3713 BYTE *data;
3714 USHORT i;
3715 int res, best_lang = 0, best_index = -1;
3716
3717 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
3718 ok(size != GDI_ERROR, "no name table found\n");
3719 if(size == GDI_ERROR) return FALSE;
3720
3721 data = HeapAlloc(GetProcessHeap(), 0, size);
3722 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
3723 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3724
3725 header = (void *)data;
3726 header->format = GET_BE_WORD(header->format);
3727 header->number_of_record = GET_BE_WORD(header->number_of_record);
3728 header->storage_offset = GET_BE_WORD(header->storage_offset);
3729 if (header->format != 0)
3730 {
3731 trace("got format %u\n", header->format);
3732 goto out;
3733 }
3734 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3735 {
3736 trace("number records out of range: %d\n", header->number_of_record);
3737 goto out;
3738 }
3739 if (header->storage_offset >= size)
3740 {
3741 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3742 goto out;
3743 }
3744
3745 entry = (void *)&header[1];
3746 for (i = 0; i < header->number_of_record; i++)
3747 {
3748 if (GET_BE_WORD(entry[i].name_id) != name_id) continue;
3749 res = match_name_table_language( &entry[i], language_id);
3750 if (res > best_lang)
3751 {
3752 best_lang = res;
3753 best_index = i;
3754 }
3755 }
3756
3757 offset = header->storage_offset + GET_BE_WORD(entry[best_index].offset);
3758 length = GET_BE_WORD(entry[best_index].length);
3759 if (offset + length > size)
3760 {
3761 trace("entry %d is out of range\n", best_index);
3762 goto out;
3763 }
3764 if (length >= out_size)
3765 {
3766 trace("buffer too small for entry %d\n", best_index);
3767 goto out;
3768 }
3769
3770 name = (WCHAR *)(data + offset);
3771 for (c = 0; c < length / 2; c++)
3772 out_buf[c] = GET_BE_WORD(name[c]);
3773 out_buf[c] = 0;
3774
3775 r = TRUE;
3776
3777 out:
3778 HeapFree(GetProcessHeap(), 0, data);
3779 return r;
3780 }
3781
3782 static void test_text_metrics(const LOGFONTA *lf, const NEWTEXTMETRICA *ntm)
3783 {
3784 HDC hdc;
3785 HFONT hfont, hfont_old;
3786 TEXTMETRICA tmA;
3787 TT_OS2_V4 tt_os2;
3788 LONG size, ret;
3789 const char *font_name = lf->lfFaceName;
3790 DWORD cmap_first = 0, cmap_last = 0;
3791 UINT ascent, descent, cell_height;
3792 cmap_type cmap_type;
3793 BOOL sys_lang_non_english;
3794
3795 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3796 hdc = GetDC(0);
3797
3798 SetLastError(0xdeadbeef);
3799 hfont = CreateFontIndirectA(lf);
3800 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3801
3802 hfont_old = SelectObject(hdc, hfont);
3803
3804 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3805 if (size == GDI_ERROR)
3806 {
3807 trace("OS/2 chunk was not found\n");
3808 goto end_of_test;
3809 }
3810 if (size > sizeof(tt_os2))
3811 {
3812 trace("got too large OS/2 chunk of size %u\n", size);
3813 size = sizeof(tt_os2);
3814 }
3815
3816 memset(&tt_os2, 0, sizeof(tt_os2));
3817 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3818 ok(ret >= TT_OS2_V0_SIZE && ret <= size, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE,
3819 size, ret);
3820
3821 SetLastError(0xdeadbeef);
3822 ret = GetTextMetricsA(hdc, &tmA);
3823 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3824
3825 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3826 {
3827 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name);
3828 }
3829 else
3830 {
3831 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3832 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3833 UINT os2_first_char, os2_last_char, default_char, break_char;
3834 USHORT version;
3835 TEXTMETRICW tmW;
3836
3837 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3838 descent = abs((SHORT)GET_BE_WORD(tt_os2.usWinDescent));
3839 cell_height = ascent + descent;
3840 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3841 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3842
3843 version = GET_BE_WORD(tt_os2.version);
3844
3845 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3846 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3847 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3848 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3849
3850 if (winetest_debug > 1)
3851 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3852 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3853 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3854
3855 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3856 {
3857 expect_first_W = 0;
3858 switch(GetACP())
3859 {
3860 case 1255: /* Hebrew */
3861 expect_last_W = 0xf896;
3862 break;
3863 case 1257: /* Baltic */
3864 expect_last_W = 0xf8fd;
3865 break;
3866 default:
3867 expect_last_W = 0xf0ff;
3868 }
3869 expect_break_W = 0x20;
3870 expect_default_W = expect_break_W - 1;
3871 expect_first_A = 0x1e;
3872 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3873 }
3874 else
3875 {
3876 expect_first_W = cmap_first;
3877 expect_last_W = cmap_last;
3878 if(os2_first_char <= 1)
3879 expect_break_W = os2_first_char + 2;
3880 else if(os2_first_char > 0xff)
3881 expect_break_W = 0x20;
3882 else
3883 expect_break_W = os2_first_char;
3884 expect_default_W = expect_break_W - 1;
3885 expect_first_A = expect_default_W - 1;
3886 expect_last_A = min(expect_last_W, 0xff);
3887 }
3888 expect_break_A = expect_break_W;
3889 expect_default_A = expect_default_W;
3890
3891 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3892 todo_wine_if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3893 ok(tmA.tmFirstChar == expect_first_A ||
3894 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3895 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3896 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3897 ok(tmA.tmLastChar == expect_last_A ||
3898 tmA.tmLastChar == 0xff /* win9x */,
3899 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3900 else
3901 skip("tmLastChar is DBCS lead byte\n");
3902 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3903 font_name, tmA.tmBreakChar, expect_break_A);
3904 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3905 "A: tmDefaultChar for %s got %02x expected %02x\n",
3906 font_name, tmA.tmDefaultChar, expect_default_A);
3907
3908
3909 SetLastError(0xdeadbeef);
3910 ret = GetTextMetricsW(hdc, &tmW);
3911 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3912 "GetTextMetricsW error %u\n", GetLastError());
3913 if (ret)
3914 {
3915 /* Wine uses the os2 first char */
3916 todo_wine_if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3917 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3918 font_name, tmW.tmFirstChar, expect_first_W);
3919
3920 /* Wine uses the os2 last char */
3921 todo_wine_if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3922 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3923 font_name, tmW.tmLastChar, expect_last_W);
3924 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3925 font_name, tmW.tmBreakChar, expect_break_W);
3926 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3927 "W: tmDefaultChar for %s got %02x expected %02x\n",
3928 font_name, tmW.tmDefaultChar, expect_default_W);
3929
3930 /* Test the aspect ratio while we have tmW */
3931 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3932 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3933 tmW.tmDigitizedAspectX, ret);
3934 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3935 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3936 tmW.tmDigitizedAspectX, ret);
3937 }
3938 }
3939
3940 /* test FF_ values */
3941 switch(tt_os2.panose.bFamilyType)
3942 {
3943 case PAN_ANY:
3944 case PAN_NO_FIT:
3945 case PAN_FAMILY_TEXT_DISPLAY:
3946 case PAN_FAMILY_PICTORIAL:
3947 default:
3948 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3949 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3950 {
3951 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3952 break;
3953 }
3954 switch(tt_os2.panose.bSerifStyle)
3955 {
3956 case PAN_ANY:
3957 case PAN_NO_FIT:
3958 default:
3959 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3960 break;
3961
3962 case PAN_SERIF_COVE:
3963 case PAN_SERIF_OBTUSE_COVE:
3964 case PAN_SERIF_SQUARE_COVE:
3965 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3966 case PAN_SERIF_SQUARE:
3967 case PAN_SERIF_THIN:
3968 case PAN_SERIF_BONE:
3969 case PAN_SERIF_EXAGGERATED:
3970 case PAN_SERIF_TRIANGLE:
3971 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3972 break;
3973
3974 case PAN_SERIF_NORMAL_SANS:
3975 case PAN_SERIF_OBTUSE_SANS:
3976 case PAN_SERIF_PERP_SANS:
3977 case PAN_SERIF_FLARED:
3978 case PAN_SERIF_ROUNDED:
3979 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3980 break;
3981 }
3982 break;
3983
3984 case PAN_FAMILY_SCRIPT:
3985 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3986 break;
3987
3988 case PAN_FAMILY_DECORATIVE:
3989 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3990 break;
3991 }
3992
3993 test_negative_width(hdc, lf);
3994
3995 end_of_test:
3996 SelectObject(hdc, hfont_old);
3997 DeleteObject(hfont);
3998
3999 ReleaseDC(0, hdc);
4000 }
4001
4002 static INT CALLBACK enum_truetype_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
4003 {
4004 INT *enumed = (INT *)lParam;
4005
4006 if (type == TRUETYPE_FONTTYPE)
4007 {
4008 (*enumed)++;
4009 test_text_metrics(lf, (const NEWTEXTMETRICA *)ntm);
4010 }
4011 return 1;
4012 }
4013
4014 static void test_GetTextMetrics(void)
4015 {
4016 LOGFONTA lf;
4017 HDC hdc;
4018 INT enumed;
4019
4020 /* Report only once */
4021 if(!pGetGlyphIndicesA)
4022 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
4023
4024 hdc = GetDC(0);
4025
4026 memset(&lf, 0, sizeof(lf));
4027 lf.lfCharSet = DEFAULT_CHARSET;
4028 enumed = 0;
4029 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
4030 trace("Tested metrics of %d truetype fonts\n", enumed);
4031
4032 ReleaseDC(0, hdc);
4033 }
4034
4035 static void test_nonexistent_font(void)
4036 {
4037 static const struct
4038 {
4039 const char *name;
4040 int charset;
4041 } font_subst[] =
4042 {
4043 { "Times New Roman Baltic", 186 },
4044 { "Times New Roman CE", 238 },
4045 { "Times New Roman CYR", 204 },
4046 { "Times New Roman Greek", 161 },
4047 { "Times New Roman TUR", 162 }
4048 };
4049 static const struct
4050 {
4051 const char *name;
4052 int charset;
4053 } shell_subst[] =
4054 {
4055 { "MS Shell Dlg", 186 },
4056 { "MS Shell Dlg", 238 },
4057 { "MS Shell Dlg", 204 },
4058 { "MS Shell Dlg", 161 },
4059 { "MS Shell Dlg", 162 }
4060 };
4061 LOGFONTA lf;
4062 HDC hdc;
4063 HFONT hfont;
4064 CHARSETINFO csi;
4065 INT cs, expected_cs, i, ret;
4066 char buf[LF_FACESIZE];
4067
4068 expected_cs = GetACP();
4069 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
4070 {
4071 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
4072 return;
4073 }
4074 expected_cs = csi.ciCharset;
4075 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
4076
4077 hdc = CreateCompatibleDC(0);
4078
4079 for (i = 0; i < sizeof(shell_subst)/sizeof(shell_subst[0]); i++)
4080 {
4081 ret = is_font_installed(shell_subst[i].name);
4082 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4083 ret = is_truetype_font_installed(shell_subst[i].name);
4084 ok(ret || broken(!ret) /* win2000 */, "%s should be enumerated\n", shell_subst[i].name);
4085
4086 memset(&lf, 0, sizeof(lf));
4087 lf.lfHeight = -13;
4088 lf.lfWeight = FW_REGULAR;
4089 strcpy(lf.lfFaceName, shell_subst[i].name);
4090 hfont = CreateFontIndirectA(&lf);
4091 hfont = SelectObject(hdc, hfont);
4092 GetTextFaceA(hdc, sizeof(buf), buf);
4093 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4094 cs = GetTextCharset(hdc);
4095 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, shell_subst[i].name);
4096
4097 DeleteObject(SelectObject(hdc, hfont));
4098
4099 memset(&lf, 0, sizeof(lf));
4100 lf.lfHeight = -13;
4101 lf.lfWeight = FW_DONTCARE;
4102 strcpy(lf.lfFaceName, shell_subst[i].name);
4103 hfont = CreateFontIndirectA(&lf);
4104 hfont = SelectObject(hdc, hfont);
4105 GetTextFaceA(hdc, sizeof(buf), buf);
4106 ok(!lstrcmpiA(buf, shell_subst[i].name), "expected %s, got %s\n", shell_subst[i].name, buf);
4107 cs = GetTextCharset(hdc);
4108 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, shell_subst[i].name);
4109 DeleteObject(SelectObject(hdc, hfont));
4110 }
4111
4112 if (!is_truetype_font_installed("Arial") ||
4113 !is_truetype_font_installed("Times New Roman"))
4114 {
4115 DeleteDC(hdc);
4116 skip("Arial or Times New Roman not installed\n");
4117 return;
4118 }
4119
4120 memset(&lf, 0, sizeof(lf));
4121 lf.lfHeight = 100;
4122 lf.lfWeight = FW_REGULAR;
4123 lf.lfCharSet = ANSI_CHARSET;
4124 lf.lfPitchAndFamily = FF_SWISS;
4125 strcpy(lf.lfFaceName, "Nonexistent font");
4126 hfont = CreateFontIndirectA(&lf);
4127 hfont = SelectObject(hdc, hfont);
4128 GetTextFaceA(hdc, sizeof(buf), buf);
4129 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
4130 cs = GetTextCharset(hdc);
4131 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4132 DeleteObject(SelectObject(hdc, hfont));
4133
4134 memset(&lf, 0, sizeof(lf));
4135 lf.lfHeight = -13;
4136 lf.lfWeight = FW_DONTCARE;
4137 strcpy(lf.lfFaceName, "Nonexistent font");
4138 hfont = CreateFontIndirectA(&lf);
4139 hfont = SelectObject(hdc, hfont);
4140 GetTextFaceA(hdc, sizeof(buf), buf);
4141 todo_wine /* Wine uses Arial for all substitutions */
4142 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
4143 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
4144 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4145 "Got %s\n", buf);
4146 cs = GetTextCharset(hdc);
4147 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
4148 DeleteObject(SelectObject(hdc, hfont));
4149
4150 memset(&lf, 0, sizeof(lf));
4151 lf.lfHeight = -13;
4152 lf.lfWeight = FW_REGULAR;
4153 strcpy(lf.lfFaceName, "Nonexistent font");
4154 hfont = CreateFontIndirectA(&lf);
4155 hfont = SelectObject(hdc, hfont);
4156 GetTextFaceA(hdc, sizeof(buf), buf);
4157 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4158 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
4159 cs = GetTextCharset(hdc);
4160 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4161 DeleteObject(SelectObject(hdc, hfont));
4162
4163 memset(&lf, 0, sizeof(lf));
4164 lf.lfHeight = -13;
4165 lf.lfWeight = FW_DONTCARE;
4166 strcpy(lf.lfFaceName, "Times New Roman");
4167 hfont = CreateFontIndirectA(&lf);
4168 hfont = SelectObject(hdc, hfont);
4169 GetTextFaceA(hdc, sizeof(buf), buf);
4170 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
4171 cs = GetTextCharset(hdc);
4172 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
4173 DeleteObject(SelectObject(hdc, hfont));
4174
4175 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
4176 {
4177 ret = is_font_installed(font_subst[i].name);
4178 todo_wine
4179 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4180 "%s should be enumerated\n", font_subst[i].name);
4181 ret = is_truetype_font_installed(font_subst[i].name);
4182 todo_wine
4183 ok(ret || broken(!ret && !i) /* win2000 doesn't have Times New Roman Baltic substitution */,
4184 "%s should be enumerated\n", font_subst[i].name);
4185
4186 memset(&lf, 0, sizeof(lf));
4187 lf.lfHeight = -13;
4188 lf.lfWeight = FW_REGULAR;
4189 strcpy(lf.lfFaceName, font_subst[i].name);
4190 hfont = CreateFontIndirectA(&lf);
4191 hfont = SelectObject(hdc, hfont);
4192 cs = GetTextCharset(hdc);
4193 if (font_subst[i].charset == expected_cs)
4194 {
4195 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4196 GetTextFaceA(hdc, sizeof(buf), buf);
4197 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
4198 }
4199 else
4200 {
4201 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
4202 GetTextFaceA(hdc, sizeof(buf), buf);
4203 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
4204 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
4205 }
4206 DeleteObject(SelectObject(hdc, hfont));
4207
4208 memset(&lf, 0, sizeof(lf));
4209 lf.lfHeight = -13;
4210 lf.lfWeight = FW_DONTCARE;
4211 strcpy(lf.lfFaceName, font_subst[i].name);
4212 hfont = CreateFontIndirectA(&lf);
4213 hfont = SelectObject(hdc, hfont);
4214 GetTextFaceA(hdc, sizeof(buf), buf);
4215 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
4216 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
4217 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
4218 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
4219 "got %s for font %s\n", buf, font_subst[i].name);
4220 cs = GetTextCharset(hdc);
4221 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
4222 DeleteObject(SelectObject(hdc, hfont));
4223 }
4224
4225 DeleteDC(hdc);
4226 }
4227
4228 static void test_RealizationInfo(void)
4229 {
4230 struct font_realization_info {
4231 DWORD size;
4232 DWORD flags;
4233 DWORD cache_num;
4234 DWORD instance_id;
4235 DWORD unk;
4236 WORD face_index;
4237 WORD simulations;
4238 };
4239
4240 struct realization_info_t
4241 {
4242 DWORD flags;
4243 DWORD cache_num;
4244 DWORD instance_id;
4245 };
4246
4247 HDC hdc;
4248 DWORD info[4], info2[10];
4249 BOOL r, have_file = FALSE;
4250 HFONT hfont, hfont_old;
4251 LOGFONTA lf;
4252 DWORD needed, read;
4253 HANDLE h;
4254 BYTE file[16], data[14];
4255 struct file_info
4256 {
4257 FILETIME time;
4258 LARGE_INTEGER size;
4259 WCHAR path[MAX_PATH];
4260 } file_info;
4261 FILETIME time;
4262 LARGE_INTEGER size;
4263
4264 if(!pGdiRealizationInfo)
4265 {
4266 win_skip("GdiRealizationInfo not available\n");
4267 return;
4268 }
4269
4270 hdc = GetDC(0);
4271
4272 memset(info, 0xcc, sizeof(info));
4273 r = pGdiRealizationInfo(hdc, info);
4274 ok(r != 0, "ret 0\n");
4275 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
4276 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4277
4278 if (!is_truetype_font_installed("Tahoma"))
4279 {
4280 skip("skipping GdiRealizationInfo with truetype font\n");
4281 goto end;
4282 }
4283
4284 memset(&lf, 0, sizeof(lf));
4285 strcpy(lf.lfFaceName, "Tahoma");
4286 lf.lfHeight = 20;
4287 lf.lfWeight = FW_BOLD;
4288 lf.lfItalic = 1;
4289 hfont = CreateFontIndirectA(&lf);
4290 hfont_old = SelectObject(hdc, hfont);
4291
4292 memset(info, 0xcc, sizeof(info));
4293 r = pGdiRealizationInfo(hdc, info);
4294 ok(r != 0, "ret 0\n");
4295 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
4296 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4297
4298 if (pGetFontRealizationInfo)
4299 {
4300 struct font_realization_info *fri = (struct font_realization_info*)info2;
4301 struct realization_info_t *ri = (struct realization_info_t*)info;
4302
4303 /* The first DWORD represents a struct size. On a
4304 newly rebooted system setting this to < 16 results
4305 in GetFontRealizationInfo failing. However there
4306 appears to be some caching going on which results
4307 in calls after a successful call also succeeding even
4308 if the size < 16. This means we can't reliably test
4309 this behaviour. */
4310
4311 memset(info2, 0xcc, sizeof(info2));
4312 info2[0] = 16;
4313 r = pGetFontRealizationInfo(hdc, info2);
4314 ok(r != 0, "ret 0\n");
4315 /* We may get the '24' version here if that has been previously
4316 requested. */
4317 ok(fri->size == 16 || fri->size == 24, "got %d\n", info2[0]);
4318 ok(fri->flags == ri->flags, "flags mismatch\n");
4319 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4320 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4321 ok(info2[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2[6]);
4322
4323 memset(info2, 0xcc, sizeof(info2));
4324 info2[0] = 28;
4325 r = pGetFontRealizationInfo(hdc, info2);
4326 ok(r == FALSE, "got %d\n", r);
4327
4328 memset(info2, 0xcc, sizeof(info2));
4329 info2[0] = 24;
4330 r = pGetFontRealizationInfo(hdc, info2);
4331 ok(r != 0, "ret 0\n");
4332 ok(fri->size == 24, "got %d\n", fri->size);
4333 ok(fri->flags == ri->flags, "flags mismatch\n");
4334 ok(fri->cache_num == ri->cache_num, "cache_num mismatch\n");
4335 ok(fri->instance_id == ri->instance_id, "instance id mismatch\n");
4336 ok(fri->simulations == 0x2, "got simulations flags 0x%04x\n", fri->simulations);
4337 ok(fri->face_index == 0, "got wrong face index %u\n", fri->face_index);
4338 ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4339
4340 /* Test GetFontFileInfo() */
4341 /* invalid font id */
4342 SetLastError(0xdeadbeef);
4343 r = pGetFontFileInfo(0xabababab, 0, &file_info, sizeof(file_info), &needed);
4344 ok(r == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "ret %d gle %d\n", r, GetLastError());
4345
4346 needed = 0;
4347 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed);
4348 ok(r != 0 || GetLastError() == ERROR_NOACCESS, "ret %d gle %d\n", r, GetLastError());
4349
4350 if (r)
4351 {
4352 ok(needed > 0 && needed < sizeof(file_info), "got needed size %u\n", needed);
4353
4354 h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
4355 ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError());
4356
4357 GetFileTime(h, NULL, NULL, &time);
4358 ok(!CompareFileTime(&file_info.time, &time), "time mismatch\n");
4359 GetFileSizeEx(h, &size);
4360 ok(file_info.size.QuadPart == size.QuadPart, "size mismatch\n");
4361
4362 /* Read first 16 bytes from the file */
4363 ReadFile(h, file, sizeof(file), &read, NULL);
4364 CloseHandle(h);
4365 have_file = TRUE;
4366
4367 /* shorter buffer */
4368 SetLastError(0xdeadbeef);
4369 r = pGetFontFileInfo(fri->instance_id, 0, &file_info, needed - 1, &needed);
4370 ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %d\n", r, GetLastError());
4371 }
4372
4373 if (pGetFontFileData) {
4374 /* Get bytes 2 - 16 using GetFontFileData */
4375 r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data));
4376 ok(r != 0, "ret 0 gle %d\n", GetLastError());
4377
4378 if (have_file)
4379 ok(!memcmp(data, file + 2, sizeof(data)), "mismatch\n");
4380 else
4381 win_skip("GetFontFileInfo() failed, skipping\n");
4382 }
4383 }
4384
4385 DeleteObject(SelectObject(hdc, hfont_old));
4386
4387 end:
4388 ReleaseDC(0, hdc);
4389 }
4390
4391 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4392 the nul in the count of characters copied when the face name buffer is not
4393 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4394 always includes it. */
4395 static void test_GetTextFace(void)
4396 {
4397 static const char faceA[] = "Tahoma";
4398 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
4399 LOGFONTA fA = {0};
4400 LOGFONTW fW = {0};
4401 char bufA[LF_FACESIZE];
4402 WCHAR bufW[LF_FACESIZE];
4403 HFONT f, g;
4404 HDC dc;
4405 int n;
4406
4407 if(!is_font_installed("Tahoma"))
4408 {
4409 skip("Tahoma is not installed so skipping this test\n");
4410 return;
4411 }
4412
4413 /* 'A' case. */
4414 memcpy(fA.lfFaceName, faceA, sizeof faceA);
4415 f = CreateFontIndirectA(&fA);
4416 ok(f != NULL, "CreateFontIndirectA failed\n");
4417
4418 dc = GetDC(NULL);
4419 g = SelectObject(dc, f);
4420 n = GetTextFaceA(dc, sizeof bufA, bufA);
4421 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
4422 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
4423
4424 /* Play with the count arg. */
4425 bufA[0] = 'x';
4426 n = GetTextFaceA(dc, 0, bufA);
4427 ok(n == 0, "GetTextFaceA returned %d\n", n);
4428 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4429
4430 bufA[0] = 'x';
4431 n = GetTextFaceA(dc, 1, bufA);
4432 ok(n == 0, "GetTextFaceA returned %d\n", n);
4433 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
4434
4435 bufA[0] = 'x'; bufA[1] = 'y';
4436 n = GetTextFaceA(dc, 2, bufA);
4437 ok(n == 1, "GetTextFaceA returned %d\n", n);
4438 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
4439
4440 n = GetTextFaceA(dc, 0, NULL);
4441 ok(n == sizeof faceA ||
4442 broken(n == 0), /* win98, winMe */
4443 "GetTextFaceA returned %d\n", n);
4444
4445 DeleteObject(SelectObject(dc, g));
4446 ReleaseDC(NULL, dc);
4447
4448 /* 'W' case. */
4449 memcpy(fW.lfFaceName, faceW, sizeof faceW);
4450 SetLastError(0xdeadbeef);
4451 f = CreateFontIndirectW(&fW);
4452 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
4453 {
4454 win_skip("CreateFontIndirectW is not implemented\n");
4455 return;
4456 }
4457 ok(f != NULL, "CreateFontIndirectW failed\n");
4458
4459 dc = GetDC(NULL);
4460 g = SelectObject(dc, f);
4461 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
4462 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4463 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
4464
4465 /* Play with the count arg. */
4466 bufW[0] = 'x';
4467 n = GetTextFaceW(dc, 0, bufW);
4468 ok(n == 0, "GetTextFaceW returned %d\n", n);
4469 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4470
4471 bufW[0] = 'x';
4472 n = GetTextFaceW(dc, 1, bufW);
4473 ok(n == 1, "GetTextFaceW returned %d\n", n);
4474 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
4475
4476 bufW[0] = 'x'; bufW[1] = 'y';
4477 n = GetTextFaceW(dc, 2, bufW);
4478 ok(n == 2, "GetTextFaceW returned %d\n", n);
4479 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
4480
4481 n = GetTextFaceW(dc, 0, NULL);
4482 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
4483
4484 DeleteObject(SelectObject(dc, g));
4485 ReleaseDC(NULL, dc);
4486 }
4487
4488 static void test_orientation(void)
4489 {
4490 static const char test_str[11] = "Test String";
4491 HDC hdc;
4492 LOGFONTA lf;
4493 HFONT hfont, old_hfont;
4494 SIZE size;
4495
4496 if (!is_truetype_font_installed("Arial"))
4497 {
4498 skip("Arial is not installed\n");
4499 return;
4500 }
4501
4502 hdc = CreateCompatibleDC(0);
4503 memset(&lf, 0, sizeof(lf));
4504 lstrcpyA(lf.lfFaceName, "Arial");
4505 lf.lfHeight = 72;
4506 lf.lfOrientation = lf.lfEscapement = 900;
4507 hfont = create_font("orientation", &lf);
4508 old_hfont = SelectObject(hdc, hfont);
4509 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
4510 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
4511 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
4512 SelectObject(hdc, old_hfont);
4513 DeleteObject(hfont);
4514 DeleteDC(hdc);
4515 }
4516
4517 static void test_oemcharset(void)
4518 {
4519 HDC hdc;
4520 LOGFONTA lf, clf;
4521 HFONT hfont, old_hfont;
4522 int charset;
4523
4524 hdc = CreateCompatibleDC(0);
4525 ZeroMemory(&lf, sizeof(lf));
4526 lf.lfHeight = 12;
4527 lf.lfCharSet = OEM_CHARSET;
4528 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
4529 lstrcpyA(lf.lfFaceName, "Terminal");
4530 hfont = CreateFontIndirectA(&lf);
4531 old_hfont = SelectObject(hdc, hfont);
4532 charset = GetTextCharset(hdc);
4533 todo_wine
4534 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
4535 hfont = SelectObject(hdc, old_hfont);
4536 GetObjectA(hfont, sizeof(clf), &clf);
4537 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
4538 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
4539 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
4540 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
4541 DeleteObject(hfont);
4542 DeleteDC(hdc);
4543 }
4544
4545 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONTA *lpelfe,
4546 const TEXTMETRICA *lpntme,
4547 DWORD FontType, LPARAM lParam)
4548 {
4549 const NEWTEXTMETRICEXA *lpntmex = (const NEWTEXTMETRICEXA *)lpntme;
4550 CHARSETINFO csi;
4551 LOGFONTA lf = *lpelfe;
4552 HFONT hfont;
4553 DWORD found_subset;
4554
4555 /* skip bitmap, proportional or vertical font */
4556 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
4557 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
4558 lf.lfFaceName[0] == '@')
4559 return 1;
4560
4561 /* skip linked font */
4562 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
4563 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
4564 return 1;
4565
4566 /* skip linked font, like SimSun-ExtB */
4567 switch (lpelfe->lfCharSet) {
4568 case SHIFTJIS_CHARSET:
4569 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 17); /* Hiragana */
4570 break;
4571 case GB2312_CHARSET:
4572 case CHINESEBIG5_CHARSET:
4573 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 16); /* CJK Symbols And Punctuation */
4574 break;
4575 case HANGEUL_CHARSET:
4576 found_subset = lpntmex->ntmFontSig.fsUsb[1] & (1 << 24); /* Hangul Syllables */
4577 break;
4578 default:
4579 found_subset = lpntmex->ntmFontSig.fsUsb[0] & (1 << 0); /* Basic Latin */
4580 break;
4581 }
4582 if (!found_subset)
4583 return 1;
4584
4585 /* test with an odd height */
4586 lf.lfHeight = -19;
4587 lf.lfWidth = 0;
4588 hfont = CreateFontIndirectA(&lf);
4589 if (hfont)
4590 {
4591 *(HFONT *)lParam = hfont;
4592 return 0;
4593 }
4594 return 1;
4595 }
4596
4597 static void test_GetGlyphOutline(void)
4598 {
4599 HDC hdc;
4600 GLYPHMETRICS gm, gm2;
4601 LOGFONTA lf;
4602 HFONT hfont, old_hfont;
4603 INT ret, ret2;
4604 const UINT fmt[] = { GGO_METRICS, GGO_BITMAP, GGO_GRAY2_BITMAP,
4605 GGO_GRAY4_BITMAP, GGO_GRAY8_BITMAP };
4606 static const struct
4607 {
4608 UINT cs;
4609 UINT a;
4610 UINT w;
4611 } c[] =
4612 {
4613 {ANSI_CHARSET, 0x30, 0x30},
4614 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
4615 {HANGEUL_CHARSET, 0x8141, 0xac02},
4616 {GB2312_CHARSET, 0x8141, 0x4e04},
4617 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
4618 };
4619 UINT i;
4620
4621 if (!is_truetype_font_installed("Tahoma"))
4622 {
4623 skip("Tahoma is not installed\n");
4624 return;
4625 }
4626
4627 hdc = CreateCompatibleDC(0);
4628 memset(&lf, 0, sizeof(lf));
4629 lf.lfHeight = 72;
4630 lstrcpyA(lf.lfFaceName, "Tahoma");
4631 SetLastError(0xdeadbeef);
4632 hfont = CreateFontIndirectA(&lf);
4633 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4634 old_hfont = SelectObject(hdc, hfont);
4635
4636 memset(&gm, 0, sizeof(gm));
4637 SetLastError(0xdeadbeef);
4638 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4639 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4640
4641 memset(&gm, 0, sizeof(gm));
4642 SetLastError(0xdeadbeef);
4643 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4644 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
4645 ok(GetLastError() == 0xdeadbeef ||
4646 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
4647 "expected 0xdeadbeef, got %u\n", GetLastError());
4648
4649 memset(&gm, 0, sizeof(gm));
4650 SetLastError(0xdeadbeef);
4651 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
4652 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4653 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
4654
4655 memset(&gm, 0, sizeof(gm));
4656 SetLastError(0xdeadbeef);
4657 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
4658 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4659 {
4660 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
4661 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4662 }
4663
4664 /* test for needed buffer size request on space char */
4665 memset(&gm, 0, sizeof(gm));
4666 SetLastError(0xdeadbeef);
4667 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
4668 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4669 {
4670 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4671 ok(gm.gmBlackBoxX == 1, "Expected 1, got %u\n", gm.gmBlackBoxX);
4672 ok(gm.gmBlackBoxY == 1, "Expected 1, got %u\n", gm.gmBlackBoxY);
4673 }
4674
4675 /* requesting buffer size for space char + error */
4676 memset(&gm, 0, sizeof(gm));
4677 SetLastError(0xdeadbeef);
4678 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
4679 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4680 {
4681 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
4682 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4683 ok(gm.gmBlackBoxX == 0, "Expected 0, got %u\n", gm.gmBlackBoxX);
4684 ok(gm.gmBlackBoxY == 0, "Expected 0, got %u\n", gm.gmBlackBoxY);
4685 }
4686
4687 /* test GetGlyphOutline with a buffer too small */
4688 SetLastError(0xdeadbeef);
4689 ret = GetGlyphOutlineA(hdc, 'A', GGO_NATIVE, &gm, sizeof(i), &i, &mat);
4690 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4691 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4692
4693 for (i = 0; i < sizeof(fmt) / sizeof(fmt[0]); ++i)
4694 {
4695 DWORD dummy;
4696
4697 memset(&gm, 0xab, sizeof(gm));
4698 SetLastError(0xdeadbeef);
4699 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, NULL, &mat);
4700 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4701 {
4702 if (fmt[i] == GGO_METRICS)
4703 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4704 else
4705 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4706 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4707 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4708 }
4709
4710 memset(&gm, 0xab, sizeof(gm));
4711 SetLastError(0xdeadbeef);
4712 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, 0, &dummy, &mat);
4713 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4714 {
4715 if (fmt[i] == GGO_METRICS)
4716 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4717 else
4718 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4719 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4720 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4721 }
4722
4723 memset(&gm, 0xab, sizeof(gm));
4724 SetLastError(0xdeadbeef);
4725 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), NULL, &mat);
4726 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4727 {
4728 if (fmt[i] == GGO_METRICS)
4729 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4730 else
4731 ok(ret == 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt[i], ret);
4732 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4733 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4734 }
4735
4736 memset(&gm, 0xab, sizeof(gm));
4737 SetLastError(0xdeadbeef);
4738 ret = GetGlyphOutlineW(hdc, ' ', fmt[i], &gm, sizeof(dummy), &dummy, &mat);
4739 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
4740 {
4741 if (fmt[i] == GGO_METRICS) {
4742 ok(ret != GDI_ERROR, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt[i], ret);
4743 ok(gm.gmBlackBoxX == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxX);
4744 ok(gm.gmBlackBoxY == 1, "%2d:expected 1, got %u\n", fmt[i], gm.gmBlackBoxY);
4745 }
4746 else
4747 {
4748 ok(ret == GDI_ERROR, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt[i], ret);
4749 memset(&gm2, 0xab, sizeof(gm2));
4750 ok(memcmp(&gm, &gm2, sizeof(GLYPHMETRICS)) == 0,
4751 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt[i]);
4752 }
4753 }
4754 }
4755
4756 SelectObject(hdc, old_hfont);
4757 DeleteObject(hfont);
4758
4759 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
4760 {
4761 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4762 TEXTMETRICA tm;
4763
4764 lf.lfFaceName[0] = '\0';
4765 lf.lfCharSet = c[i].cs;
4766 lf.lfPitchAndFamily = 0;
4767 if (EnumFontFamiliesExA(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
4768 {
4769 skip("TrueType font for charset %u is not installed\n", c[i].cs);
4770 continue;
4771 }
4772
4773 old_hfont = SelectObject(hdc, hfont);
4774
4775 /* expected to ignore superfluous bytes (sigle-byte character) */
4776 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4777 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
4778 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4779
4780 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
4781 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4782 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4783
4784 /* expected to ignore superfluous bytes (double-byte character) */
4785 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
4786 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
4787 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
4788 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
4789
4790 /* expected to match wide-char version results */
4791 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
4792 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
4793
4794 if (EnumFontFamiliesExA(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
4795 {
4796 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
4797 continue;
4798 }
4799 DeleteObject(SelectObject(hdc, hfont));
4800 if (c[i].a <= 0xff)
4801 {
4802 DeleteObject(SelectObject(hdc, old_hfont));
4803 continue;
4804 }
4805
4806 ret = GetObjectA(hfont, sizeof lf, &lf);
4807 ok(ret > 0, "GetObject error %u\n", GetLastError());
4808
4809 ret = GetTextMetricsA(hdc, &tm);
4810 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4811 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4812 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4813 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4814 -lf.lfHeight, tm.tmAveCharWidth, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4815 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4816 "expected %d, got %d (%s:%d)\n",
4817 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4818
4819 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
4820 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4821 ok(gm2.gmCellIncY == -lf.lfHeight,
4822 "expected %d, got %d (%s:%d)\n",
4823 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4824
4825 lf.lfItalic = TRUE;
4826 hfont = CreateFontIndirectA(&lf);
4827 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4828 DeleteObject(SelectObject(hdc, hfont));
4829 ret = GetTextMetricsA(hdc, &tm);
4830 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4831 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4832 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4833 ok(gm2.gmCellIncX == tm.tmAveCharWidth * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
4834 "expected %d, got %d (%s:%d)\n",
4835 tm.tmAveCharWidth * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
4836
4837 lf.lfItalic = FALSE;
4838 lf.lfEscapement = lf.lfOrientation = 2700;
4839 hfont = CreateFontIndirectA(&lf);
4840 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
4841 DeleteObject(SelectObject(hdc, hfont));
4842 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
4843 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
4844 ok(gm2.gmCellIncY == -lf.lfHeight,
4845 "expected %d, got %d (%s:%d)\n",
4846 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
4847
4848 hfont = SelectObject(hdc, old_hfont);
4849 DeleteObject(hfont);
4850 }
4851
4852 DeleteDC(hdc);
4853 }
4854
4855 /* bug #9995: there is a limit to the character width that can be specified */
4856 static void test_GetTextMetrics2(const char *fontname, int font_height)
4857 {
4858 HFONT of, hf;
4859 HDC hdc;
4860 TEXTMETRICA tm;
4861 BOOL ret;
4862 int ave_width, height, width, ratio, scale;
4863
4864 if (!is_truetype_font_installed( fontname)) {
4865 skip("%s is not installed\n", fontname);
4866 return;
4867 }
4868 hdc = CreateCompatibleDC(0);
4869 ok( hdc != NULL, "CreateCompatibleDC failed\n");
4870 /* select width = 0 */
4871 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4872 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4873 DEFAULT_QUALITY, VARIABLE_PITCH,
4874 fontname);
4875 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
4876 of = SelectObject( hdc, hf);
4877 ret = GetTextMetricsA( hdc, &tm);
4878 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
4879 height = tm.tmHeight;
4880 ave_width = tm.tmAveCharWidth;
4881 SelectObject( hdc, of);
4882 DeleteObject( hf);
4883
4884 trace("height %d, ave width %d\n", height, ave_width);
4885
4886 for (width = ave_width * 2; /* nothing*/; width += ave_width)
4887 {
4888 hf = CreateFontA(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
4889 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
4890 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
4891 ok(hf != 0, "CreateFont failed\n");
4892 of = SelectObject(hdc, hf);
4893 ret = GetTextMetricsA(hdc, &tm);
4894 ok(ret, "GetTextMetrics error %u\n", GetLastError());
4895 SelectObject(hdc, of);
4896 DeleteObject(hf);
4897
4898 if (match_off_by_1(tm.tmAveCharWidth, ave_width, FALSE) || width / height > 200)
4899 break;
4900 }
4901
4902 DeleteDC(hdc);
4903
4904 ratio = width / height;
4905 scale = width / ave_width;
4906
4907 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4908 width, height, ratio, width, ave_width, scale);
4909
4910 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
4911 }
4912
4913 static void test_GetCharacterPlacement(void)
4914 {
4915 GCP_RESULTSA result;
4916 DWORD size, size2;
4917 WCHAR glyphs[20];
4918 HDC hdc;
4919
4920 hdc = CreateCompatibleDC(0);
4921 ok(!!hdc, "CreateCompatibleDC failed\n");
4922
4923 memset(&result, 0, sizeof(result));
4924 result.lStructSize = sizeof(result);
4925 result.lpGlyphs = glyphs;
4926 result.nGlyphs = 20;
4927
4928 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, &result, 0);
4929 ok(size, "GetCharacterPlacementA failed!\n");
4930
4931 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 0, NULL, 0);
4932 ok(size2, "GetCharacterPlacementA failed!\n");
4933 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
4934
4935 size2 = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, NULL, GCP_REORDER);
4936 ok(size2, "GetCharacterPlacementA failed!\n");
4937 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
4938
4939 size = GetCharacterPlacementA(hdc, "Wine Test", 9, 1024, &result, GCP_REORDER);
4940 ok(size, "GetCharacterPlacementA failed!\n");
4941 ok(size == size2, "GetCharacterPlacementA returned different result: %u vs %u\n", size2, size);
4942 }
4943
4944 static void test_CreateFontIndirect(void)
4945 {
4946 LOGFONTA lf, getobj_lf;
4947 int ret, i;
4948 HFONT hfont;
4949 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4950
4951 memset(&lf, 0, sizeof(lf));
4952 lf.lfCharSet = ANSI_CHARSET;
4953 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4954 lf.lfHeight = 16;
4955 lf.lfWidth = 16;
4956 lf.lfQuality = DEFAULT_QUALITY;
4957 lf.lfItalic = FALSE;
4958 lf.lfWeight = FW_DONTCARE;
4959
4960 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
4961 {
4962 lstrcpyA(lf.lfFaceName, TestName[i]);
4963 hfont = CreateFontIndirectA(&lf);
4964 ok(hfont != 0, "CreateFontIndirectA failed\n");
4965 SetLastError(0xdeadbeef);
4966 ret = GetObjectA(hfont, sizeof(getobj_lf), &getobj_lf);
4967 ok(ret, "GetObject failed: %d\n", GetLastError());
4968 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
4969 ok(lf.lfWeight == getobj_lf.lfWeight ||
4970 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
4971 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
4972 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
4973 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
4974 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
4975 DeleteObject(hfont);
4976 }
4977 }
4978
4979 static void test_CreateFontIndirectEx(void)
4980 {
4981 ENUMLOGFONTEXDVA lfex;
4982 HFONT hfont;
4983
4984 if (!pCreateFontIndirectExA)
4985 {
4986 win_skip("CreateFontIndirectExA is not available\n");
4987 return;
4988 }
4989
4990 if (!is_truetype_font_installed("Arial"))
4991 {
4992 skip("Arial is not installed\n");
4993 return;
4994 }
4995
4996 SetLastError(0xdeadbeef);
4997 hfont = pCreateFontIndirectExA(NULL);
4998 ok(hfont == NULL, "got %p\n", hfont);
4999 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
5000
5001 memset(&lfex, 0, sizeof(lfex));
5002 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
5003 hfont = pCreateFontIndirectExA(&lfex);
5004 ok(hfont != 0, "CreateFontIndirectEx failed\n");
5005 if (hfont)
5006 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
5007 DeleteObject(hfont);
5008 }
5009
5010 static void free_font(void *font)
5011 {
5012 UnmapViewOfFile(font);
5013 }
5014
5015 static void *load_font(const char *font_name, DWORD *font_size)
5016 {
5017 char file_name[MAX_PATH];
5018 HANDLE file, mapping;
5019 void *font;
5020
5021 if (!GetWindowsDirectoryA(file_name, sizeof(file_name))) return NULL;
5022 strcat(file_name, "\\fonts\\");
5023 strcat(file_name, font_name);
5024
5025 file = CreateFileA(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
5026 if (file == INVALID_HANDLE_VALUE) return NULL;
5027
5028 *font_size = GetFileSize(file, NULL);
5029
5030 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
5031 if (!mapping)
5032 {
5033 CloseHandle(file);
5034 return NULL;
5035 }
5036
5037 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5038
5039 CloseHandle(file);
5040 CloseHandle(mapping);
5041 return font;
5042 }
5043
5044 static void test_AddFontMemResource(void)
5045 {
5046 void *font;
5047 DWORD font_size, num_fonts;
5048 HANDLE ret;
5049 BOOL bRet;
5050
5051 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
5052 {
5053 win_skip("AddFontMemResourceEx is not available on this platform\n");
5054 return;
5055 }
5056
5057 font = load_font("sserife.fon", &font_size);
5058 if (!font)
5059 {
5060 skip("Unable to locate and load font sserife.fon\n");
5061 return;
5062 }
5063
5064 SetLastError(0xdeadbeef);
5065 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
5066 ok(!ret, "AddFontMemResourceEx should fail\n");
5067 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5068 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5069 GetLastError());
5070
5071 SetLastError(0xdeadbeef);
5072 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
5073 ok(!ret, "AddFontMemResourceEx should fail\n");
5074 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5075 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5076 GetLastError());
5077
5078 SetLastError(0xdeadbeef);
5079 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
5080 ok(!ret, "AddFontMemResourceEx should fail\n");
5081 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5082 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5083 GetLastError());
5084
5085 SetLastError(0xdeadbeef);
5086 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
5087 ok(!ret, "AddFontMemResourceEx should fail\n");
5088 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5089 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5090 GetLastError());
5091
5092 SetLastError(0xdeadbeef);
5093 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
5094 ok(!ret, "AddFontMemResourceEx should fail\n");
5095 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5096 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5097 GetLastError());
5098
5099 SetLastError(0xdeadbeef);
5100 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
5101 ok(!ret, "AddFontMemResourceEx should fail\n");
5102 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5103 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5104 GetLastError());
5105
5106 num_fonts = 0xdeadbeef;
5107 SetLastError(0xdeadbeef);
5108 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
5109 ok(!ret, "AddFontMemResourceEx should fail\n");
5110 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5111 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5112 GetLastError());
5113 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5114
5115 if (0) /* hangs under windows 2000 */
5116 {
5117 num_fonts = 0xdeadbeef;
5118 SetLastError(0xdeadbeef);
5119 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
5120 ok(!ret, "AddFontMemResourceEx should fail\n");
5121 ok(GetLastError() == 0xdeadbeef,
5122 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5123 GetLastError());
5124 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5125 }
5126
5127 num_fonts = 0xdeadbeef;
5128 SetLastError(0xdeadbeef);
5129 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
5130 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
5131 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5132 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
5133
5134 free_font(font);
5135
5136 SetLastError(0xdeadbeef);
5137 bRet = pRemoveFontMemResourceEx(ret);
5138 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
5139
5140 /* test invalid pointer to number of loaded fonts */
5141 font = load_font("sserife.fon", &font_size);
5142 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
5143
5144 SetLastError(0xdeadbeef);
5145 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
5146 ok(!ret, "AddFontMemResourceEx should fail\n");
5147 ok(GetLastError() == 0xdeadbeef,
5148 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5149 GetLastError());
5150
5151 SetLastError(0xdeadbeef);
5152 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
5153 ok(!ret, "AddFontMemResourceEx should fail\n");
5154 ok(GetLastError() == ERROR_INVALID_PARAMETER,
5155 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5156 GetLastError());
5157
5158 free_font(font);
5159 }
5160
5161 static INT CALLBACK enum_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5162 {
5163 LOGFONTA *lf;
5164
5165 if (type != TRUETYPE_FONTTYPE) return 1;
5166
5167 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5168
5169 lf = (LOGFONTA *)lparam;
5170 *lf = *elf;
5171 return 0;
5172 }
5173
5174 static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5175 {
5176 int ret;
5177 LOGFONTA *lf;
5178
5179 if (type != TRUETYPE_FONTTYPE) return 1;
5180
5181 lf = (LOGFONTA *)lparam;
5182 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
5183 if(ret == 0)
5184 {
5185 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
5186 *lf = *elf;
5187 return 0;
5188 }
5189 return 1;
5190 }
5191
5192 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
5193 {
5194 return lparam;
5195 }
5196
5197 static void test_EnumFonts(void)
5198 {
5199 int ret;
5200 LOGFONTA lf;
5201 HDC hdc;
5202
5203 if (!is_truetype_font_installed("Arial"))
5204 {
5205 skip("Arial is not installed\n");
5206 return;
5207 }
5208
5209 /* Windows uses localized font face names, so Arial Bold won't be found */
5210 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
5211 {
5212 skip("User locale is not English, skipping the test\n");
5213 return;
5214 }
5215
5216 hdc = CreateCompatibleDC(0);
5217
5218 /* check that the enumproc's retval is returned */
5219 ret = EnumFontFamiliesA(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
5220 ok(ret == 0xcafe, "got %08x\n", ret);
5221
5222 ret = EnumFontFamiliesA(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
5223 ok(!ret, "font Arial is not enumerated\n");
5224 ret = strcmp(lf.lfFaceName, "Arial");
5225 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5226 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5227
5228 strcpy(lf.lfFaceName, "Arial");
5229 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5230 ok(!ret, "font Arial is not enumerated\n");
5231 ret = strcmp(lf.lfFaceName, "Arial");
5232 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5233 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
5234
5235 ret = EnumFontFamiliesA(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
5236 ok(!ret, "font Arial Bold is not enumerated\n");
5237 ret = strcmp(lf.lfFaceName, "Arial");
5238 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5239 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5240
5241 strcpy(lf.lfFaceName, "Arial Bold");
5242 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5243 ok(ret, "font Arial Bold should not be enumerated\n");
5244
5245 ret = EnumFontFamiliesA(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
5246 ok(!ret, "font Arial Bold Italic is not enumerated\n");
5247 ret = strcmp(lf.lfFaceName, "Arial");
5248 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
5249 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
5250
5251 strcpy(lf.lfFaceName, "Arial Bold Italic");
5252 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5253 ok(ret, "font Arial Bold Italic should not be enumerated\n");
5254
5255 ret = EnumFontFamiliesA(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
5256 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5257
5258 strcpy(lf.lfFaceName, "Arial Italic Bold");
5259 ret = EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
5260 ok(ret, "font Arial Italic Bold should not be enumerated\n");
5261
5262 DeleteDC(hdc);
5263 }
5264
5265 static INT CALLBACK enum_ms_shell_dlg_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5266 {
5267 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5268
5269 if (0) /* Disabled to limit console spam */
5270 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5271 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5272
5273 if (type != TRUETYPE_FONTTYPE) return 1;
5274 if (strcmp(lf->lfFaceName, "MS Shell Dlg") != 0) return 1;
5275
5276 if (efnd->total >= efnd->size)
5277 {
5278 efnd->size = max( (efnd->total + 1) * 2, 256 );
5279 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5280 if (!efnd->elf) return 0;
5281 }
5282 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5283 return 0;
5284 }
5285
5286 static INT CALLBACK enum_ms_shell_dlg2_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5287 {
5288 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
5289
5290 if (0) /* Disabled to limit console spam */
5291 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5292 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
5293
5294 if (type != TRUETYPE_FONTTYPE) return 1;
5295 if (strcmp(lf->lfFaceName, "MS Shell Dlg 2") != 0) return 1;
5296
5297 if (efnd->total >= efnd->size)
5298 {
5299 efnd->size = max( (efnd->total + 1) * 2, 256 );
5300 efnd->elf = heap_realloc( efnd->elf, efnd->size * sizeof(*efnd->elf) );
5301 if (!efnd->elf) return 0;
5302 }
5303 efnd->elf[efnd->total++] = *(ENUMLOGFONTA *)lf;
5304 return 0;
5305 }
5306
5307 static void test_EnumFonts_subst(void)
5308 {
5309 int ret;
5310 LOGFONTA lf;
5311 HDC hdc;
5312 struct enum_fullname_data efnd;
5313
5314 ret = is_font_installed("MS Shell Dlg");
5315 ok(ret, "MS Shell Dlg should be enumerated\n");
5316 ret = is_truetype_font_installed("MS Shell Dlg");
5317 ok(ret, "MS Shell Dlg should be enumerated as a TrueType font\n");
5318
5319 ret = is_font_installed("MS Shell Dlg 2");
5320 ok(ret, "MS Shell Dlg 2 should be enumerated\n");
5321 ret = is_truetype_font_installed("MS Shell Dlg 2");
5322 ok(ret, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5323
5324 hdc = CreateCompatibleDC(0);
5325
5326 memset(&efnd, 0, sizeof(efnd));
5327 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5328 ok(ret, "MS Shell Dlg should not be enumerated\n");
5329 ok(!efnd.total, "MS Shell Dlg should not be enumerated\n");
5330
5331 memset(&lf, 0, sizeof(lf));
5332 lf.lfCharSet = DEFAULT_CHARSET;
5333
5334 efnd.total = 0;
5335 strcpy(lf.lfFaceName, "MS Shell Dlg");
5336 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg_proc, (LPARAM)&efnd, 0);
5337 ok(!ret, "MS Shell Dlg should be enumerated\n");
5338 ok(efnd.total > 0, "MS Shell Dlg should be enumerated\n");
5339 if (efnd.total)
5340 {
5341 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg");
5342 ok(!ret, "expected MS Shell Dlg, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5343 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg");
5344 ok(ret, "did not expect MS Shell Dlg\n");
5345 }
5346
5347 efnd.total = 0;
5348 ret = EnumFontFamiliesExA(hdc, NULL, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5349 ok(ret, "MS Shell Dlg 2 should not be enumerated\n");
5350 ok(!efnd.total, "MS Shell Dlg 2 should not be enumerated\n");
5351
5352 efnd.total = 0;
5353 strcpy(lf.lfFaceName, "MS Shell Dlg 2");
5354 ret = EnumFontFamiliesExA(hdc, &lf, enum_ms_shell_dlg2_proc, (LPARAM)&efnd, 0);
5355 ok(!ret, "MS Shell Dlg 2 should be enumerated\n");
5356 ok(efnd.total > 0, "MS Shell Dlg 2 should be enumerated\n");
5357 if (efnd.total)
5358 {
5359 ret = strcmp((const char *)efnd.elf[0].elfLogFont.lfFaceName, "MS Shell Dlg 2");
5360 ok(!ret, "expected MS Shell Dlg 2, got %s\n", efnd.elf[0].elfLogFont.lfFaceName);
5361 ret = strcmp((const char *)efnd.elf[0].elfFullName, "MS Shell Dlg 2");
5362 ok(ret, "did not expect MS Shell Dlg 2\n");
5363 }
5364
5365 heap_free(efnd.elf);
5366 DeleteDC(hdc);
5367 }
5368
5369 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam)
5370 {
5371 const ENUMLOGFONTA *elf = (const ENUMLOGFONTA *)lf;
5372 const char *fullname = (const char *)lParam;
5373
5374 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
5375
5376 return 1;
5377 }
5378
5379 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
5380 {
5381 HDC hdc = GetDC(0);
5382 BOOL ret = FALSE;
5383
5384 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
5385 ret = TRUE;
5386
5387 ReleaseDC(0, hdc);
5388 return ret;
5389 }
5390
5391 static void test_fullname(void)
5392 {
5393 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5394 WCHAR bufW[LF_FULLFACESIZE];
5395 char bufA[LF_FULLFACESIZE];
5396 HFONT hfont, of;
5397 LOGFONTA lf;
5398 HDC hdc;
5399 int i;
5400 DWORD ret;
5401
5402 hdc = CreateCompatibleDC(0);
5403 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5404
5405 memset(&lf, 0, sizeof(lf));
5406 lf.lfCharSet = ANSI_CHARSET;
5407 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5408 lf.lfHeight = 16;
5409 lf.lfWidth = 16;
5410 lf.lfQuality = DEFAULT_QUALITY;
5411 lf.lfItalic = FALSE;
5412 lf.lfWeight = FW_DONTCARE;
5413
5414 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
5415 {
5416 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
5417 {
5418 skip("%s is not installed\n", TestName[i]);
5419 continue;
5420 }
5421
5422 lstrcpyA(lf.lfFaceName, TestName[i]);
5423 hfont = CreateFontIndirectA(&lf);
5424 ok(hfont != 0, "CreateFontIndirectA failed\n");
5425
5426 of = SelectObject(hdc, hfont);
5427 bufW[0] = 0;
5428 bufA[0] = 0;
5429 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
5430 ok(ret, "face full name could not be read\n");
5431 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
5432 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
5433 SelectObject(hdc, of);
5434 DeleteObject(hfont);
5435 }
5436 DeleteDC(hdc);
5437 }
5438
5439 static WCHAR *prepend_at(WCHAR *family)
5440 {
5441 if (!family)
5442 return NULL;
5443
5444 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
5445 family[0] = '@';
5446 return family;
5447 }
5448
5449 static void test_fullname2_helper(const char *Family)
5450 {
5451 char *FamilyName, *FaceName, *StyleName, *otmStr;
5452 struct enum_fullname_data efnd;
5453 WCHAR *bufW;
5454 char *bufA;
5455 HFONT hfont, of;
5456 LOGFONTA lf;
5457 HDC hdc;
5458 int i;
5459 DWORD otm_size, ret, buf_size;
5460 OUTLINETEXTMETRICA *otm;
5461 BOOL want_vertical, get_vertical;
5462 want_vertical = ( Family[0] == '@' );
5463
5464 hdc = CreateCompatibleDC(0);
5465 ok(hdc != NULL, "CreateCompatibleDC failed\n");
5466
5467 memset(&lf, 0, sizeof(lf));
5468 lf.lfCharSet = DEFAULT_CHARSET;
5469 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5470 lf.lfHeight = 16;
5471 lf.lfWidth = 16;
5472 lf.lfQuality = DEFAULT_QUALITY;
5473 lf.lfItalic = FALSE;
5474 lf.lfWeight = FW_DONTCARE;
5475 strcpy(lf.lfFaceName, Family);
5476 memset(&efnd, 0, sizeof(efnd));
5477 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
5478 if (efnd.total == 0)
5479 skip("%s is not installed\n", lf.lfFaceName);
5480
5481 for (i = 0; i < efnd.total; i++)
5482 {
5483 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
5484 FaceName = (char *)efnd.elf[i].elfFullName;
5485 StyleName = (char *)efnd.elf[i].elfStyle;
5486
5487 get_vertical = ( FamilyName[0] == '@' );
5488 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
5489
5490 lstrcpyA(lf.lfFaceName, FaceName);
5491 hfont = CreateFontIndirectA(&lf);
5492 ok(hfont != 0, "CreateFontIndirectA failed\n");
5493
5494 of = SelectObject(hdc, hfont);
5495 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
5496 ok(buf_size != GDI_ERROR, "no name table found\n");
5497 if (buf_size == GDI_ERROR) continue;
5498
5499 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
5500 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
5501
5502 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5503 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5504 memset(otm, 0, otm_size);
5505 ret = GetOutlineTextMetricsA(hdc, otm_size, otm);
5506 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
5507 if (ret == 0) continue;
5508
5509 bufW[0] = 0;
5510 bufA[0] = 0;
5511 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
5512 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5513 ok(ret, "%s: FAMILY (family name) could not be read\n", FamilyName);
5514 if (want_vertical) bufW = prepend_at(bufW);
5515 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5516 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
5517 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
5518 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
5519
5520 bufW[0] = 0;
5521 bufA[0] = 0;
5522 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
5523 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5524 ok(ret, "FULL_NAME (face name) could not be read\n");
5525 if (want_vertical) bufW = prepend_at(bufW);
5526 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5527 ok(!lstrcmpA(FaceName, bufA), "%s: font face names don't match: returned %s, expect %s\n", FamilyName, FaceName, bufA);
5528 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
5529 ok(!lstrcmpA(FaceName, otmStr), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName, FaceName, otmStr);
5530
5531 bufW[0] = 0;
5532 bufA[0] = 0;
5533 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
5534 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5535 ok(ret, "%s: SUBFAMILY (style name) could not be read\n", FamilyName);
5536 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5537 ok(!lstrcmpA(StyleName, bufA), "%s: style names don't match: returned %s, expect %s\n", FamilyName, StyleName, bufA);
5538 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
5539 ok(!lstrcmpA(StyleName, otmStr), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName, StyleName, otmStr);
5540
5541 bufW[0] = 0;
5542 bufA[0] = 0;
5543 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
5544 if (!ret) ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
5545 ok(ret, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName);
5546 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
5547 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
5548 ok(!lstrcmpA(otmStr, bufA), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName, otmStr, bufA);
5549
5550 SelectObject(hdc, of);
5551 DeleteObject(hfont);
5552
5553 HeapFree(GetProcessHeap(), 0, otm);
5554 HeapFree(GetProcessHeap(), 0, bufW);
5555 HeapFree(GetProcessHeap(), 0, bufA);
5556 }
5557 heap_free(efnd.elf);
5558 DeleteDC(hdc);
5559 }
5560
5561 static void test_fullname2(void)
5562 {
5563 test_fullname2_helper("Arial");
5564 test_fullname2_helper("DejaVu Sans");
5565 test_fullname2_helper("Lucida Sans");
5566 test_fullname2_helper("Tahoma");
5567 test_fullname2_helper("Webdings");
5568 test_fullname2_helper("Wingdings");
5569 test_fullname2_helper("SimSun");
5570 test_fullname2_helper("NSimSun");
5571 test_fullname2_helper("MingLiu");
5572 test_fullname2_helper("PMingLiu");
5573 test_fullname2_helper("WenQuanYi Micro Hei");
5574 test_fullname2_helper("MS UI Gothic");
5575 test_fullname2_helper("Ume UI Gothic");
5576 test_fullname2_helper("MS Gothic");
5577 test_fullname2_helper("Ume Gothic");
5578 test_fullname2_helper("MS PGothic");
5579 test_fullname2_helper("Ume P Gothic");
5580 test_fullname2_helper("Gulim");
5581 test_fullname2_helper("Batang");
5582 test_fullname2_helper("UnBatang");
5583 test_fullname2_helper("UnDotum");
5584 test_fullname2_helper("@SimSun");
5585 test_fullname2_helper("@NSimSun");
5586 test_fullname2_helper("@MingLiu");
5587 test_fullname2_helper("@PMingLiu");
5588 test_fullname2_helper("@WenQuanYi Micro Hei");
5589 test_fullname2_helper("@MS UI Gothic");
5590 test_fullname2_helper("@Ume UI Gothic");
5591 test_fullname2_helper("@MS Gothic");
5592 test_fullname2_helper("@Ume Gothic");
5593 test_fullname2_helper("@MS PGothic");
5594 test_fullname2_helper("@Ume P Gothic");
5595 test_fullname2_helper("@Gulim");
5596 test_fullname2_helper("@Batang");
5597 test_fullname2_helper("@UnBatang");
5598 test_fullname2_helper("@UnDotum");
5599
5600 }
5601
5602 static void test_GetGlyphOutline_empty_contour(void)
5603 {
5604 HDC hdc;
5605 LOGFONTA lf;
5606 HFONT hfont, hfont_prev;
5607 TTPOLYGONHEADER *header;
5608 GLYPHMETRICS gm;
5609 char buf[1024];
5610 DWORD ret;
5611
5612 memset(&lf, 0, sizeof(lf));
5613 lf.lfHeight = 72;
5614 lstrcpyA(lf.lfFaceName, "wine_test");
5615
5616 hfont = CreateFontIndirectA(&lf);
5617 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5618
5619 hdc = GetDC(NULL);
5620
5621 hfont_prev = SelectObject(hdc, hfont);
5622 ok(hfont_prev != NULL, "SelectObject failed\n");
5623
5624 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
5625 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5626
5627 header = (TTPOLYGONHEADER*)buf;
5628 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
5629 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
5630 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
5631 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
5632 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5633 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5634 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
5635 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
5636
5637 SelectObject(hdc, hfont_prev);
5638 DeleteObject(hfont);
5639 ReleaseDC(NULL, hdc);
5640 }
5641
5642 static void test_GetGlyphOutline_metric_clipping(void)
5643 {
5644 HDC hdc;
5645 LOGFONTA lf;
5646 HFONT hfont, hfont_prev;
5647 GLYPHMETRICS gm;
5648 TEXTMETRICA tm;
5649 TEXTMETRICW tmW;
5650 DWORD ret;
5651
5652 memset(&lf, 0, sizeof(lf));
5653 lf.lfHeight = 72;
5654 lstrcpyA(lf.lfFaceName, "wine_test");
5655
5656 SetLastError(0xdeadbeef);
5657 hfont = CreateFontIndirectA(&lf);
5658 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5659
5660 hdc = GetDC(NULL);
5661
5662 hfont_prev = SelectObject(hdc, hfont);
5663 ok(hfont_prev != NULL, "SelectObject failed\n");
5664
5665 SetLastError(0xdeadbeef);
5666 ret = GetTextMetricsA(hdc, &tm);
5667 ok(ret, "GetTextMetrics error %u\n", GetLastError());
5668
5669 GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
5670 ok(gm.gmptGlyphOrigin.y <= tm.tmAscent,
5671 "Glyph top(%d) exceeds ascent(%d)\n",
5672 gm.gmptGlyphOrigin.y, tm.tmAscent);
5673 GetGlyphOutlineA(hdc, 'D', GGO_METRICS, &gm, 0, NULL, &mat);
5674 ok(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY >= -tm.tmDescent,
5675 "Glyph bottom(%d) exceeds descent(%d)\n",
5676 gm.gmptGlyphOrigin.y - gm.gmBlackBoxY, -tm.tmDescent);
5677
5678 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5679 GetTextMetricsW(hdc, &tmW);
5680 todo_wine
5681 ok( tmW.tmLastChar == 0xfffe, "got %04x\n", tmW.tmLastChar);
5682
5683 SelectObject(hdc, hfont_prev);
5684 DeleteObject(hfont);
5685 ReleaseDC(NULL, hdc);
5686 }
5687
5688 static void test_fstype_fixup(void)
5689 {
5690 HDC hdc;
5691 LOGFONTA lf;
5692 HFONT hfont, hfont_prev;
5693 DWORD ret;
5694 OUTLINETEXTMETRICA *otm;
5695 DWORD otm_size;
5696
5697 memset(&lf, 0, sizeof(lf));
5698 lf.lfHeight = 72;
5699 lstrcpyA(lf.lfFaceName, "wine_test");
5700
5701 SetLastError(0xdeadbeef);
5702 hfont = CreateFontIndirectA(&lf);
5703 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
5704
5705 hdc = GetDC(NULL);
5706
5707 hfont_prev = SelectObject(hdc, hfont);
5708 ok(hfont_prev != NULL, "SelectObject failed\n");
5709
5710 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
5711 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
5712 otm->otmSize = sizeof(*otm);
5713 ret = GetOutlineTextMetricsA(hdc, otm->otmSize, otm);
5714 ok(ret == otm->otmSize, "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
5715
5716 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5717 valid bits are 1, 2, 3, 8, 9. */
5718 ok((otm->otmfsType & ~0x30e) == 0, "fsType %#x\n", otm->otmfsType);
5719
5720 HeapFree(GetProcessHeap(), 0, otm);
5721
5722 SelectObject(hdc, hfont_prev);
5723 DeleteObject(hfont);
5724 ReleaseDC(NULL, hdc);
5725 }
5726
5727 static void test_CreateScalableFontResource(void)
5728 {
5729 char ttf_name[MAX_PATH];
5730 char tmp_path[MAX_PATH];
5731 char fot_name[MAX_PATH];
5732 char *file_part;
5733 DWORD ret;
5734 int i;
5735
5736 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
5737 {
5738 win_skip("AddFontResourceExA is not available on this platform\n");
5739 return;
5740 }
5741
5742 if (!write_ttf_file("wine_test.ttf", ttf_name))
5743 {
5744 skip("Failed to create ttf file for testing\n");
5745 return;
5746 }
5747
5748 trace("created %s\n", ttf_name);
5749
5750 ret = is_truetype_font_installed("wine_test");
5751 ok(!ret, "font wine_test should not be enumerated\n");
5752
5753 ret = GetTempPathA(MAX_PATH, tmp_path);
5754 ok(ret, "GetTempPath() error %d\n", GetLastError());
5755 ret = GetTempFileNameA(tmp_path, "fot", 0, fot_name);
5756 ok(ret, "GetTempFileName() error %d\n", GetLastError());
5757
5758 ret = GetFileAttributesA(fot_name);
5759 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
5760
5761 SetLastError(0xdeadbeef);
5762 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5763 ok(!ret, "CreateScalableFontResource() should fail\n");
5764 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5765
5766 SetLastError(0xdeadbeef);
5767 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, "");
5768 ok(!ret, "CreateScalableFontResource() should fail\n");
5769 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5770
5771 file_part = strrchr(ttf_name, '\\');
5772 SetLastError(0xdeadbeef);
5773 ret = CreateScalableFontResourceA(0, fot_name, file_part, tmp_path);
5774 ok(!ret, "CreateScalableFontResource() should fail\n");
5775 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
5776
5777 SetLastError(0xdeadbeef);
5778 ret = CreateScalableFontResourceA(0, fot_name, "random file name", tmp_path);
5779 ok(!ret, "CreateScalableFontResource() should fail\n");
5780 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5781
5782 SetLastError(0xdeadbeef);
5783 ret = CreateScalableFontResourceA(0, fot_name, NULL, ttf_name);
5784 ok(!ret, "CreateScalableFontResource() should fail\n");
5785 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
5786
5787 ret = DeleteFileA(fot_name);
5788 ok(ret, "DeleteFile() error %d\n", GetLastError());
5789
5790 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5791 ok(!ret, "RemoveFontResourceEx() should fail\n");
5792
5793 /* test public font resource */
5794 SetLastError(0xdeadbeef);
5795 ret = CreateScalableFontResourceA(0, fot_name, ttf_name, NULL);
5796 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5797
5798 ret = is_truetype_font_installed("wine_test");
5799 ok(!ret, "font wine_test should not be enumerated\n");
5800
5801 SetLastError(0xdeadbeef);
5802 ret = pAddFontResourceExA(fot_name, 0, 0);
5803 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5804
5805 ret = is_truetype_font_installed("wine_test");
5806 ok(ret, "font wine_test should be enumerated\n");
5807
5808 test_GetGlyphOutline_empty_contour();
5809 test_GetGlyphOutline_metric_clipping();
5810 test_fstype_fixup();
5811
5812 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5813 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
5814
5815 SetLastError(0xdeadbeef);
5816 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5817 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5818
5819 ret = is_truetype_font_installed("wine_test");
5820 ok(!ret, "font wine_test should not be enumerated\n");
5821
5822 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5823 ok(!ret, "RemoveFontResourceEx() should fail\n");
5824
5825 /* test refcounting */
5826 for (i = 0; i < 5; i++)
5827 {
5828 SetLastError(0xdeadbeef);
5829 ret = pAddFontResourceExA(fot_name, 0, 0);
5830 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5831 }
5832 for (i = 0; i < 5; i++)
5833 {
5834 SetLastError(0xdeadbeef);
5835 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5836 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5837 }
5838 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5839 ok(!ret, "RemoveFontResourceEx() should fail\n");
5840
5841 DeleteFileA(fot_name);
5842
5843 /* test hidden font resource */
5844 SetLastError(0xdeadbeef);
5845 ret = CreateScalableFontResourceA(1, fot_name, ttf_name, NULL);
5846 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
5847
5848 ret = is_truetype_font_installed("wine_test");
5849 ok(!ret, "font wine_test should not be enumerated\n");
5850
5851 SetLastError(0xdeadbeef);
5852 ret = pAddFontResourceExA(fot_name, 0, 0);
5853 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
5854
5855 ret = is_truetype_font_installed("wine_test");
5856 todo_wine
5857 ok(!ret, "font wine_test should not be enumerated\n");
5858
5859 /* XP allows removing a private font added with 0 flags */
5860 SetLastError(0xdeadbeef);
5861 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
5862 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
5863
5864 ret = is_truetype_font_installed("wine_test");
5865 ok(!ret, "font wine_test should not be enumerated\n");
5866
5867 ret = pRemoveFontResourceExA(fot_name, 0, 0);
5868 ok(!ret, "RemoveFontResourceEx() should fail\n");
5869
5870 DeleteFileA(fot_name);
5871 DeleteFileA(ttf_name);
5872 }
5873
5874 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
5875 {
5876 LOGFONTA lf;
5877 HFONT hfont, hfont_prev;
5878 HDC hdc;
5879 char facename[100];
5880 DWORD ret;
5881 static const WCHAR str[] = { 0x2025 };
5882
5883 *installed = is_truetype_font_installed(name);
5884
5885 lf.lfHeight = -18;
5886 lf.lfWidth = 0;
5887 lf.lfEscapement = 0;
5888 lf.lfOrientation = 0;
5889 lf.lfWeight = FW_DONTCARE;
5890 lf.lfItalic = 0;
5891 lf.lfUnderline = 0;
5892 lf.lfStrikeOut = 0;
5893 lf.lfCharSet = DEFAULT_CHARSET;
5894 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
5895 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
5896 lf.lfQuality = DEFAULT_QUALITY;
5897 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5898 strcpy(lf.lfFaceName, name);
5899
5900 hfont = CreateFontIndirectA(&lf);
5901 ok(hfont != NULL, "CreateFontIndirectA failed\n");
5902
5903 hdc = GetDC(NULL);
5904
5905 hfont_prev = SelectObject(hdc, hfont);
5906 ok(hfont_prev != NULL, "SelectObject failed\n");
5907
5908 ret = GetTextFaceA(hdc, sizeof facename, facename);
5909 ok(ret, "GetTextFaceA failed\n");
5910 *selected = !strcmp(facename, name);
5911
5912 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
5913 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5914 if (!*selected)
5915 memset(gm, 0, sizeof *gm);
5916
5917 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
5918 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
5919
5920 SelectObject(hdc, hfont_prev);
5921 DeleteObject(hfont);
5922 ReleaseDC(NULL, hdc);
5923 }
5924
5925 static void check_vertical_metrics(const char *face)
5926 {
5927 LOGFONTA lf;
5928 HFONT hfont, hfont_prev;
5929 HDC hdc;
5930 DWORD ret;
5931 GLYPHMETRICS rgm, vgm;
5932 const UINT code = 0x5EAD, height = 1000;
5933 WORD idx;
5934 ABC abc;
5935 OUTLINETEXTMETRICA otm;
5936 USHORT numOfLongVerMetrics;
5937
5938 hdc = GetDC(NULL);
5939
5940 memset(&lf, 0, sizeof(lf));
5941 strcpy(lf.lfFaceName, face);
5942 lf.lfHeight = -height;
5943 lf.lfCharSet = DEFAULT_CHARSET;
5944 lf.lfEscapement = lf.lfOrientation = 900;
5945 hfont = CreateFontIndirectA(&lf);
5946 hfont_prev = SelectObject(hdc, hfont);
5947 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &rgm, 0, NULL, &mat);
5948 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5949 ret = GetCharABCWidthsW(hdc, code, code, &abc);
5950 ok(ret, "GetCharABCWidthsW failed\n");
5951 DeleteObject(SelectObject(hdc, hfont_prev));
5952
5953 memset(&lf, 0, sizeof(lf));
5954 strcpy(lf.lfFaceName, "@");
5955 strcat(lf.lfFaceName, face);
5956 lf.lfHeight = -height;
5957 lf.lfCharSet = DEFAULT_CHARSET;
5958 hfont = CreateFontIndirectA(&lf);
5959 hfont_prev = SelectObject(hdc, hfont);
5960 ret = GetGlyphOutlineW(hdc, code, GGO_METRICS, &vgm, 0, NULL, &mat);
5961 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
5962
5963 memset(&otm, 0, sizeof(otm));
5964 otm.otmSize = sizeof(otm);
5965 ret = GetOutlineTextMetricsA(hdc, sizeof(otm), &otm);
5966 ok(ret != 0, "GetOutlineTextMetricsA failed\n");
5967
5968 if (GetFontData(hdc, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT) * 17,
5969 &numOfLongVerMetrics, sizeof(numOfLongVerMetrics)) != GDI_ERROR) {
5970 int offset;
5971 SHORT topSideBearing;
5972
5973 if (!pGetGlyphIndicesW) {
5974 win_skip("GetGlyphIndices is not available on this platform\n");
5975 }
5976 else {
5977 ret = pGetGlyphIndicesW(hdc, (LPCWSTR)&code, 1, &idx, 0);
5978 ok(ret != 0, "GetGlyphIndicesW failed\n");
5979 numOfLongVerMetrics = GET_BE_WORD(numOfLongVerMetrics);
5980 if (numOfLongVerMetrics > idx)
5981 offset = idx * 2 + 1;
5982 else
5983 offset = numOfLongVerMetrics * 2 + (idx - numOfLongVerMetrics);
5984 ret = GetFontData(hdc, MS_MAKE_TAG('v','m','t','x'), offset * sizeof(SHORT),
5985 &topSideBearing, sizeof(SHORT));
5986 ok(ret != GDI_ERROR, "GetFontData(vmtx) failed\n");
5987 topSideBearing = GET_BE_WORD(topSideBearing);
5988 ok(match_off_by_1(vgm.gmptGlyphOrigin.x,
5989 MulDiv(topSideBearing, height, otm.otmEMSquare), FALSE),
5990 "expected %d, got %d\n",
5991 MulDiv(topSideBearing, height, otm.otmEMSquare), vgm.gmptGlyphOrigin.x);
5992 }
5993 }
5994 else
5995 {
5996 ok(vgm.gmptGlyphOrigin.x == rgm.gmptGlyphOrigin.x + vgm.gmCellIncX + otm.otmDescent,
5997 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5998 vgm.gmptGlyphOrigin.x, rgm.gmptGlyphOrigin.x, vgm.gmCellIncX, otm.otmDescent);
5999 }
6000
6001 ok(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB + otm.otmDescent ||
6002 broken(vgm.gmptGlyphOrigin.y == abc.abcA + abc.abcB - otm.otmTextMetrics.tmDescent) /* win2k */,
6003 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6004 (INT)vgm.gmptGlyphOrigin.y, abc.abcA, abc.abcB, otm.otmDescent);
6005
6006 DeleteObject(SelectObject(hdc, hfont_prev));
6007 ReleaseDC(NULL, hdc);
6008 }
6009
6010 static void test_vertical_font(void)
6011 {
6012 char ttf_name[MAX_PATH];
6013 int num, i;
6014 BOOL ret, installed, selected;
6015 GLYPHMETRICS gm;
6016 WORD hgi, vgi;
6017 const char* face_list[] = {
6018 "@WineTestVertical", /* has vmtx table */
6019 "@Ume Gothic", /* doesn't have vmtx table */
6020 "@MS UI Gothic", /* has vmtx table, available on native */
6021 };
6022
6023 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
6024 {
6025 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
6026 return;
6027 }
6028
6029 if (!write_ttf_file("vertical.ttf", ttf_name))
6030 {
6031 skip("Failed to create ttf file for testing\n");
6032 return;
6033 }
6034
6035 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
6036 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6037
6038 check_vertical_font("WineTestVertical", &installed, &selected, &gm, &hgi);
6039 ok(installed, "WineTestVertical is not installed\n");
6040 ok(selected, "WineTestVertical is not selected\n");
6041 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6042 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6043 gm.gmBlackBoxX, gm.gmBlackBoxY);
6044
6045 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &vgi);
6046 ok(installed, "@WineTestVertical is not installed\n");
6047 ok(selected, "@WineTestVertical is not selected\n");
6048 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
6049 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6050 gm.gmBlackBoxX, gm.gmBlackBoxY);
6051
6052 ok(hgi != vgi, "same glyph h:%u v:%u\n", hgi, vgi);
6053
6054 for (i = 0; i < sizeof(face_list)/sizeof(face_list[0]); i++) {
6055 const char* face = face_list[i];
6056 if (!is_truetype_font_installed(face)) {
6057 skip("%s is not installed\n", face);
6058 continue;
6059 }
6060 trace("Testing %s...\n", face);
6061 check_vertical_metrics(&face[1]);
6062 }
6063
6064 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
6065 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
6066
6067 DeleteFileA(ttf_name);
6068 }
6069
6070 static INT CALLBACK has_vertical_font_proc(const LOGFONTA *lf, const TEXTMETRICA *ntm,
6071 DWORD type, LPARAM lParam)
6072 {
6073 if (lf->lfFaceName[0] == '@') {
6074 return 0;
6075 }
6076 return 1;
6077 }
6078
6079 static void test_east_asian_font_selection(void)
6080 {
6081 HDC hdc;
6082 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
6083 GB2312_CHARSET, CHINESEBIG5_CHARSET };
6084 size_t i;
6085
6086 hdc = GetDC(NULL);
6087
6088 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
6089 {
6090 LOGFONTA lf;
6091 HFONT hfont;
6092 char face_name[LF_FACESIZE];
6093 int ret;
6094
6095 memset(&lf, 0, sizeof lf);
6096 lf.lfFaceName[0] = '\0';
6097 lf.lfCharSet = charset[i];
6098
6099 if (EnumFontFamiliesExA(hdc, &lf, has_vertical_font_proc, 0, 0))
6100 {
6101 skip("Vertical font for charset %u is not installed\n", charset[i]);
6102 continue;
6103 }
6104
6105 hfont = CreateFontIndirectA(&lf);
6106 hfont = SelectObject(hdc, hfont);
6107 memset(face_name, 0, sizeof face_name);
6108 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6109 ok(ret && face_name[0] != '@',
6110 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
6111 DeleteObject(SelectObject(hdc, hfont));
6112
6113 memset(&lf, 0, sizeof lf);
6114 strcpy(lf.lfFaceName, "@");
6115 lf.lfCharSet = charset[i];
6116 hfont = CreateFontIndirectA(&lf);
6117 hfont = SelectObject(hdc, hfont);
6118 memset(face_name, 0, sizeof face_name);
6119 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
6120 ok(ret && face_name[0] == '@',
6121 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
6122 DeleteObject(SelectObject(hdc, hfont));
6123 }
6124 ReleaseDC(NULL, hdc);
6125 }
6126
6127 static int get_font_dpi(const LOGFONTA *lf, int *height)
6128 {
6129 HDC hdc = CreateCompatibleDC(0);
6130 HFONT hfont;
6131 TEXTMETRICA tm;
6132 int ret;
6133
6134 hfont = CreateFontIndirectA(lf);
6135 ok(hfont != 0, "CreateFontIndirect failed\n");
6136
6137 SelectObject(hdc, hfont);
6138 ret = GetTextMetricsA(hdc, &tm);
6139 ok(ret, "GetTextMetrics failed\n");
6140 ret = tm.tmDigitizedAspectX;
6141 if (height) *height = tm.tmHeight;
6142
6143 DeleteDC(hdc);
6144 DeleteObject(hfont);
6145
6146 return ret;
6147 }
6148
6149 static void test_stock_fonts(void)
6150 {
6151 static const int font[] =
6152 {
6153 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
6154 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6155 };
6156 static const struct test_data
6157 {
6158 int charset, weight, height, height_pixels, dpi;
6159 const char face_name[LF_FACESIZE];
6160 WORD lang_id;
6161 } td[][12] =
6162 {
6163 { /* ANSI_FIXED_FONT */
6164 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
6165 { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_HEBREW},
6166 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
6167 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
6168 { 0 }
6169 },
6170 { /* ANSI_VAR_FONT */
6171 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "MS Sans Serif" },
6172 { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "MS Sans Serif" },
6173 { 0 }
6174 },
6175 { /* SYSTEM_FONT */
6176 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6177 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6178 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6179 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6180 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6181 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6182 { 0 }
6183 },
6184 { /* DEVICE_DEFAULT_FONT */
6185 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 18, 96, "System" },
6186 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 22, 120, "System" },
6187 { HANGEUL_CHARSET, FW_NORMAL, 16, 16, 96, "System" },
6188 { HANGEUL_CHARSET, FW_NORMAL, 20, 20, 120, "System" },
6189 { DEFAULT_CHARSET, FW_BOLD, 16, 16, 96, "System" },
6190 { DEFAULT_CHARSET, FW_BOLD, 20, 20, 120, "System" },
6191 { 0 }
6192 },
6193 { /* DEFAULT_GUI_FONT */
6194 { SHIFTJIS_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6195 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 15, 96, "?MS UI Gothic" },
6196 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 18, 120, "?MS UI Gothic" },
6197 { HANGEUL_CHARSET, FW_NORMAL, -12, 15, 96, "?Gulim" },
6198 { HANGEUL_CHARSET, FW_NORMAL, -15, 18, 120, "?Gulim" },
6199 { GB2312_CHARSET, FW_NORMAL, -12, 15, 96, "?SimHei" },
6200 { GB2312_CHARSET, FW_NORMAL, -15, 18, 120, "?SimHei" },
6201 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 15, 96, "?MingLiU" },
6202 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 18, 120, "?MingLiU" },
6203 { DEFAULT_CHARSET, FW_NORMAL, -11, 13, 96, "MS Shell Dlg" },
6204 { DEFAULT_CHARSET, FW_NORMAL, -13, 16, 120, "MS Shell Dlg" },
6205 { 0 }
6206 }
6207 };
6208 int i, j;
6209
6210 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
6211 {
6212 HFONT hfont;
6213 LOGFONTA lf;
6214 int ret, height;
6215
6216 hfont = GetStockObject(font[i]);
6217 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
6218
6219 ret = GetObjectA(hfont, sizeof(lf), &lf);
6220 if (ret != sizeof(lf))
6221 {
6222 /* NT4 */
6223 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
6224 continue;
6225 }
6226
6227 for (j = 0; td[i][j].face_name[0] != 0; j++)
6228 {
6229 if ((lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET) ||
6230 (system_lang_id != td[i][j].lang_id && td[i][j].lang_id != LANG_NEUTRAL) ||
6231 (td[i][j].face_name[0] != '?' && strcmp(lf.lfFaceName, td[i][j].face_name)))
6232 {
6233 continue;
6234 }
6235
6236 ret = get_font_dpi(&lf, &height);
6237 if (ret != td[i][j].dpi)
6238 {
6239 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6240 i, j, lf.lfFaceName, ret, td[i][j].dpi);
6241 continue;
6242 }
6243
6244 /* FIXME: Remove once Wine is fixed */
6245 todo_wine_if (td[i][j].dpi != 96 &&
6246 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6247 ((!strcmp(td[i][j].face_name, "MS Sans Serif") && td[i][j].height == 12) ||
6248 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6249 (!strcmp(td[i][j].face_name, "System") && td[i][j].height > 16)))
6250 ok(height == td[i][j].height_pixels, "%d(%d): expected height %d, got %d\n", i, j, td[i][j].height_pixels, height);
6251
6252 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
6253 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
6254 if (td[i][j].face_name[0] == '?')
6255 {
6256 /* Wine doesn't have this font, skip this case for now.
6257 Actually, the face name is localized on Windows and varies
6258 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6259 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
6260 }
6261 else
6262 {
6263 ok(!strcmp(td[i][j].face_name, lf.lfFaceName), "%d(%d): expected lfFaceName %s, got %s\n", i, j, td[i][j].face_name, lf.lfFaceName);
6264 }
6265 break;
6266 }
6267 }
6268 }
6269
6270 static void test_max_height(void)
6271 {
6272 HDC hdc;
6273 LOGFONTA lf;
6274 HFONT hfont, hfont_old;
6275 TEXTMETRICA tm1, tm;
6276 BOOL r;
6277 LONG invalid_height[] = { -65536, -123456, 123456 };
6278 size_t i;
6279
6280 memset(&tm1, 0, sizeof(tm1));
6281 memset(&lf, 0, sizeof(lf));
6282 strcpy(lf.lfFaceName, "Tahoma");
6283 lf.lfHeight = -1;
6284
6285 hdc = GetDC(NULL);
6286
6287 /* get 1 ppem value */
6288 hfont = CreateFontIndirectA(&lf);
6289 hfont_old = SelectObject(hdc, hfont);
6290 r = GetTextMetricsA(hdc, &tm1);
6291 ok(r, "GetTextMetrics failed\n");
6292 ok(tm1.tmHeight > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6293 ok(tm1.tmAveCharWidth > 0, "expected a positive value, got %d\n", tm1.tmHeight);
6294 DeleteObject(SelectObject(hdc, hfont_old));
6295
6296 /* test the largest value */
6297 lf.lfHeight = -((1 << 16) - 1);
6298 hfont = CreateFontIndirectA(&lf);
6299 hfont_old = SelectObject(hdc, hfont);
6300 memset(&tm, 0, sizeof(tm));
6301 r = GetTextMetricsA(hdc, &tm);
6302 ok(r, "GetTextMetrics failed\n");
6303 ok(tm.tmHeight > tm1.tmHeight,
6304 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6305 ok(tm.tmAveCharWidth > tm1.tmAveCharWidth,
6306 "expected greater than 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6307 DeleteObject(SelectObject(hdc, hfont_old));
6308
6309 /* test an invalid value */
6310 for (i = 0; i < sizeof(invalid_height)/sizeof(invalid_height[0]); i++) {
6311 lf.lfHeight = invalid_height[i];
6312 hfont = CreateFontIndirectA(&lf);
6313 hfont_old = SelectObject(hdc, hfont);
6314 memset(&tm, 0, sizeof(tm));
6315 r = GetTextMetricsA(hdc, &tm);
6316 ok(r, "GetTextMetrics failed\n");
6317 ok(tm.tmHeight == tm1.tmHeight,
6318 "expected 1 ppem value (%d), got %d\n", tm1.tmHeight, tm.tmHeight);
6319 ok(tm.tmAveCharWidth == tm1.tmAveCharWidth,
6320 "expected 1 ppem value (%d), got %d\n", tm1.tmAveCharWidth, tm.tmAveCharWidth);
6321 DeleteObject(SelectObject(hdc, hfont_old));
6322 }
6323
6324 ReleaseDC(NULL, hdc);
6325 return;
6326 }
6327
6328 static void test_vertical_order(void)
6329 {
6330 struct enum_font_data efd;
6331 LOGFONTA lf;
6332 HDC hdc;
6333 int i, j;
6334
6335 hdc = CreateCompatibleDC(0);
6336 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6337
6338 memset(&lf, 0, sizeof(lf));
6339 lf.lfCharSet = DEFAULT_CHARSET;
6340 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
6341 lf.lfHeight = 16;
6342 lf.lfWidth = 16;
6343 lf.lfQuality = DEFAULT_QUALITY;
6344 lf.lfItalic = FALSE;
6345 lf.lfWeight = FW_DONTCARE;
6346 memset( &efd, 0, sizeof(efd) );
6347 EnumFontFamiliesExA(hdc, &lf, enum_font_data_proc, (LPARAM)&efd, 0);
6348 for (i = 0; i < efd.total; i++)
6349 {
6350 if (efd.lf[i].lfFaceName[0] != '@') continue;
6351 for (j = 0; j < efd.total; j++)
6352 {
6353 if (!strcmp(efd.lf[i].lfFaceName + 1, efd.lf[j].lfFaceName))
6354 {
6355 ok(i > j,"Found vertical font %s before its horizontal version\n", efd.lf[i].lfFaceName);
6356 break;
6357 }
6358 }
6359 }
6360 heap_free( efd.lf );
6361 DeleteDC( hdc );
6362 }
6363
6364 static void test_GetCharWidth32(void)
6365 {
6366 BOOL ret;
6367 HDC hdc;
6368 LOGFONTA lf;
6369 HFONT hfont;
6370 INT bufferA;
6371 INT bufferW;
6372 HWND hwnd;
6373
6374 if (!pGetCharWidth32A || !pGetCharWidth32W)
6375 {
6376 win_skip("GetCharWidth32A/W not available on this platform\n");
6377 return;
6378 }
6379
6380 memset(&lf, 0, sizeof(lf));
6381 strcpy(lf.lfFaceName, "System");
6382 lf.lfHeight = 20;
6383
6384 hfont = CreateFontIndirectA(&lf);
6385 hdc = GetDC(0);
6386 hfont = SelectObject(hdc, hfont);
6387
6388 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6389 ok(ret, "GetCharWidth32W should have succeeded\n");
6390 ret = pGetCharWidth32A(hdc, 'a', 'a', &bufferA);
6391 ok(ret, "GetCharWidth32A should have succeeded\n");
6392 ok (bufferA == bufferW, "Widths should be the same\n");
6393 ok (bufferA > 0," Width should be greater than zero\n");
6394
6395 hfont = SelectObject(hdc, hfont);
6396 DeleteObject(hfont);
6397 ReleaseDC(NULL, hdc);
6398
6399 memset(&lf, 0, sizeof(lf));
6400 strcpy(lf.lfFaceName, "Tahoma");
6401 lf.lfHeight = 20;
6402
6403 hfont = CreateFontIndirectA(&lf);
6404 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
6405 0, 0, 0, NULL);
6406 hdc = GetDC(hwnd);
6407 SetMapMode( hdc, MM_ANISOTROPIC );
6408 SelectObject(hdc, hfont);
6409
6410 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6411 ok(ret, "GetCharWidth32W should have succeeded\n");
6412 ok (bufferW > 0," Width should be greater than zero\n");
6413 SetWindowExtEx(hdc, -1,-1,NULL);
6414 SetGraphicsMode(hdc, GM_COMPATIBLE);
6415 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6416 ok(ret, "GetCharWidth32W should have succeeded\n");
6417 ok (bufferW > 0," Width should be greater than zero\n");
6418 SetGraphicsMode(hdc, GM_ADVANCED);
6419 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6420 ok(ret, "GetCharWidth32W should have succeeded\n");
6421 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6422 SetWindowExtEx(hdc, 1,1,NULL);
6423 SetGraphicsMode(hdc, GM_COMPATIBLE);
6424 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6425 ok(ret, "GetCharWidth32W should have succeeded\n");
6426 ok (bufferW > 0," Width should be greater than zero\n");
6427 SetGraphicsMode(hdc, GM_ADVANCED);
6428 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6429 ok(ret, "GetCharWidth32W should have succeeded\n");
6430 ok (bufferW > 0," Width should be greater than zero\n");
6431
6432 ReleaseDC(hwnd, hdc);
6433 DestroyWindow(hwnd);
6434
6435 hwnd = CreateWindowExA(WS_EX_LAYOUTRTL, "static", "", WS_POPUP, 0,0,100,100,
6436 0, 0, 0, NULL);
6437 hdc = GetDC(hwnd);
6438 SetMapMode( hdc, MM_ANISOTROPIC );
6439 SelectObject(hdc, hfont);
6440
6441 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6442 ok(ret, "GetCharWidth32W should have succeeded\n");
6443 ok (bufferW > 0," Width should be greater than zero\n");
6444 SetWindowExtEx(hdc, -1,-1,NULL);
6445 SetGraphicsMode(hdc, GM_COMPATIBLE);
6446 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6447 ok(ret, "GetCharWidth32W should have succeeded\n");
6448 ok (bufferW > 0," Width should be greater than zero\n");
6449 SetGraphicsMode(hdc, GM_ADVANCED);
6450 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6451 ok(ret, "GetCharWidth32W should have succeeded\n");
6452 ok (bufferW > 0," Width should be greater than zero\n");
6453 SetWindowExtEx(hdc, 1,1,NULL);
6454 SetGraphicsMode(hdc, GM_COMPATIBLE);
6455 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6456 ok(ret, "GetCharWidth32W should have succeeded\n");
6457 ok (bufferW > 0," Width should be greater than zero\n");
6458 SetGraphicsMode(hdc, GM_ADVANCED);
6459 ret = pGetCharWidth32W(hdc, 'a', 'a', &bufferW);
6460 ok(ret, "GetCharWidth32W should have succeeded\n");
6461 todo_wine ok (bufferW > 0," Width should be greater than zero\n");
6462
6463 ReleaseDC(hwnd, hdc);
6464 DestroyWindow(hwnd);
6465 DeleteObject(hfont);
6466 }
6467
6468 static void test_fake_bold_font(void)
6469 {
6470 static const MAT2 x2_mat = { {0,2}, {0,0}, {0,0}, {0,2} };
6471 HDC hdc;
6472 LOGFONTA lf;
6473 BOOL ret;
6474 struct glyph_data {
6475 TEXTMETRICA tm;
6476 ABC abc;
6477 INT w;
6478 GLYPHMETRICS gm;
6479 } data[2];
6480 int i;
6481 DWORD r;
6482
6483 if (!pGetCharWidth32A || !pGetCharABCWidthsA) {
6484 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6485 return;
6486 }
6487
6488 /* Test outline font */
6489 memset(&lf, 0, sizeof(lf));
6490 strcpy(lf.lfFaceName, "Wingdings");
6491 lf.lfCharSet = SYMBOL_CHARSET;
6492
6493 hdc = GetDC(NULL);
6494
6495 for (i = 0; i <= 1; i++)
6496 {
6497 HFONT hfont, hfont_old;
6498
6499 lf.lfWeight = i ? FW_BOLD : FW_NORMAL;
6500 hfont = CreateFontIndirectA(&lf);
6501 hfont_old = SelectObject(hdc, hfont);
6502
6503 ret = GetTextMetricsA(hdc, &data[i].tm);
6504 ok(ret, "got %d\n", ret);
6505 ret = pGetCharABCWidthsA(hdc, 0x76, 0x76, &data[i].abc);
6506 ok(ret, "got %d\n", ret);
6507 data[i].w = data[i].abc.abcA + data[i].abc.abcB + data[i].abc.abcC;
6508 r = GetGlyphOutlineA(hdc, 0x76, GGO_METRICS, &data[i].gm, 0, NULL, &x2_mat);
6509 ok(r != GDI_ERROR, "got %d\n", ret);
6510
6511 SelectObject(hdc, hfont_old);
6512 DeleteObject(hfont);
6513 }
6514 ReleaseDC(NULL, hdc);
6515
6516 /* compare results (outline) */
6517 ok(data[0].tm.tmHeight == data[1].tm.tmHeight,
6518 "expected %d, got %d\n", data[0].tm.tmHeight, data[1].tm.tmHeight);
6519 ok(data[0].tm.tmAscent == data[1].tm.tmAscent,
6520 "expected %d, got %d\n", data[0].tm.tmAscent, data[1].tm.tmAscent);
6521 ok(data[0].tm.tmDescent == data[1].tm.tmDescent,
6522 "expected %d, got %d\n", data[0].tm.tmDescent, data[1].tm.tmDescent);
6523 ok(data[0].tm.tmAveCharWidth + 1 == data[1].tm.tmAveCharWidth,
6524 "expected %d, got %d\n", data[0].tm.tmAveCharWidth + 1, data[1].tm.tmAveCharWidth);
6525 ok(data[0].tm.tmMaxCharWidth + 1 == data[1].tm.tmMaxCharWidth,
6526 "expected %d, got %d\n", data[0].tm.tmMaxCharWidth + 1, data[1].tm.tmMaxCharWidth);
6527 ok(data[0].tm.tmOverhang == data[1].tm.tmOverhang,
6528 "expected %d, got %d\n", data[0].tm.tmOverhang, data[1].tm.tmOverhang);
6529 ok(data[0].w + 1 == data[1].w,
6530 "expected %d, got %d\n", data[0].w + 1, data[1].w);
6531
6532 ok(data[0].gm.gmCellIncX + 1 == data[1].gm.gmCellIncX,
6533 "expected %d, got %d\n", data[0].gm.gmCellIncX + 1, data[1].gm.gmCellIncX);
6534 ok(data[0].gm.gmCellIncY == data[1].gm.gmCellIncY,
6535 "expected %d, got %d\n", data[0].gm.gmCellIncY, data[1].gm.gmCellIncY);
6536 }
6537
6538 static void test_bitmap_font_glyph_index(void)
6539 {
6540 const WCHAR text[] = {'#','!','/','b','i','n','/','s','h',0};
6541 const struct {
6542 LPCSTR face;
6543 BYTE charset;
6544 } bitmap_font_list[] = {
6545 { "Courier", ANSI_CHARSET },
6546 { "Small Fonts", ANSI_CHARSET },
6547 { "Fixedsys", DEFAULT_CHARSET },
6548 { "System", DEFAULT_CHARSET }
6549 };
6550 HDC hdc;
6551 LOGFONTA lf;
6552 HFONT hFont;
6553 CHAR facename[LF_FACESIZE];
6554 BITMAPINFO bmi;
6555 HBITMAP hBmp[2];
6556 void *pixels[2];
6557 int i, j;
6558 DWORD ret;
6559 BITMAP bmp;
6560 TEXTMETRICA tm;
6561 CHARSETINFO ci;
6562 BYTE chr = '\xA9';
6563
6564 if (!pGetGlyphIndicesW || !pGetGlyphIndicesA) {
6565 win_skip("GetGlyphIndices is unavailable\n");
6566 return;
6567 }
6568
6569 hdc = CreateCompatibleDC(0);
6570 ok(hdc != NULL, "CreateCompatibleDC failed\n");
6571
6572 memset(&bmi, 0, sizeof(bmi));
6573 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
6574 bmi.bmiHeader.biBitCount = 32;
6575 bmi.bmiHeader.biPlanes = 1;
6576 bmi.bmiHeader.biWidth = 128;
6577 bmi.bmiHeader.biHeight = 32;
6578 bmi.bmiHeader.biCompression = BI_RGB;
6579
6580 for (i = 0; i < sizeof(bitmap_font_list)/sizeof(bitmap_font_list[0]); i++) {
6581 memset(&lf, 0, sizeof(lf));
6582 lf.lfCharSet = bitmap_font_list[i].charset;
6583 strcpy(lf.lfFaceName, bitmap_font_list[i].face);
6584 hFont = CreateFontIndirectA(&lf);
6585 ok(hFont != NULL, "Can't create font (%s:%d)\n", lf.lfFaceName, lf.lfCharSet);
6586 hFont = SelectObject(hdc, hFont);
6587 ret = GetTextMetricsA(hdc, &tm);
6588 ok(ret, "GetTextMetric failed\n");
6589 ret = GetTextFaceA(hdc, sizeof(facename), facename);
6590 ok(ret, "GetTextFace failed\n");
6591 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) {
6592 skip("TrueType font (%s) was selected for \"%s\"\n", facename, bitmap_font_list[i].face);
6593 continue;
6594 }
6595 if (lstrcmpiA(facename, lf.lfFaceName) != 0) {
6596 skip("expected %s, got %s\n", lf.lfFaceName, facename);
6597 continue;
6598 }
6599
6600 for (j = 0; j < 2; j++) {
6601 HBITMAP hBmpPrev;
6602 hBmp[j] = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels[j], NULL, 0);
6603 ok(hBmp[j] != NULL, "Can't create DIB\n");
6604 hBmpPrev = SelectObject(hdc, hBmp[j]);
6605 switch (j) {
6606 case 0:
6607 ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
6608 break;
6609 case 1:
6610 {
6611 int len = lstrlenW(text);
6612 LPWORD indices = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WORD));
6613 ret = pGetGlyphIndicesW(hdc, text, len, indices, 0);
6614 ok(ret, "GetGlyphIndices failed\n");
6615 ok(memcmp(indices, text, sizeof(WORD) * len) == 0,
6616 "Glyph indices and text are different for %s:%d\n", lf.lfFaceName, tm.tmCharSet);
6617 ret = ExtTextOutW(hdc, 0, 0, ETO_GLYPH_INDEX, NULL, indices, len, NULL);
6618 HeapFree(GetProcessHeap(), 0, indices);
6619 break;
6620 }
6621 }
6622 ok(ret, "ExtTextOutW failed\n");
6623 SelectObject(hdc, hBmpPrev);
6624 }
6625
6626 GetObjectA(hBmp[0], sizeof(bmp), &bmp);
6627 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6628 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6629
6630 ret = TranslateCharsetInfo((LPDWORD)(DWORD_PTR)tm.tmCharSet, &ci, TCI_SRCCHARSET);
6631 if (!ret) {
6632 skip("Can't get charset info for (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6633 goto next;
6634 }
6635 if (IsDBCSLeadByteEx(ci.ciACP, chr)) {
6636 skip("High-ascii character is not defined in codepage %d\n", ci.ciACP);
6637 goto next;
6638 }
6639
6640 for (j = 0; j < 2; j++) {
6641 HBITMAP hBmpPrev;
6642 WORD code;
6643 hBmpPrev = SelectObject(hdc, hBmp[j]);
6644 switch (j) {
6645 case 0:
6646 ret = ExtTextOutA(hdc, 100, 0, 0, NULL, (LPCSTR)&chr, 1, NULL);
6647 break;
6648 case 1:
6649 ret = pGetGlyphIndicesA(hdc, (LPCSTR)&chr, 1, &code, 0);
6650 ok(ret, "GetGlyphIndices failed\n");
6651 ok(code == chr, "expected %02x, got %02x (%s:%d)\n", chr, code, lf.lfFaceName, tm.tmCharSet);
6652 ret = ExtTextOutA(hdc, 100, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&code, 1, NULL);
6653 break;
6654 }
6655 ok(ret, "ExtTextOutA failed\n");
6656 SelectObject(hdc, hBmpPrev);
6657 }
6658
6659 ok(memcmp(pixels[0], pixels[1], bmp.bmHeight * bmp.bmWidthBytes) == 0,
6660 "Images are different (%s:%d)\n", lf.lfFaceName, tm.tmCharSet);
6661 next:
6662 for (j = 0; j < 2; j++)
6663 DeleteObject(hBmp[j]);
6664 hFont = SelectObject(hdc, hFont);
6665 DeleteObject(hFont);
6666 }
6667
6668 DeleteDC(hdc);
6669 }
6670
6671 static void test_GetCharWidthI(void)
6672 {
6673 static const char *teststr = "wine ";
6674 HFONT hfont, prev_hfont;
6675 WORD glyphs[5];
6676 INT widths[5];
6677 LOGFONTA lf;
6678 ABC abc[5];
6679 int len, i;
6680 DWORD nb;
6681 BOOL ret;
6682 HDC hdc;
6683
6684 memset(&lf, 0, sizeof(lf));
6685 strcpy(lf.lfFaceName, "Tahoma");
6686 lf.lfHeight = -20;
6687
6688 hdc = GetDC(0);
6689
6690 hfont = CreateFontIndirectA(&lf);
6691 prev_hfont = SelectObject(hdc, hfont);
6692
6693 len = strlen(teststr);
6694 nb = GetGlyphIndicesA(hdc, teststr, len, glyphs, 0);
6695 ok(nb == len, "\n");
6696
6697 memset(abc, 0xcc, sizeof(abc));
6698 ret = GetCharABCWidthsI(hdc, 0, len, glyphs, abc);
6699 ok(ret, "GetCharABCWidthsI failed\n");
6700
6701 memset(widths, 0xcc, sizeof(widths));
6702 ret = GetCharWidthI(hdc, 0, len, glyphs, widths);
6703 ok(ret, "GetCharWidthI failed\n");
6704
6705 for (i = 0; i < len; i++)
6706 ok(widths[i] == abc[i].abcA + abc[i].abcB + abc[i].abcC, "%u, glyph %u, got width %d\n",
6707 i, glyphs[i], widths[i]);
6708
6709 DeleteObject(SelectObject(hdc, prev_hfont));
6710 ReleaseDC(0, hdc);
6711 }
6712
6713 START_TEST(font)
6714 {
6715 init();
6716
6717 test_stock_fonts();
6718 test_logfont();
6719 test_bitmap_font();
6720 test_outline_font();
6721 test_bitmap_font_metrics();
6722 test_GdiGetCharDimensions();
6723 test_GetCharABCWidths();
6724 test_text_extents();
6725 test_GetGlyphIndices();
6726 test_GetKerningPairs();
6727 test_GetOutlineTextMetrics();
6728 test_SetTextJustification();
6729 test_font_charset();
6730 test_GdiGetCodePage();
6731 test_GetFontUnicodeRanges();
6732 test_nonexistent_font();
6733 test_orientation();
6734 test_height_selection();
6735 test_AddFontMemResource();
6736 test_EnumFonts();
6737 test_EnumFonts_subst();
6738
6739 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6740 * I'd like to avoid them in this test.
6741 */
6742 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
6743 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
6744 if (is_truetype_font_installed("Arial Black") &&
6745 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6746 {
6747 test_EnumFontFamilies("", ANSI_CHARSET);
6748 test_EnumFontFamilies("", SYMBOL_CHARSET);
6749 test_EnumFontFamilies("", DEFAULT_CHARSET);
6750 }
6751 else
6752 skip("Arial Black or Symbol/Wingdings is not installed\n");
6753 test_EnumFontFamiliesEx_default_charset();
6754 test_GetTextMetrics();
6755 test_RealizationInfo();
6756 test_GetTextFace();
6757 test_GetGlyphOutline();
6758 test_GetTextMetrics2("Tahoma", -11);
6759 test_GetTextMetrics2("Tahoma", -55);
6760 test_GetTextMetrics2("Tahoma", -110);
6761 test_GetTextMetrics2("Arial", -11);
6762 test_GetTextMetrics2("Arial", -55);
6763 test_GetTextMetrics2("Arial", -110);
6764 test_GetCharacterPlacement();
6765 test_CreateFontIndirect();
6766 test_CreateFontIndirectEx();
6767 test_oemcharset();
6768 test_fullname();
6769 test_fullname2();
6770 test_east_asian_font_selection();
6771 test_max_height();
6772 test_vertical_order();
6773 test_GetCharWidth32();
6774 test_fake_bold_font();
6775 test_bitmap_font_glyph_index();
6776 test_GetCharWidthI();
6777
6778 /* These tests should be last test until RemoveFontResource
6779 * is properly implemented.
6780 */
6781 test_vertical_font();
6782 test_CreateScalableFontResource();
6783 }