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