9b2028183dfa3bd14b116c82138642153e65c314
[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) (abs((a) - (b)) <= 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 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
46 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
48 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
49 LPINT nfit, LPINT dxs, LPSIZE size );
50 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
51 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
52 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
53 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
54 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
55 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
56
57 static HMODULE hgdi32 = 0;
58 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
59 static WORD system_lang_id;
60
61 static void init(void)
62 {
63 hgdi32 = GetModuleHandleA("gdi32.dll");
64
65 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
66 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
67 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
68 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
69 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
70 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
71 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
72 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
73 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
74 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
75 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
76 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
77 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
78 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
79 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
80 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
81
82 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
83 }
84
85 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
86 {
87 if (type != TRUETYPE_FONTTYPE) return 1;
88
89 return 0;
90 }
91
92 static BOOL is_truetype_font_installed(const char *name)
93 {
94 HDC hdc = GetDC(0);
95 BOOL ret = FALSE;
96
97 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
98 ret = TRUE;
99
100 ReleaseDC(0, hdc);
101 return ret;
102 }
103
104 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
105 {
106 return 0;
107 }
108
109 static BOOL is_font_installed(const char *name)
110 {
111 HDC hdc = GetDC(0);
112 BOOL ret = FALSE;
113
114 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
115 ret = TRUE;
116
117 ReleaseDC(0, hdc);
118 return ret;
119 }
120
121 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
122 {
123 LOGFONTA getobj_lf;
124 int ret, minlen = 0;
125
126 if (!hfont)
127 return;
128
129 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
130 /* NT4 tries to be clever and only returns the minimum length */
131 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
132 minlen++;
133 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
134 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
135 ok(lf->lfHeight == getobj_lf.lfHeight ||
136 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
137 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
138 ok(lf->lfWidth == getobj_lf.lfWidth ||
139 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
140 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
141 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
142 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
143 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
144 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
145 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
146 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
147 ok(lf->lfWeight == getobj_lf.lfWeight ||
148 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
149 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
150 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
151 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
152 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
153 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
154 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
155 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
156 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
157 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
158 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
159 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
160 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
161 }
162
163 static HFONT create_font(const char* test, const LOGFONTA* lf)
164 {
165 HFONT hfont = CreateFontIndirectA(lf);
166 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
167 if (hfont)
168 check_font(test, lf, hfont);
169 return hfont;
170 }
171
172 static void test_logfont(void)
173 {
174 LOGFONTA lf;
175 HFONT hfont;
176
177 memset(&lf, 0, sizeof lf);
178
179 lf.lfCharSet = ANSI_CHARSET;
180 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
181 lf.lfWeight = FW_DONTCARE;
182 lf.lfHeight = 16;
183 lf.lfWidth = 16;
184 lf.lfQuality = DEFAULT_QUALITY;
185
186 lstrcpyA(lf.lfFaceName, "Arial");
187 hfont = create_font("Arial", &lf);
188 DeleteObject(hfont);
189
190 memset(&lf, 'A', sizeof(lf));
191 hfont = CreateFontIndirectA(&lf);
192 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
193
194 lf.lfFaceName[LF_FACESIZE - 1] = 0;
195 check_font("AAA...", &lf, hfont);
196 DeleteObject(hfont);
197 }
198
199 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
200 {
201 if (type & RASTER_FONTTYPE)
202 {
203 LOGFONT *lf = (LOGFONT *)lParam;
204 *lf = *elf;
205 return 0; /* stop enumeration */
206 }
207
208 return 1; /* continue enumeration */
209 }
210
211 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
212 {
213 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
214 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
215 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
216 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
217 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
218 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
219 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
220 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
221 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
222 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
223 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
224 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
225 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
226 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
227 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
228 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
229 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
230 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
231 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
232 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
233 }
234
235 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
236 LONG lfWidth, const char *test_str,
237 INT test_str_len, const TEXTMETRICA *tm_orig,
238 const SIZE *size_orig, INT width_of_A_orig,
239 INT scale_x, INT scale_y)
240 {
241 LOGFONTA lf;
242 OUTLINETEXTMETRIC otm;
243 TEXTMETRICA tm;
244 SIZE size;
245 INT width_of_A, cx, cy;
246 UINT ret;
247
248 if (!hfont)
249 return;
250
251 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
252
253 GetObjectA(hfont, sizeof(lf), &lf);
254
255 if (GetOutlineTextMetricsA(hdc, 0, NULL))
256 {
257 otm.otmSize = sizeof(otm) / 2;
258 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259 ok(ret == sizeof(otm)/2 /* XP */ ||
260 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
261
262 memset(&otm, 0x1, sizeof(otm));
263 otm.otmSize = sizeof(otm);
264 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
265 ok(ret == sizeof(otm) /* XP */ ||
266 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
267
268 memset(&tm, 0x2, sizeof(tm));
269 ret = GetTextMetricsA(hdc, &tm);
270 ok(ret, "GetTextMetricsA failed\n");
271 /* the structure size is aligned */
272 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
273 {
274 ok(0, "tm != otm\n");
275 compare_tm(&tm, &otm.otmTextMetrics);
276 }
277
278 tm = otm.otmTextMetrics;
279 if (0) /* these metrics are scaled too, but with rounding errors */
280 {
281 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
282 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
283 }
284 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
285 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
286 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
287 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
288 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
289 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
290 }
291 else
292 {
293 ret = GetTextMetricsA(hdc, &tm);
294 ok(ret, "GetTextMetricsA failed\n");
295 }
296
297 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
298 cy = tm.tmHeight / tm_orig->tmHeight;
299 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
300 lfHeight, scale_x, scale_y, cx, cy);
301 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
302 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
303 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
304 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
305 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
306
307 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
308 if (lf.lfHeight)
309 {
310 if (lf.lfWidth)
311 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
312 }
313 else
314 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
315
316 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
317
318 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
319 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
320
321 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
322
323 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);
324 }
325
326 /* Test how GDI scales bitmap font metrics */
327 static void test_bitmap_font(void)
328 {
329 static const char test_str[11] = "Test String";
330 HDC hdc;
331 LOGFONTA bitmap_lf;
332 HFONT hfont, old_hfont;
333 TEXTMETRICA tm_orig;
334 SIZE size_orig;
335 INT ret, i, width_orig, height_orig, scale, lfWidth;
336
337 if(!winetest_interactive)
338 {
339 skip("reactos bug 5401: Skipping bitmap font tests!\n");
340 return;
341 }
342
343 hdc = CreateCompatibleDC(0);
344
345 /* "System" has only 1 pixel size defined, otherwise the test breaks */
346 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
347 if (ret)
348 {
349 ReleaseDC(0, hdc);
350 trace("no bitmap fonts were found, skipping the test\n");
351 return;
352 }
353
354 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
355
356 height_orig = bitmap_lf.lfHeight;
357 lfWidth = bitmap_lf.lfWidth;
358
359 hfont = create_font("bitmap", &bitmap_lf);
360 old_hfont = SelectObject(hdc, hfont);
361 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
362 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
363 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
364 SelectObject(hdc, old_hfont);
365 DeleteObject(hfont);
366
367 bitmap_lf.lfHeight = 0;
368 bitmap_lf.lfWidth = 4;
369 hfont = create_font("bitmap", &bitmap_lf);
370 old_hfont = SelectObject(hdc, hfont);
371 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
372 SelectObject(hdc, old_hfont);
373 DeleteObject(hfont);
374
375 bitmap_lf.lfHeight = height_orig;
376 bitmap_lf.lfWidth = lfWidth;
377
378 /* test fractional scaling */
379 for (i = 1; i <= height_orig * 6; i++)
380 {
381 INT nearest_height;
382
383 bitmap_lf.lfHeight = i;
384 hfont = create_font("fractional", &bitmap_lf);
385 scale = (i + height_orig - 1) / height_orig;
386 nearest_height = scale * height_orig;
387 /* Only jump to the next height if the difference <= 25% original height */
388 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
389 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
390 so we'll not test this particular height. */
391 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
392 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
393 old_hfont = SelectObject(hdc, hfont);
394 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
395 SelectObject(hdc, old_hfont);
396 DeleteObject(hfont);
397 }
398
399 /* test integer scaling 3x2 */
400 bitmap_lf.lfHeight = height_orig * 2;
401 bitmap_lf.lfWidth *= 3;
402 hfont = create_font("3x2", &bitmap_lf);
403 old_hfont = SelectObject(hdc, hfont);
404 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
405 SelectObject(hdc, old_hfont);
406 DeleteObject(hfont);
407
408 /* test integer scaling 3x3 */
409 bitmap_lf.lfHeight = height_orig * 3;
410 bitmap_lf.lfWidth = 0;
411 hfont = create_font("3x3", &bitmap_lf);
412 old_hfont = SelectObject(hdc, hfont);
413 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
414 SelectObject(hdc, old_hfont);
415 DeleteObject(hfont);
416
417 DeleteDC(hdc);
418 }
419
420 /* Test how GDI scales outline font metrics */
421 static void test_outline_font(void)
422 {
423 static const char test_str[11] = "Test String";
424 HDC hdc, hdc_2;
425 LOGFONTA lf;
426 HFONT hfont, old_hfont, old_hfont_2;
427 OUTLINETEXTMETRICA otm;
428 SIZE size_orig;
429 INT width_orig, height_orig, lfWidth;
430 XFORM xform;
431 GLYPHMETRICS gm;
432 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
433 POINT pt;
434 INT ret;
435
436 if(!winetest_interactive)
437 {
438 skip("reactos bug 5401: Skipping outline font tests!\n");
439 return;
440 }
441
442 if (!is_truetype_font_installed("Arial"))
443 {
444 skip("Arial is not installed\n");
445 return;
446 }
447
448 hdc = CreateCompatibleDC(0);
449
450 memset(&lf, 0, sizeof(lf));
451 strcpy(lf.lfFaceName, "Arial");
452 lf.lfHeight = 72;
453 hfont = create_font("outline", &lf);
454 old_hfont = SelectObject(hdc, hfont);
455 otm.otmSize = sizeof(otm);
456 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
457 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
458 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
459
460 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
461 SelectObject(hdc, old_hfont);
462 DeleteObject(hfont);
463
464 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
465 lf.lfHeight = otm.otmEMSquare;
466 lf.lfHeight = -lf.lfHeight;
467 hfont = create_font("outline", &lf);
468 old_hfont = SelectObject(hdc, hfont);
469 otm.otmSize = sizeof(otm);
470 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
471 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
472 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
473 SelectObject(hdc, old_hfont);
474 DeleteObject(hfont);
475
476 height_orig = otm.otmTextMetrics.tmHeight;
477 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
478
479 /* test integer scaling 3x2 */
480 lf.lfHeight = height_orig * 2;
481 lf.lfWidth = lfWidth * 3;
482 hfont = create_font("3x2", &lf);
483 old_hfont = SelectObject(hdc, hfont);
484 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
485 SelectObject(hdc, old_hfont);
486 DeleteObject(hfont);
487
488 /* test integer scaling 3x3 */
489 lf.lfHeight = height_orig * 3;
490 lf.lfWidth = lfWidth * 3;
491 hfont = create_font("3x3", &lf);
492 old_hfont = SelectObject(hdc, hfont);
493 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
494 SelectObject(hdc, old_hfont);
495 DeleteObject(hfont);
496
497 /* test integer scaling 1x1 */
498 lf.lfHeight = height_orig * 1;
499 lf.lfWidth = lfWidth * 1;
500 hfont = create_font("1x1", &lf);
501 old_hfont = SelectObject(hdc, hfont);
502 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
503 SelectObject(hdc, old_hfont);
504 DeleteObject(hfont);
505
506 /* test integer scaling 1x1 */
507 lf.lfHeight = height_orig;
508 lf.lfWidth = 0;
509 hfont = create_font("1x1", &lf);
510 old_hfont = SelectObject(hdc, hfont);
511 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
512
513 /* with an identity matrix */
514 memset(&gm, 0, sizeof(gm));
515 SetLastError(0xdeadbeef);
516 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
517 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
518 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
519 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
520 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
521 /* with a custom matrix */
522 memset(&gm, 0, sizeof(gm));
523 SetLastError(0xdeadbeef);
524 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
525 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
526 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
527 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
528 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
529
530 /* Test that changing the DC transformation affects only the font
531 * selected on this DC and doesn't affect the same font selected on
532 * another DC.
533 */
534 hdc_2 = CreateCompatibleDC(0);
535 old_hfont_2 = SelectObject(hdc_2, hfont);
536 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
537
538 SetMapMode(hdc, MM_ANISOTROPIC);
539
540 /* font metrics on another DC should be unchanged */
541 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
542
543 /* test restrictions of compatibility mode GM_COMPATIBLE */
544 /* part 1: rescaling only X should not change font scaling on screen.
545 So compressing the X axis by 2 is not done, and this
546 appears as X scaling of 2 that no one requested. */
547 SetWindowExtEx(hdc, 100, 100, NULL);
548 SetViewportExtEx(hdc, 50, 100, NULL);
549 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
550 /* font metrics on another DC should be unchanged */
551 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
552
553 /* part 2: rescaling only Y should change font scaling.
554 As also X is scaled by a factor of 2, but this is not
555 requested by the DC transformation, we get a scaling factor
556 of 2 in the X coordinate. */
557 SetViewportExtEx(hdc, 100, 200, NULL);
558 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
559 /* font metrics on another DC should be unchanged */
560 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
561
562 /* restore scaling */
563 SetMapMode(hdc, MM_TEXT);
564
565 /* font metrics on another DC should be unchanged */
566 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
567
568 SelectObject(hdc_2, old_hfont_2);
569 DeleteDC(hdc_2);
570
571 if (!SetGraphicsMode(hdc, GM_ADVANCED))
572 {
573 SelectObject(hdc, old_hfont);
574 DeleteObject(hfont);
575 DeleteDC(hdc);
576 skip("GM_ADVANCED is not supported on this platform\n");
577 return;
578 }
579
580 xform.eM11 = 20.0f;
581 xform.eM12 = 0.0f;
582 xform.eM21 = 0.0f;
583 xform.eM22 = 20.0f;
584 xform.eDx = 0.0f;
585 xform.eDy = 0.0f;
586
587 SetLastError(0xdeadbeef);
588 ret = SetWorldTransform(hdc, &xform);
589 ok(ret, "SetWorldTransform error %u\n", GetLastError());
590
591 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
592
593 /* with an identity matrix */
594 memset(&gm, 0, sizeof(gm));
595 SetLastError(0xdeadbeef);
596 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
597 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
598 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
599 pt.x = width_orig; pt.y = 0;
600 LPtoDP(hdc, &pt, 1);
601 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
602 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
603 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
604 /* with a custom matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
611 LPtoDP(hdc, &pt, 1);
612 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
613 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
614 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
615
616 SetLastError(0xdeadbeef);
617 ret = SetMapMode(hdc, MM_LOMETRIC);
618 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
619
620 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621
622 /* with an identity matrix */
623 memset(&gm, 0, sizeof(gm));
624 SetLastError(0xdeadbeef);
625 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
626 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
627 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
628 pt.x = width_orig; pt.y = 0;
629 LPtoDP(hdc, &pt, 1);
630 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
631 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
632 /* with a custom matrix */
633 memset(&gm, 0, sizeof(gm));
634 SetLastError(0xdeadbeef);
635 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
636 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
637 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
638 pt.x = width_orig; pt.y = 0;
639 LPtoDP(hdc, &pt, 1);
640 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
641 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
642
643 SetLastError(0xdeadbeef);
644 ret = SetMapMode(hdc, MM_TEXT);
645 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
646
647 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
648
649 /* with an identity matrix */
650 memset(&gm, 0, sizeof(gm));
651 SetLastError(0xdeadbeef);
652 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
653 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
654 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
655 pt.x = width_orig; pt.y = 0;
656 LPtoDP(hdc, &pt, 1);
657 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
658 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
659 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
660 /* with a custom matrix */
661 memset(&gm, 0, sizeof(gm));
662 SetLastError(0xdeadbeef);
663 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
664 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
665 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
666 pt.x = width_orig; pt.y = 0;
667 LPtoDP(hdc, &pt, 1);
668 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
669 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
670 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
671
672 SelectObject(hdc, old_hfont);
673 DeleteObject(hfont);
674 DeleteDC(hdc);
675 }
676
677 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
678 {
679 LOGFONT *lf = (LOGFONT *)lParam;
680
681 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
682 {
683 *lf = *elf;
684 return 0; /* stop enumeration */
685 }
686 return 1; /* continue enumeration */
687 }
688
689 static BOOL is_CJK(void)
690 {
691 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
692 }
693
694 #define FH_SCALE 0x80000000
695 static void test_bitmap_font_metrics(void)
696 {
697 static const struct font_data
698 {
699 const char face_name[LF_FACESIZE];
700 int weight, height, ascent, descent, int_leading, ext_leading;
701 int ave_char_width, max_char_width, dpi;
702 BYTE first_char, last_char, def_char, break_char;
703 DWORD ansi_bitfield;
704 WORD skip_lang_id;
705 int scaled_height;
706 } fd[] =
707 {
708 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
709 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
710 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
711 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
712 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
713 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
714 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
715 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
716 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 16 },
717 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
718
719 { "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 },
720 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
721 { "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 },
722 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
723 { "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 },
724 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
725 { "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 },
726 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
727 { "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 },
728 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
729
730 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
731 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
732 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
733 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
734 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
735 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
736 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
737 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
738 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
739 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
740 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
741 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
742 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
743 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
744 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
745 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
746
747 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
748 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
749 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
750 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
751 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
752 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
753 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
754 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
755 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
756 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
757 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
758 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
759
760 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
761 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
762 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
763 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
764 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
765 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
766 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
767 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
768 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
769 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
770 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
771 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
772 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
773 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
774 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
775 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
776 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
777
778 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
779 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
780 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
781 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
782 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
783 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
784 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
785 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
786 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
787 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
788 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
789
790 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
791 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
792 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
793
794 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
795 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
796 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
797
798 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
799 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
800 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
801
802 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
803 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
804
805 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
806 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
807 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
808 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
809 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
810 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
811 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
812 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
813 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
814 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
815 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
816 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
817 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
818 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
819 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
820 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
821 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
822 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
823 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
824 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
825 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
826
827 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
828 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
829 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
830 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
831 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
832 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
833 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
834 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
835 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
836 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
837 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
838 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
839
840 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
841 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
842 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
843
844 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
845
846 /* FIXME: add "Terminal" */
847 };
848 static const int font_log_pixels[] = { 96, 120 };
849 HDC hdc;
850 LOGFONT lf;
851 HFONT hfont, old_hfont;
852 TEXTMETRIC tm;
853 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
854 char face_name[LF_FACESIZE];
855 CHARSETINFO csi;
856
857 trace("system language id %04x\n", system_lang_id);
858
859 expected_cs = GetACP();
860 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
861 {
862 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
863 return;
864 }
865 expected_cs = csi.ciCharset;
866 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
867
868 hdc = CreateCompatibleDC(0);
869 assert(hdc);
870
871 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
872 GetDeviceCaps(hdc, LOGPIXELSY));
873
874 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
875 diff = 32768;
876 font_res = 0;
877 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
878 {
879 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
880 if (new_diff < diff)
881 {
882 diff = new_diff;
883 font_res = font_log_pixels[i];
884 }
885 }
886 trace("best font resolution is %d\n", font_res);
887
888 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
889 {
890 int bit, height;
891
892 memset(&lf, 0, sizeof(lf));
893
894 height = fd[i].height & ~FH_SCALE;
895 lf.lfHeight = height;
896 strcpy(lf.lfFaceName, fd[i].face_name);
897
898 for(bit = 0; bit < 32; bit++)
899 {
900 GLYPHMETRICS gm;
901 DWORD fs[2];
902 BOOL bRet;
903
904 fs[0] = 1L << bit;
905 fs[1] = 0;
906 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
907 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
908
909 lf.lfCharSet = csi.ciCharset;
910 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
911 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
912 if (fd[i].height & FH_SCALE)
913 ok(ret, "scaled font height %d should not be enumerated\n", height);
914 else
915 {
916 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
917 {
918 if (ret) /* FIXME: Remove once Wine is fixed */
919 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
920 else
921 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
922 }
923 }
924 if (ret && !(fd[i].height & FH_SCALE))
925 continue;
926
927 hfont = create_font(lf.lfFaceName, &lf);
928 old_hfont = SelectObject(hdc, hfont);
929
930 SetLastError(0xdeadbeef);
931 ret = GetTextFace(hdc, sizeof(face_name), face_name);
932 ok(ret, "GetTextFace error %u\n", GetLastError());
933
934 if (lstrcmp(face_name, fd[i].face_name) != 0)
935 {
936 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
937 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
938 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
939 SelectObject(hdc, old_hfont);
940 DeleteObject(hfont);
941 continue;
942 }
943
944 memset(&gm, 0, sizeof(gm));
945 SetLastError(0xdeadbeef);
946 ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
947 todo_wine {
948 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
949 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
950 }
951
952 bRet = GetTextMetrics(hdc, &tm);
953 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
954
955 SetLastError(0xdeadbeef);
956 ret = GetTextCharset(hdc);
957 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
958 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
959 else
960 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
961
962 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
963 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
964
965 if(fd[i].dpi == tm.tmDigitizedAspectX)
966 {
967 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
968 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
969 {
970 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
971 if (fd[i].height & FH_SCALE)
972 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);
973 else
974 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);
975 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
976 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
977 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);
978 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);
979 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);
980 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
981 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
982 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
983 make default char test fail */
984 if (tm.tmCharSet == lf.lfCharSet)
985 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
986 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
987 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);
988
989 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
990 that make the max width bigger */
991 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
992 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);
993 }
994 else
995 skip("Skipping font metrics test for system langid 0x%x\n",
996 system_lang_id);
997 }
998 SelectObject(hdc, old_hfont);
999 DeleteObject(hfont);
1000 }
1001 }
1002
1003 DeleteDC(hdc);
1004 }
1005
1006 static void test_GdiGetCharDimensions(void)
1007 {
1008 HDC hdc;
1009 TEXTMETRICW tm;
1010 LONG ret;
1011 SIZE size;
1012 LONG avgwidth, height;
1013 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1014
1015 if (!pGdiGetCharDimensions)
1016 {
1017 win_skip("GdiGetCharDimensions not available on this platform\n");
1018 return;
1019 }
1020
1021 hdc = CreateCompatibleDC(NULL);
1022
1023 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1024 avgwidth = ((size.cx / 26) + 1) / 2;
1025
1026 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1027 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1028 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1029
1030 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1031 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1032
1033 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1034 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1035
1036 height = 0;
1037 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1038 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1039 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1040
1041 DeleteDC(hdc);
1042 }
1043
1044 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1045 const TEXTMETRIC *lpntme,
1046 DWORD FontType, LPARAM lParam)
1047 {
1048 if (FontType & TRUETYPE_FONTTYPE)
1049 {
1050 HFONT hfont;
1051
1052 hfont = CreateFontIndirect(lpelfe);
1053 if (hfont)
1054 {
1055 *(HFONT *)lParam = hfont;
1056 return 0;
1057 }
1058 }
1059
1060 return 1;
1061 }
1062
1063 static void test_GetCharABCWidths(void)
1064 {
1065 static const WCHAR str[] = {'a',0};
1066 BOOL ret;
1067 HDC hdc;
1068 LOGFONTA lf;
1069 HFONT hfont;
1070 ABC abc[1];
1071 ABCFLOAT abcf[1];
1072 WORD glyphs[1];
1073 DWORD nb;
1074 static const struct
1075 {
1076 UINT first;
1077 UINT last;
1078 } range[] =
1079 {
1080 {0xff, 0xff},
1081 {0x100, 0x100},
1082 {0xff, 0x100},
1083 {0x1ff, 0xff00},
1084 {0xffff, 0xffff},
1085 {0x10000, 0x10000},
1086 {0xffff, 0x10000},
1087 {0xffffff, 0xffffff},
1088 {0x1000000, 0x1000000},
1089 {0xffffff, 0x1000000},
1090 {0xffffffff, 0xffffffff},
1091 {0x00, 0xff}
1092 };
1093 static const struct
1094 {
1095 UINT cs;
1096 UINT a;
1097 UINT w;
1098 BOOL r[sizeof range / sizeof range[0]];
1099 } c[] =
1100 {
1101 {ANSI_CHARSET, 0x30, 0x30,
1102 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1103 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1104 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1105 {HANGEUL_CHARSET, 0x8141, 0xac02,
1106 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1107 {JOHAB_CHARSET, 0x8446, 0x3135,
1108 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1109 {GB2312_CHARSET, 0x8141, 0x4e04,
1110 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1111 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1112 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1113 };
1114 UINT i;
1115
1116 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1117 {
1118 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1119 return;
1120 }
1121
1122 memset(&lf, 0, sizeof(lf));
1123 strcpy(lf.lfFaceName, "System");
1124 lf.lfHeight = 20;
1125
1126 hfont = CreateFontIndirectA(&lf);
1127 hdc = GetDC(0);
1128 hfont = SelectObject(hdc, hfont);
1129
1130 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1131 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1132
1133 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1134 ok(!ret, "GetCharABCWidthsI should have failed\n");
1135
1136 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1137 ok(!ret, "GetCharABCWidthsI should have failed\n");
1138
1139 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1140 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1141
1142 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1143 ok(!ret, "GetCharABCWidthsW should have failed\n");
1144
1145 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1146 ok(!ret, "GetCharABCWidthsW should have failed\n");
1147
1148 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1149 ok(!ret, "GetCharABCWidthsW should have failed\n");
1150
1151 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1152 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1153
1154 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1155 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1156
1157 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1158 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1159
1160 hfont = SelectObject(hdc, hfont);
1161 DeleteObject(hfont);
1162
1163 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1164 {
1165 ABC a[2], w[2];
1166 ABC full[256];
1167 UINT code = 0x41, j;
1168
1169 lf.lfFaceName[0] = '\0';
1170 lf.lfCharSet = c[i].cs;
1171 lf.lfPitchAndFamily = 0;
1172 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1173 {
1174 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1175 continue;
1176 }
1177
1178 memset(a, 0, sizeof a);
1179 memset(w, 0, sizeof w);
1180 hfont = SelectObject(hdc, hfont);
1181 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1182 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1183 memcmp(a, w, sizeof a) == 0,
1184 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1185
1186 memset(a, 0xbb, sizeof a);
1187 ret = pGetCharABCWidthsA(hdc, code, code, a);
1188 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1189 memset(full, 0xcc, sizeof full);
1190 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1191 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1192 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1193 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1194
1195 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1196 {
1197 memset(full, 0xdd, sizeof full);
1198 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1199 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1200 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1201 if (ret)
1202 {
1203 UINT last = range[j].last - range[j].first;
1204 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1205 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1206 "GetCharABCWidthsA %x should match. codepage = %u\n",
1207 range[j].last, c[i].cs);
1208 }
1209 }
1210
1211 hfont = SelectObject(hdc, hfont);
1212 DeleteObject(hfont);
1213 }
1214
1215 ReleaseDC(NULL, hdc);
1216 }
1217
1218 static void test_text_extents(void)
1219 {
1220 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1221 LPINT extents;
1222 INT i, len, fit1, fit2;
1223 LOGFONTA lf;
1224 TEXTMETRICA tm;
1225 HDC hdc;
1226 HFONT hfont;
1227 SIZE sz;
1228 SIZE sz1, sz2;
1229 BOOL ret;
1230
1231 memset(&lf, 0, sizeof(lf));
1232 strcpy(lf.lfFaceName, "Arial");
1233 lf.lfHeight = 20;
1234
1235 hfont = CreateFontIndirectA(&lf);
1236 hdc = GetDC(0);
1237 hfont = SelectObject(hdc, hfont);
1238 GetTextMetricsA(hdc, &tm);
1239 GetTextExtentPointA(hdc, "o", 1, &sz);
1240 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1241
1242 SetLastError(0xdeadbeef);
1243 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1244 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1245 {
1246 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1247 hfont = SelectObject(hdc, hfont);
1248 DeleteObject(hfont);
1249 ReleaseDC(0, hdc);
1250 return;
1251 }
1252
1253 len = lstrlenW(wt);
1254 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1255 extents[0] = 1; /* So that the increasing sequence test will fail
1256 if the extents array is untouched. */
1257 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1258 GetTextExtentPointW(hdc, wt, len, &sz2);
1259 ok(sz1.cy == sz2.cy,
1260 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1261 /* Because of the '\n' in the string GetTextExtentExPoint and
1262 GetTextExtentPoint return different widths under Win2k, but
1263 under WinXP they return the same width. So we don't test that
1264 here. */
1265
1266 for (i = 1; i < len; ++i)
1267 ok(extents[i-1] <= extents[i],
1268 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1269 i);
1270 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1271 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1272 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1273 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1274 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1275 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1276 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1277 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1278 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1279 ok(extents[0] == extents[2] && extents[1] == extents[3],
1280 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1281 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1282 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1283 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1284 HeapFree(GetProcessHeap(), 0, extents);
1285
1286 /* extents functions fail with -ve counts (the interesting case being -1) */
1287 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1288 ok(ret == FALSE, "got %d\n", ret);
1289 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1290 ok(ret == FALSE, "got %d\n", ret);
1291 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1292 ok(ret == FALSE, "got %d\n", ret);
1293
1294 /* max_extent = 0 succeeds and returns zero */
1295 fit1 = fit2 = -215;
1296 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1297 ok(ret == TRUE ||
1298 broken(ret == FALSE), /* NT4, 2k */
1299 "got %d\n", ret);
1300 ok(fit1 == 0 ||
1301 broken(fit1 == -215), /* NT4, 2k */
1302 "fit = %d\n", fit1);
1303 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1304 ok(ret == TRUE, "got %d\n", ret);
1305 ok(fit2 == 0, "fit = %d\n", fit2);
1306
1307 /* max_extent = -1 is interpreted as a very large width that will
1308 * definitely fit our three characters */
1309 fit1 = fit2 = -215;
1310 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1311 ok(ret == TRUE, "got %d\n", ret);
1312 ok(fit1 == 3, "fit = %d\n", fit1);
1313 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1314 ok(ret == TRUE, "got %d\n", ret);
1315 ok(fit2 == 3, "fit = %d\n", fit2);
1316
1317 /* max_extent = -2 is interpreted similarly, but the Ansi version
1318 * rejects it while the Unicode one accepts it */
1319 fit1 = fit2 = -215;
1320 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1321 ok(ret == FALSE, "got %d\n", ret);
1322 ok(fit1 == -215, "fit = %d\n", fit1);
1323 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1324 ok(ret == TRUE, "got %d\n", ret);
1325 ok(fit2 == 3, "fit = %d\n", fit2);
1326
1327 hfont = SelectObject(hdc, hfont);
1328 DeleteObject(hfont);
1329 ReleaseDC(NULL, hdc);
1330 }
1331
1332 static void test_GetGlyphIndices(void)
1333 {
1334 HDC hdc;
1335 HFONT hfont;
1336 DWORD charcount;
1337 LOGFONTA lf;
1338 DWORD flags = 0;
1339 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1340 WORD glyphs[(sizeof(testtext)/2)-1];
1341 TEXTMETRIC textm;
1342 HFONT hOldFont;
1343
1344 if (!pGetGlyphIndicesW) {
1345 win_skip("GetGlyphIndicesW not available on platform\n");
1346 return;
1347 }
1348
1349 hdc = GetDC(0);
1350
1351 memset(&lf, 0, sizeof(lf));
1352 strcpy(lf.lfFaceName, "System");
1353 lf.lfHeight = 16;
1354 lf.lfCharSet = ANSI_CHARSET;
1355
1356 hfont = CreateFontIndirectA(&lf);
1357 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1358 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1359 if (textm.tmCharSet == ANSI_CHARSET)
1360 {
1361 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1362 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1363 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1364 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1365 flags = 0;
1366 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1367 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1368 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1369 textm.tmDefaultChar, glyphs[4]);
1370 }
1371 else
1372 /* FIXME: Write tests for non-ANSI charsets. */
1373 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1374
1375 if(!is_font_installed("Tahoma"))
1376 {
1377 skip("Tahoma is not installed so skipping this test\n");
1378 return;
1379 }
1380 memset(&lf, 0, sizeof(lf));
1381 strcpy(lf.lfFaceName, "Tahoma");
1382 lf.lfHeight = 20;
1383
1384 hfont = CreateFontIndirectA(&lf);
1385 hOldFont = SelectObject(hdc, hfont);
1386 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1387 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1388 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1389 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1390 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1391 flags = 0;
1392 testtext[0] = textm.tmDefaultChar;
1393 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1394 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1395 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1396 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1397 DeleteObject(SelectObject(hdc, hOldFont));
1398 }
1399
1400 static void test_GetKerningPairs(void)
1401 {
1402 static const struct kerning_data
1403 {
1404 const char face_name[LF_FACESIZE];
1405 LONG height;
1406 /* some interesting fields from OUTLINETEXTMETRIC */
1407 LONG tmHeight, tmAscent, tmDescent;
1408 UINT otmEMSquare;
1409 INT otmAscent;
1410 INT otmDescent;
1411 UINT otmLineGap;
1412 UINT otmsCapEmHeight;
1413 UINT otmsXHeight;
1414 INT otmMacAscent;
1415 INT otmMacDescent;
1416 UINT otmMacLineGap;
1417 UINT otmusMinimumPPEM;
1418 /* small subset of kerning pairs to test */
1419 DWORD total_kern_pairs;
1420 const KERNINGPAIR kern_pair[26];
1421 } kd[] =
1422 {
1423 {"Arial", 12, 12, 9, 3,
1424 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1425 26,
1426 {
1427 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1428 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1429 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1430 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1431 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1432 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1433 {933,970,+1},{933,972,-1}
1434 }
1435 },
1436 {"Arial", -34, 39, 32, 7,
1437 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1438 26,
1439 {
1440 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1441 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1442 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1443 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1444 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1445 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1446 {933,970,+2},{933,972,-3}
1447 }
1448 },
1449 { "Arial", 120, 120, 97, 23,
1450 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1451 26,
1452 {
1453 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1454 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1455 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1456 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1457 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1458 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1459 {933,970,+6},{933,972,-10}
1460 }
1461 },
1462 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1463 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1464 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1465 26,
1466 {
1467 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1468 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1469 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1470 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1471 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1472 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1473 {933,970,+54},{933,972,-83}
1474 }
1475 }
1476 #endif
1477 };
1478 LOGFONT lf;
1479 HFONT hfont, hfont_old;
1480 KERNINGPAIR *kern_pair;
1481 HDC hdc;
1482 DWORD total_kern_pairs, ret, i, n, matches;
1483
1484 hdc = GetDC(0);
1485
1486 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1487 * which may render this test unusable, so we're trying to avoid that.
1488 */
1489 SetLastError(0xdeadbeef);
1490 GetKerningPairsW(hdc, 0, NULL);
1491 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1492 {
1493 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1494 ReleaseDC(0, hdc);
1495 return;
1496 }
1497
1498 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1499 {
1500 OUTLINETEXTMETRICW otm;
1501 UINT uiRet;
1502
1503 if (!is_font_installed(kd[i].face_name))
1504 {
1505 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1506 continue;
1507 }
1508
1509 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1510
1511 memset(&lf, 0, sizeof(lf));
1512 strcpy(lf.lfFaceName, kd[i].face_name);
1513 lf.lfHeight = kd[i].height;
1514 hfont = CreateFontIndirect(&lf);
1515 assert(hfont != 0);
1516
1517 hfont_old = SelectObject(hdc, hfont);
1518
1519 SetLastError(0xdeadbeef);
1520 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1521 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1522 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1523
1524 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1525 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1526 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1527 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1528 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1529 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1530
1531 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1532 kd[i].otmEMSquare, otm.otmEMSquare);
1533 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1534 kd[i].otmAscent, otm.otmAscent);
1535 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1536 kd[i].otmDescent, otm.otmDescent);
1537 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1538 kd[i].otmLineGap, otm.otmLineGap);
1539 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1540 kd[i].otmMacDescent, otm.otmMacDescent);
1541 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1542 kd[i].otmMacAscent, otm.otmMacAscent);
1543 todo_wine {
1544 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1545 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1546 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1547 kd[i].otmsXHeight, otm.otmsXHeight);
1548 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1549 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1550 kd[i].otmMacLineGap, otm.otmMacLineGap);
1551 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1552 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1553 }
1554
1555 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1556 trace("total_kern_pairs %u\n", total_kern_pairs);
1557 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1558
1559 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1560 * passes on XP.
1561 */
1562 SetLastError(0xdeadbeef);
1563 ret = GetKerningPairsW(hdc, 0, kern_pair);
1564 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1565 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1566 ok(ret == 0, "got %u, expected 0\n", ret);
1567
1568 ret = GetKerningPairsW(hdc, 100, NULL);
1569 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1570
1571 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1572 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1573
1574 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1575 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1576
1577 matches = 0;
1578
1579 for (n = 0; n < ret; n++)
1580 {
1581 DWORD j;
1582 /* Disabled to limit console spam */
1583 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1584 trace("{'%c','%c',%d},\n",
1585 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1586 for (j = 0; j < kd[i].total_kern_pairs; j++)
1587 {
1588 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1589 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1590 {
1591 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1592 "pair %d:%d got %d, expected %d\n",
1593 kern_pair[n].wFirst, kern_pair[n].wSecond,
1594 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1595 matches++;
1596 }
1597 }
1598 }
1599
1600 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1601 matches, kd[i].total_kern_pairs);
1602
1603 HeapFree(GetProcessHeap(), 0, kern_pair);
1604
1605 SelectObject(hdc, hfont_old);
1606 DeleteObject(hfont);
1607 }
1608
1609 ReleaseDC(0, hdc);
1610 }
1611
1612 static void test_height_selection(void)
1613 {
1614 static const struct font_data
1615 {
1616 const char face_name[LF_FACESIZE];
1617 int requested_height;
1618 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1619 } fd[] =
1620 {
1621 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1622 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1623 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1624 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1625 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1626 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1627 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1628 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1629 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1630 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1631 };
1632 HDC hdc;
1633 LOGFONT lf;
1634 HFONT hfont, old_hfont;
1635 TEXTMETRIC tm;
1636 INT ret, i;
1637
1638 hdc = CreateCompatibleDC(0);
1639 assert(hdc);
1640
1641 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1642 {
1643 if (!is_truetype_font_installed(fd[i].face_name))
1644 {
1645 skip("%s is not installed\n", fd[i].face_name);
1646 continue;
1647 }
1648
1649 memset(&lf, 0, sizeof(lf));
1650 lf.lfHeight = fd[i].requested_height;
1651 lf.lfWeight = fd[i].weight;
1652 strcpy(lf.lfFaceName, fd[i].face_name);
1653
1654 hfont = CreateFontIndirect(&lf);
1655 assert(hfont);
1656
1657 old_hfont = SelectObject(hdc, hfont);
1658 ret = GetTextMetrics(hdc, &tm);
1659 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1660 if(fd[i].dpi == tm.tmDigitizedAspectX)
1661 {
1662 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1663 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);
1664 ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1665 ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1666 ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1667 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1668 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1669 #endif
1670 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);
1671 }
1672
1673 SelectObject(hdc, old_hfont);
1674 DeleteObject(hfont);
1675 }
1676
1677 DeleteDC(hdc);
1678 }
1679
1680 static void test_GetOutlineTextMetrics(void)
1681 {
1682 OUTLINETEXTMETRIC *otm;
1683 LOGFONT lf;
1684 HFONT hfont, hfont_old;
1685 HDC hdc;
1686 DWORD ret, otm_size;
1687 LPSTR unset_ptr;
1688
1689 if (!is_font_installed("Arial"))
1690 {
1691 skip("Arial is not installed\n");
1692 return;
1693 }
1694
1695 hdc = GetDC(0);
1696
1697 memset(&lf, 0, sizeof(lf));
1698 strcpy(lf.lfFaceName, "Arial");
1699 lf.lfHeight = -13;
1700 lf.lfWeight = FW_NORMAL;
1701 lf.lfPitchAndFamily = DEFAULT_PITCH;
1702 lf.lfQuality = PROOF_QUALITY;
1703 hfont = CreateFontIndirect(&lf);
1704 assert(hfont != 0);
1705
1706 hfont_old = SelectObject(hdc, hfont);
1707 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1708 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1709
1710 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1711
1712 memset(otm, 0xAA, otm_size);
1713 SetLastError(0xdeadbeef);
1714 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1715 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1716 ok(ret == 1 /* Win9x */ ||
1717 ret == otm->otmSize /* XP*/,
1718 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1719 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1720 {
1721 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1722 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1723 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1724 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1725 }
1726
1727 memset(otm, 0xAA, otm_size);
1728 SetLastError(0xdeadbeef);
1729 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1730 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1731 ok(ret == 1 /* Win9x */ ||
1732 ret == otm->otmSize /* XP*/,
1733 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1734 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1735 {
1736 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1737 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1738 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1739 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1740 }
1741
1742 /* ask about truncated data */
1743 memset(otm, 0xAA, otm_size);
1744 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1745 SetLastError(0xdeadbeef);
1746 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1747 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1748 ok(ret == 1 /* Win9x */ ||
1749 ret == otm->otmSize /* XP*/,
1750 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1751 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1752 {
1753 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1754 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1755 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1756 }
1757 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1758
1759 HeapFree(GetProcessHeap(), 0, otm);
1760
1761 SelectObject(hdc, hfont_old);
1762 DeleteObject(hfont);
1763
1764 ReleaseDC(0, hdc);
1765 }
1766
1767 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1768 {
1769 INT y,
1770 breakCount,
1771 areaWidth = clientArea->right - clientArea->left,
1772 nErrors = 0, e;
1773 PSTR pFirstChar, pLastChar;
1774 SIZE size;
1775 TEXTMETRICA tm;
1776 struct err
1777 {
1778 char *start;
1779 int len;
1780 int GetTextExtentExPointWWidth;
1781 } error[20];
1782
1783 GetTextMetricsA(hdc, &tm);
1784 y = clientArea->top;
1785 do {
1786 breakCount = 0;
1787 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1788 pFirstChar = str;
1789
1790 do {
1791 pLastChar = str;
1792
1793 /* if not at the end of the string, ... */
1794 if (*str == '\0') break;
1795 /* ... add the next word to the current extent */
1796 while (*str != '\0' && *str++ != tm.tmBreakChar);
1797 breakCount++;
1798 SetTextJustification(hdc, 0, 0);
1799 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1800 } while ((int) size.cx < areaWidth);
1801
1802 /* ignore trailing break chars */
1803 breakCount--;
1804 while (*(pLastChar - 1) == tm.tmBreakChar)
1805 {
1806 pLastChar--;
1807 breakCount--;
1808 }
1809
1810 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1811
1812 SetTextJustification(hdc, 0, 0);
1813 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1814
1815 /* do not justify the last extent */
1816 if (*str != '\0' && breakCount > 0)
1817 {
1818 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1819 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1820 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
1821 {
1822 error[nErrors].start = pFirstChar;
1823 error[nErrors].len = pLastChar - pFirstChar;
1824 error[nErrors].GetTextExtentExPointWWidth = size.cx;
1825 nErrors++;
1826 }
1827 }
1828
1829 trace( "%u %.*s\n", size.cx, (int)(pLastChar - pFirstChar), pFirstChar);
1830
1831 y += size.cy;
1832 str = pLastChar;
1833 } while (*str && y < clientArea->bottom);
1834
1835 for (e = 0; e < nErrors; e++)
1836 {
1837 /* The width returned by GetTextExtentPoint32() is exactly the same
1838 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1839 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1840 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
1841 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
1842 }
1843 }
1844
1845 static void test_SetTextJustification(void)
1846 {
1847 HDC hdc;
1848 RECT clientArea;
1849 LOGFONTA lf;
1850 HFONT hfont;
1851 HWND hwnd;
1852 SIZE size, expect;
1853 int i;
1854 WORD indices[2];
1855 static char testText[] =
1856 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1857 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1858 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1859 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1860 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1861 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1862 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1863
1864 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1865 GetClientRect( hwnd, &clientArea );
1866 hdc = GetDC( hwnd );
1867
1868 memset(&lf, 0, sizeof lf);
1869 lf.lfCharSet = ANSI_CHARSET;
1870 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1871 lf.lfWeight = FW_DONTCARE;
1872 lf.lfHeight = 20;
1873 lf.lfQuality = DEFAULT_QUALITY;
1874 lstrcpyA(lf.lfFaceName, "Times New Roman");
1875 hfont = create_font("Times New Roman", &lf);
1876 SelectObject(hdc, hfont);
1877
1878 testJustification(hdc, testText, &clientArea);
1879
1880 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
1881 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
1882
1883 SetTextJustification(hdc, 0, 0);
1884 GetTextExtentPoint32(hdc, " ", 1, &expect);
1885 GetTextExtentPoint32(hdc, " ", 3, &size);
1886 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
1887 SetTextJustification(hdc, 4, 1);
1888 GetTextExtentPoint32(hdc, " ", 1, &size);
1889 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
1890 SetTextJustification(hdc, 9, 2);
1891 GetTextExtentPoint32(hdc, " ", 2, &size);
1892 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
1893 SetTextJustification(hdc, 7, 3);
1894 GetTextExtentPoint32(hdc, " ", 3, &size);
1895 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
1896 SetTextJustification(hdc, 7, 3);
1897 SetTextCharacterExtra(hdc, 2 );
1898 GetTextExtentPoint32(hdc, " ", 3, &size);
1899 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
1900 SetTextJustification(hdc, 0, 0);
1901 SetTextCharacterExtra(hdc, 0);
1902 size.cx = size.cy = 1234;
1903 GetTextExtentPoint32(hdc, " ", 0, &size);
1904 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
1905 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
1906 SetTextJustification(hdc, 5, 1);
1907 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
1908 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
1909 SetTextJustification(hdc, 0, 0);
1910
1911 SetMapMode( hdc, MM_ANISOTROPIC );
1912 SetWindowExtEx( hdc, 2, 2, NULL );
1913 GetClientRect( hwnd, &clientArea );
1914 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1915 testJustification(hdc, testText, &clientArea);
1916
1917 GetTextExtentPoint32(hdc, "A", 1, &expect);
1918 for (i = 0; i < 10; i++)
1919 {
1920 SetTextCharacterExtra(hdc, i);
1921 GetTextExtentPoint32(hdc, "A", 1, &size);
1922 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1923 }
1924 SetTextCharacterExtra(hdc, 0);
1925 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
1926 for (i = 0; i < 10; i++)
1927 {
1928 SetTextCharacterExtra(hdc, i);
1929 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
1930 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1931 }
1932 SetTextCharacterExtra(hdc, 0);
1933
1934 SetViewportExtEx( hdc, 3, 3, NULL );
1935 GetClientRect( hwnd, &clientArea );
1936 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1937 testJustification(hdc, testText, &clientArea);
1938
1939 GetTextExtentPoint32(hdc, "A", 1, &expect);
1940 for (i = 0; i < 10; i++)
1941 {
1942 SetTextCharacterExtra(hdc, i);
1943 GetTextExtentPoint32(hdc, "A", 1, &size);
1944 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1945 }
1946
1947 done:
1948 DeleteObject(hfont);
1949 ReleaseDC(hwnd, hdc);
1950 DestroyWindow(hwnd);
1951 }
1952
1953 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1954 {
1955 HDC hdc;
1956 LOGFONTA lf;
1957 HFONT hfont, hfont_old;
1958 CHARSETINFO csi;
1959 FONTSIGNATURE fs;
1960 INT cs;
1961 DWORD i, ret;
1962 char name[64];
1963
1964 assert(count <= 128);
1965
1966 memset(&lf, 0, sizeof(lf));
1967
1968 lf.lfCharSet = charset;
1969 lf.lfHeight = 10;
1970 lstrcpyA(lf.lfFaceName, "Arial");
1971 SetLastError(0xdeadbeef);
1972 hfont = CreateFontIndirectA(&lf);
1973 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1974
1975 hdc = GetDC(0);
1976 hfont_old = SelectObject(hdc, hfont);
1977
1978 cs = GetTextCharsetInfo(hdc, &fs, 0);
1979 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1980
1981 SetLastError(0xdeadbeef);
1982 ret = GetTextFaceA(hdc, sizeof(name), name);
1983 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1984
1985 if (charset == SYMBOL_CHARSET)
1986 {
1987 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1988 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1989 }
1990 else
1991 {
1992 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1993 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1994 }
1995
1996 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1997 {
1998 trace("Can't find codepage for charset %d\n", cs);
1999 ReleaseDC(0, hdc);
2000 return FALSE;
2001 }
2002 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
2003
2004 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
2005 {
2006 skip("Font code page %d, looking for code page %d\n",
2007 pGdiGetCodePage(hdc), code_page);
2008 ReleaseDC(0, hdc);
2009 return FALSE;
2010 }
2011
2012 if (unicode)
2013 {
2014 char ansi_buf[128];
2015 WCHAR unicode_buf[128];
2016
2017 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2018
2019 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2020
2021 SetLastError(0xdeadbeef);
2022 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2023 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2024 count, ret, GetLastError());
2025 }
2026 else
2027 {
2028 char ansi_buf[128];
2029
2030 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2031
2032 SetLastError(0xdeadbeef);
2033 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2034 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2035 count, ret, GetLastError());
2036 }
2037
2038 SelectObject(hdc, hfont_old);
2039 DeleteObject(hfont);
2040
2041 ReleaseDC(0, hdc);
2042
2043 return TRUE;
2044 }
2045
2046 static void test_font_charset(void)
2047 {
2048 static struct charset_data
2049 {
2050 INT charset;
2051 UINT code_page;
2052 WORD font_idxA[128], font_idxW[128];
2053 } cd[] =
2054 {
2055 { ANSI_CHARSET, 1252 },
2056 { RUSSIAN_CHARSET, 1251 },
2057 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2058 };
2059 int i;
2060
2061 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2062 {
2063 win_skip("Skipping the font charset test on a Win9x platform\n");
2064 return;
2065 }
2066
2067 if (!is_font_installed("Arial"))
2068 {
2069 skip("Arial is not installed\n");
2070 return;
2071 }
2072
2073 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2074 {
2075 if (cd[i].charset == SYMBOL_CHARSET)
2076 {
2077 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2078 {
2079 skip("Symbol or Wingdings is not installed\n");
2080 break;
2081 }
2082 }
2083 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2084 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2085 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2086 }
2087
2088 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2089 if (i > 2)
2090 {
2091 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2092 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2093 }
2094 else
2095 skip("Symbol or Wingdings is not installed\n");
2096 }
2097
2098 static void test_GdiGetCodePage(void)
2099 {
2100 static const struct _matching_data
2101 {
2102 UINT current_codepage;
2103 LPCSTR lfFaceName;
2104 UCHAR lfCharSet;
2105 UINT expected_codepage;
2106 } matching_data[] = {
2107 {1251, "Arial", ANSI_CHARSET, 1252},
2108 {1251, "Tahoma", ANSI_CHARSET, 1252},
2109
2110 {1252, "Arial", ANSI_CHARSET, 1252},
2111 {1252, "Tahoma", ANSI_CHARSET, 1252},
2112
2113 {1253, "Arial", ANSI_CHARSET, 1252},
2114 {1253, "Tahoma", ANSI_CHARSET, 1252},
2115
2116 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2117 { 932, "Tahoma", ANSI_CHARSET, 1252},
2118 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2119
2120 { 936, "Arial", ANSI_CHARSET, 936},
2121 { 936, "Tahoma", ANSI_CHARSET, 936},
2122 { 936, "Simsun", ANSI_CHARSET, 936},
2123
2124 { 949, "Arial", ANSI_CHARSET, 949},
2125 { 949, "Tahoma", ANSI_CHARSET, 949},
2126 { 949, "Gulim", ANSI_CHARSET, 949},
2127
2128 { 950, "Arial", ANSI_CHARSET, 950},
2129 { 950, "Tahoma", ANSI_CHARSET, 950},
2130 { 950, "PMingLiU", ANSI_CHARSET, 950},
2131 };
2132 HDC hdc;
2133 LOGFONT lf;
2134 HFONT hfont;
2135 UINT charset, acp;
2136 DWORD codepage;
2137 int i;
2138
2139 if (!pGdiGetCodePage)
2140 {
2141 skip("GdiGetCodePage not available on this platform\n");
2142 return;
2143 }
2144
2145 acp = GetACP();
2146
2147 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2148 {
2149 /* only test data matched current locale codepage */
2150 if (matching_data[i].current_codepage != acp)
2151 continue;
2152
2153 if (!is_font_installed(matching_data[i].lfFaceName))
2154 {
2155 skip("%s is not installed\n", matching_data[i].lfFaceName);
2156 continue;
2157 }
2158
2159 hdc = GetDC(0);
2160
2161 memset(&lf, 0, sizeof(lf));
2162 lf.lfHeight = -16;
2163 lf.lfCharSet = matching_data[i].lfCharSet;
2164 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2165 hfont = CreateFontIndirectA(&lf);
2166 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2167
2168 hfont = SelectObject(hdc, hfont);
2169 charset = GetTextCharset(hdc);
2170 codepage = pGdiGetCodePage(hdc);
2171 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2172 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2173 ok(codepage == matching_data[i].expected_codepage,
2174 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2175
2176 hfont = SelectObject(hdc, hfont);
2177 DeleteObject(hfont);
2178 ReleaseDC(NULL, hdc);
2179 }
2180 }
2181
2182 static void test_GetFontUnicodeRanges(void)
2183 {
2184 LOGFONTA lf;
2185 HDC hdc;
2186 HFONT hfont, hfont_old;
2187 DWORD size;
2188 GLYPHSET *gs;
2189 DWORD i;
2190
2191 if (!pGetFontUnicodeRanges)
2192 {
2193 win_skip("GetFontUnicodeRanges not available before W2K\n");
2194 return;
2195 }
2196
2197 memset(&lf, 0, sizeof(lf));
2198 lstrcpyA(lf.lfFaceName, "Arial");
2199 hfont = create_font("Arial", &lf);
2200
2201 hdc = GetDC(0);
2202 hfont_old = SelectObject(hdc, hfont);
2203
2204 size = pGetFontUnicodeRanges(NULL, NULL);
2205 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2206
2207 size = pGetFontUnicodeRanges(hdc, NULL);
2208 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2209
2210 gs = HeapAlloc(GetProcessHeap(), 0, size);
2211
2212 size = pGetFontUnicodeRanges(hdc, gs);
2213 ok(size, "GetFontUnicodeRanges failed\n");
2214
2215 if (0) /* Disabled to limit console spam */
2216 for (i = 0; i < gs->cRanges; i++)
2217 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2218 trace("found %u ranges\n", gs->cRanges);
2219
2220 HeapFree(GetProcessHeap(), 0, gs);
2221
2222 SelectObject(hdc, hfont_old);
2223 DeleteObject(hfont);
2224 ReleaseDC(NULL, hdc);
2225 }
2226
2227 #define MAX_ENUM_FONTS 4096
2228
2229 struct enum_font_data
2230 {
2231 int total;
2232 LOGFONT lf[MAX_ENUM_FONTS];
2233 };
2234
2235 struct enum_fullname_data
2236 {
2237 int total;
2238 ENUMLOGFONT elf[MAX_ENUM_FONTS];
2239 };
2240
2241 struct enum_font_dataW
2242 {
2243 int total;
2244 LOGFONTW lf[MAX_ENUM_FONTS];
2245 };
2246
2247 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2248 {
2249 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2250 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2251
2252 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2253 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2254
2255 if (type != TRUETYPE_FONTTYPE) return 1;
2256
2257 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2258
2259 if (0) /* Disabled to limit console spam */
2260 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2261 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2262 if (efd->total < MAX_ENUM_FONTS)
2263 efd->lf[efd->total++] = *lf;
2264 else
2265 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2266
2267 return 1;
2268 }
2269
2270 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2271 {
2272 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2273 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2274
2275 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2276 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2277
2278 if (type != TRUETYPE_FONTTYPE) return 1;
2279
2280 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2281
2282 if (0) /* Disabled to limit console spam */
2283 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2284 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2285 if (efd->total < MAX_ENUM_FONTS)
2286 efd->lf[efd->total++] = *lf;
2287 else
2288 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2289
2290 return 1;
2291 }
2292
2293 static void get_charset_stats(struct enum_font_data *efd,
2294 int *ansi_charset, int *symbol_charset,
2295 int *russian_charset)
2296 {
2297 int i;
2298
2299 *ansi_charset = 0;
2300 *symbol_charset = 0;
2301 *russian_charset = 0;
2302
2303 for (i = 0; i < efd->total; i++)
2304 {
2305 switch (efd->lf[i].lfCharSet)
2306 {
2307 case ANSI_CHARSET:
2308 (*ansi_charset)++;
2309 break;
2310 case SYMBOL_CHARSET:
2311 (*symbol_charset)++;
2312 break;
2313 case RUSSIAN_CHARSET:
2314 (*russian_charset)++;
2315 break;
2316 }
2317 }
2318 }
2319
2320 static void get_charset_statsW(struct enum_font_dataW *efd,
2321 int *ansi_charset, int *symbol_charset,
2322 int *russian_charset)
2323 {
2324 int i;
2325
2326 *ansi_charset = 0;
2327 *symbol_charset = 0;
2328 *russian_charset = 0;
2329
2330 for (i = 0; i < efd->total; i++)
2331 {
2332 switch (efd->lf[i].lfCharSet)
2333 {
2334 case ANSI_CHARSET:
2335 (*ansi_charset)++;
2336 break;
2337 case SYMBOL_CHARSET:
2338 (*symbol_charset)++;
2339 break;
2340 case RUSSIAN_CHARSET:
2341 (*russian_charset)++;
2342 break;
2343 }
2344 }
2345 }
2346
2347 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2348 {
2349 struct enum_font_data efd;
2350 struct enum_font_dataW efdw;
2351 LOGFONT lf;
2352 HDC hdc;
2353 int i, ret, ansi_charset, symbol_charset, russian_charset;
2354
2355 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2356
2357 if (*font_name && !is_truetype_font_installed(font_name))
2358 {
2359 skip("%s is not installed\n", font_name);
2360 return;
2361 }
2362
2363 hdc = GetDC(0);
2364
2365 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2366 * while EnumFontFamiliesEx doesn't.
2367 */
2368 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2369 {
2370 /*
2371 * Use EnumFontFamiliesW since win98 crashes when the
2372 * second parameter is NULL using EnumFontFamilies
2373 */
2374 efdw.total = 0;
2375 SetLastError(0xdeadbeef);
2376 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2377 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2378 if(ret)
2379 {
2380 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2381 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2382 ansi_charset, symbol_charset, russian_charset);
2383 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2384 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2385 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2386 ok(russian_charset > 0 ||
2387 broken(russian_charset == 0), /* NT4 */
2388 "NULL family should enumerate RUSSIAN_CHARSET\n");
2389 }
2390
2391 efdw.total = 0;
2392 SetLastError(0xdeadbeef);
2393 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2394 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2395 if(ret)
2396 {
2397 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2398 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2399 ansi_charset, symbol_charset, russian_charset);
2400 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2401 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2402 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2403 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2404 }
2405 }
2406
2407 efd.total = 0;
2408 SetLastError(0xdeadbeef);
2409 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2410 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2411 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2412 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2413 ansi_charset, symbol_charset, russian_charset,
2414 *font_name ? font_name : "<empty>");
2415 if (*font_name)
2416 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2417 else
2418 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2419 for (i = 0; i < efd.total; i++)
2420 {
2421 /* FIXME: remove completely once Wine is fixed */
2422 if (efd.lf[i].lfCharSet != font_charset)
2423 {
2424 todo_wine
2425 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2426 }
2427 else
2428 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2429 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2430 font_name, efd.lf[i].lfFaceName);
2431 }
2432
2433 memset(&lf, 0, sizeof(lf));
2434 lf.lfCharSet = ANSI_CHARSET;
2435 lstrcpy(lf.lfFaceName, font_name);
2436 efd.total = 0;
2437 SetLastError(0xdeadbeef);
2438 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2439 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2440 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2441 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2442 ansi_charset, symbol_charset, russian_charset,
2443 *font_name ? font_name : "<empty>");
2444 if (font_charset == SYMBOL_CHARSET)
2445 {
2446 if (*font_name)
2447 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2448 else
2449 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2450 }
2451 else
2452 {
2453 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2454 for (i = 0; i < efd.total; i++)
2455 {
2456 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2457 if (*font_name)
2458 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2459 font_name, efd.lf[i].lfFaceName);
2460 }
2461 }
2462
2463 /* DEFAULT_CHARSET should enumerate all available charsets */
2464 memset(&lf, 0, sizeof(lf));
2465 lf.lfCharSet = DEFAULT_CHARSET;
2466 lstrcpy(lf.lfFaceName, font_name);
2467 efd.total = 0;
2468 SetLastError(0xdeadbeef);
2469 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2470 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2471 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2472 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2473 ansi_charset, symbol_charset, russian_charset,
2474 *font_name ? font_name : "<empty>");
2475 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2476 for (i = 0; i < efd.total; i++)
2477 {
2478 if (*font_name)
2479 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2480 font_name, efd.lf[i].lfFaceName);
2481 }
2482 if (*font_name)
2483 {
2484 switch (font_charset)
2485 {
2486 case ANSI_CHARSET:
2487 ok(ansi_charset > 0,
2488 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2489 ok(!symbol_charset,
2490 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2491 ok(russian_charset > 0,
2492 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2493 break;
2494 case SYMBOL_CHARSET:
2495 ok(!ansi_charset,
2496 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2497 ok(symbol_charset,
2498 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2499 ok(!russian_charset,
2500 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2501 break;
2502 case DEFAULT_CHARSET:
2503 ok(ansi_charset > 0,
2504 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2505 ok(symbol_charset > 0,
2506 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2507 ok(russian_charset > 0,
2508 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2509 break;
2510 }
2511 }
2512 else
2513 {
2514 ok(ansi_charset > 0,
2515 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2516 ok(symbol_charset > 0,
2517 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2518 ok(russian_charset > 0,
2519 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2520 }
2521
2522 memset(&lf, 0, sizeof(lf));
2523 lf.lfCharSet = SYMBOL_CHARSET;
2524 lstrcpy(lf.lfFaceName, font_name);
2525 efd.total = 0;
2526 SetLastError(0xdeadbeef);
2527 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2528 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2529 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2530 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2531 ansi_charset, symbol_charset, russian_charset,
2532 *font_name ? font_name : "<empty>");
2533 if (*font_name && font_charset == ANSI_CHARSET)
2534 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2535 else
2536 {
2537 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2538 for (i = 0; i < efd.total; i++)
2539 {
2540 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2541 if (*font_name)
2542 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2543 font_name, efd.lf[i].lfFaceName);
2544 }
2545
2546 ok(!ansi_charset,
2547 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2548 ok(symbol_charset > 0,
2549 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2550 ok(!russian_charset,
2551 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2552 }
2553
2554 ReleaseDC(0, hdc);
2555 }
2556
2557 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2558 {
2559 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2560
2561 if (type != TRUETYPE_FONTTYPE) return 1;
2562
2563 if (efd->total < MAX_ENUM_FONTS)
2564 efd->lf[efd->total++] = *lf;
2565 else
2566 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2567
2568 return 1;
2569 }
2570
2571 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2572 {
2573 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2574
2575 if (type != TRUETYPE_FONTTYPE) return 1;
2576
2577 if (efnd->total < MAX_ENUM_FONTS)
2578 efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2579 else
2580 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2581
2582 return 1;
2583 }
2584
2585 static void test_EnumFontFamiliesEx_default_charset(void)
2586 {
2587 struct enum_font_data efd;
2588 LOGFONT gui_font, enum_font;
2589 DWORD ret;
2590 HDC hdc;
2591
2592 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2593 ok(ret, "GetObject failed.\n");
2594 if (!ret)
2595 return;
2596
2597 efd.total = 0;
2598
2599 hdc = GetDC(0);
2600 memset(&enum_font, 0, sizeof(enum_font));
2601 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2602 enum_font.lfCharSet = DEFAULT_CHARSET;
2603 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2604 ReleaseDC(0, hdc);
2605
2606 if (efd.total == 0) {
2607 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2608 return;
2609 }
2610 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2611
2612 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet || broken(system_lang_id == LANG_ARABIC),
2613 "(%s) got charset %d expected %d\n",
2614 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2615
2616 return;
2617 }
2618
2619 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2620 {
2621 HFONT hfont, hfont_prev;
2622 DWORD ret;
2623 GLYPHMETRICS gm1, gm2;
2624 LOGFONTA lf2 = *lf;
2625 WORD idx;
2626
2627 if(!pGetGlyphIndicesA)
2628 return;
2629
2630 /* negative widths are handled just as positive ones */
2631 lf2.lfWidth = -lf->lfWidth;
2632
2633 SetLastError(0xdeadbeef);
2634 hfont = CreateFontIndirectA(lf);
2635 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2636 check_font("original", lf, hfont);
2637
2638 hfont_prev = SelectObject(hdc, hfont);
2639
2640 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2641 if (ret == GDI_ERROR || idx == 0xffff)
2642 {
2643 SelectObject(hdc, hfont_prev);
2644 DeleteObject(hfont);
2645 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2646 return;
2647 }
2648
2649 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2650 memset(&gm1, 0xab, sizeof(gm1));
2651 SetLastError(0xdeadbeef);
2652 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2653 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2654
2655 SelectObject(hdc, hfont_prev);
2656 DeleteObject(hfont);
2657
2658 SetLastError(0xdeadbeef);
2659 hfont = CreateFontIndirectA(&lf2);
2660 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2661 check_font("negative width", &lf2, hfont);
2662
2663 hfont_prev = SelectObject(hdc, hfont);
2664
2665 memset(&gm2, 0xbb, sizeof(gm2));
2666 SetLastError(0xdeadbeef);
2667 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2668 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2669
2670 SelectObject(hdc, hfont_prev);
2671 DeleteObject(hfont);
2672
2673 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2674 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2675 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2676 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2677 gm1.gmCellIncX == gm2.gmCellIncX &&
2678 gm1.gmCellIncY == gm2.gmCellIncY,
2679 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2680 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2681 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2682 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2683 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2684 }
2685
2686 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2687 #include "pshpack2.h"
2688 typedef struct
2689 {
2690 USHORT version;
2691 SHORT xAvgCharWidth;
2692 USHORT usWeightClass;
2693 USHORT usWidthClass;
2694 SHORT fsType;
2695 SHORT ySubscriptXSize;
2696 SHORT ySubscriptYSize;
2697 SHORT ySubscriptXOffset;
2698 SHORT ySubscriptYOffset;
2699 SHORT ySuperscriptXSize;
2700 SHORT ySuperscriptYSize;
2701 SHORT ySuperscriptXOffset;
2702 SHORT ySuperscriptYOffset;
2703 SHORT yStrikeoutSize;
2704 SHORT yStrikeoutPosition;
2705 SHORT sFamilyClass;
2706 PANOSE panose;
2707 ULONG ulUnicodeRange1;
2708 ULONG ulUnicodeRange2;
2709 ULONG ulUnicodeRange3;
2710 ULONG ulUnicodeRange4;
2711 CHAR achVendID[4];
2712 USHORT fsSelection;
2713 USHORT usFirstCharIndex;
2714 USHORT usLastCharIndex;
2715 /* According to the Apple spec, original version didn't have the below fields,
2716 * version numbers were taken from the OpenType spec.
2717 */
2718 /* version 0 (TrueType 1.5) */
2719 USHORT sTypoAscender;
2720 USHORT sTypoDescender;
2721 USHORT sTypoLineGap;
2722 USHORT usWinAscent;
2723 USHORT usWinDescent;
2724 /* version 1 (TrueType 1.66) */
2725 ULONG ulCodePageRange1;
2726 ULONG ulCodePageRange2;
2727 /* version 2 (OpenType 1.2) */
2728 SHORT sxHeight;
2729 SHORT sCapHeight;
2730 USHORT usDefaultChar;
2731 USHORT usBreakChar;
2732 USHORT usMaxContext;
2733 } TT_OS2_V2;
2734 #include "poppack.h"
2735
2736 #ifdef WORDS_BIGENDIAN
2737 #define GET_BE_WORD(x) (x)
2738 #define GET_BE_DWORD(x) (x)
2739 #else
2740 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2741 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2742 #endif
2743
2744 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2745 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2746 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2747 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2748 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2749 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2750
2751 typedef struct
2752 {
2753 USHORT version;
2754 USHORT num_tables;
2755 } cmap_header;
2756
2757 typedef struct
2758 {
2759 USHORT plat_id;
2760 USHORT enc_id;
2761 ULONG offset;
2762 } cmap_encoding_record;
2763
2764 typedef struct
2765 {
2766 USHORT format;
2767 USHORT length;
2768 USHORT language;
2769
2770 BYTE glyph_ids[256];
2771 } cmap_format_0;
2772
2773 typedef struct
2774 {
2775 USHORT format;
2776 USHORT length;
2777 USHORT language;
2778
2779 USHORT seg_countx2;
2780 USHORT search_range;
2781 USHORT entry_selector;
2782 USHORT range_shift;
2783
2784 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2785 /* Then follows:
2786 USHORT pad;
2787 USHORT start_count[seg_countx2 / 2];
2788 USHORT id_delta[seg_countx2 / 2];
2789 USHORT id_range_offset[seg_countx2 / 2];
2790 USHORT glyph_ids[];
2791 */
2792 } cmap_format_4;
2793
2794 typedef struct
2795 {
2796 USHORT end_count;
2797 USHORT start_count;
2798 USHORT id_delta;
2799 USHORT id_range_offset;
2800 } cmap_format_4_seg;
2801
2802 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2803 {
2804 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2805 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2806 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2807 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2808 os2->panose.bWeight, os2->panose.bProportion);
2809 }
2810
2811 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2812 {
2813 int i;
2814 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2815
2816 *first = 256;
2817
2818 for(i = 0; i < 256; i++)
2819 {
2820 if(cmap->glyph_ids[i] == 0) continue;
2821 *last = i;
2822 if(*first == 256) *first = i;
2823 }
2824 if(*first == 256) return FALSE;
2825 return TRUE;
2826 }
2827
2828 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2829 {
2830 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2831 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2832 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2833 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2834 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2835 }
2836
2837 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2838 {
2839 int i;
2840 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2841 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2842 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2843
2844 *first = 0x10000;
2845
2846 for(i = 0; i < seg_count; i++)
2847 {
2848 DWORD code, index;
2849 cmap_format_4_seg seg;
2850
2851 get_seg4(cmap, i, &seg);
2852 for(code = seg.start_count; code <= seg.end_count; code++)
2853 {
2854 if(seg.id_range_offset == 0)
2855 index = (seg.id_delta + code) & 0xffff;
2856 else
2857 {
2858 index = seg.id_range_offset / 2
2859 + code - seg.start_count
2860 + i - seg_count;
2861
2862 /* some fonts have broken last segment */
2863 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2864 index = GET_BE_WORD(glyph_ids[index]);
2865 else
2866 {
2867 trace("segment %04x/%04x index %04x points to nowhere\n",
2868 seg.start_count, seg.end_count, index);
2869 index = 0;
2870 }
2871 if(index) index += seg.id_delta;
2872 }
2873 if(*first == 0x10000)
2874 *last = *first = code;
2875 else if(index)
2876 *last = code;
2877 }
2878 }
2879
2880 if(*first == 0x10000) return FALSE;
2881 return TRUE;
2882 }
2883
2884 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2885 {
2886 USHORT i;
2887 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2888
2889 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2890 {
2891 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2892 return (BYTE *)header + GET_BE_DWORD(record->offset);
2893 record++;
2894 }
2895 return NULL;
2896 }
2897
2898 typedef enum
2899 {
2900 cmap_none,
2901 cmap_ms_unicode,
2902 cmap_ms_symbol
2903 } cmap_type;
2904
2905 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2906 {
2907 LONG size, ret;
2908 cmap_header *header;
2909 void *cmap;
2910 BOOL r = FALSE;
2911 WORD format;
2912
2913 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2914 ok(size != GDI_ERROR, "no cmap table found\n");
2915 if(size == GDI_ERROR) return FALSE;
2916
2917 header = HeapAlloc(GetProcessHeap(), 0, size);
2918 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2919 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2920 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2921
2922 cmap = get_cmap(header, 3, 1);
2923 if(cmap)
2924 *cmap_type = cmap_ms_unicode;
2925 else
2926 {
2927 cmap = get_cmap(header, 3, 0);
2928 if(cmap) *cmap_type = cmap_ms_symbol;
2929 }
2930 if(!cmap)
2931 {
2932 *cmap_type = cmap_none;
2933 goto end;
2934 }
2935
2936 format = GET_BE_WORD(*(WORD *)cmap);
2937 switch(format)
2938 {
2939 case 0:
2940 r = get_first_last_from_cmap0(cmap, first, last);
2941 break;
2942 case 4:
2943 r = get_first_last_from_cmap4(cmap, first, last, size);
2944 break;
2945 default:
2946 trace("unhandled cmap format %d\n", format);
2947 break;
2948 }
2949
2950 end:
2951 HeapFree(GetProcessHeap(), 0, header);
2952 return r;
2953 }
2954
2955 #define TT_PLATFORM_MICROSOFT 3
2956 #define TT_MS_ID_SYMBOL_CS 0
2957 #define TT_MS_ID_UNICODE_CS 1
2958 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2959 #define TT_NAME_ID_FONT_FAMILY 1
2960 #define TT_NAME_ID_FONT_SUBFAMILY 2
2961 #define TT_NAME_ID_UNIQUE_ID 3
2962 #define TT_NAME_ID_FULL_NAME 4
2963
2964 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2965 {
2966 struct sfnt_name_header
2967 {
2968 USHORT format;
2969 USHORT number_of_record;
2970 USHORT storage_offset;
2971 } *header;
2972 struct sfnt_name
2973 {
2974 USHORT platform_id;
2975 USHORT encoding_id;
2976 USHORT language_id;
2977 USHORT name_id;
2978 USHORT length;
2979 USHORT offset;
2980 } *entry;
2981 BOOL r = FALSE;
2982 LONG size, offset, length;
2983 LONG c, ret;
2984 WCHAR *name;
2985 BYTE *data;
2986 USHORT i;
2987
2988 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2989 ok(size != GDI_ERROR, "no name table found\n");
2990 if(size == GDI_ERROR) return FALSE;
2991
2992 data = HeapAlloc(GetProcessHeap(), 0, size);
2993 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2994 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2995
2996 header = (void *)data;
2997 header->format = GET_BE_WORD(header->format);
2998 header->number_of_record = GET_BE_WORD(header->number_of_record);
2999 header->storage_offset = GET_BE_WORD(header->storage_offset);
3000 if (header->format != 0)
3001 {
3002 trace("got format %u\n", header->format);
3003 goto out;
3004 }
3005 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
3006 {
3007 trace("number records out of range: %d\n", header->number_of_record);
3008 goto out;
3009 }
3010 if (header->storage_offset >= size)
3011 {
3012 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3013 goto out;
3014 }
3015
3016 entry = (void *)&header[1];
3017 for (i = 0; i < header->number_of_record; i++)
3018 {
3019 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
3020 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
3021 GET_BE_WORD(entry[i].language_id) != language_id ||
3022 GET_BE_WORD(entry[i].name_id) != name_id)
3023 {
3024 continue;
3025 }
3026
3027 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
3028 length = GET_BE_WORD(entry[i].length);
3029 if (offset + length > size)
3030 {
3031 trace("entry %d is out of range\n", i);
3032 break;
3033 }
3034 if (length >= out_size)
3035 {
3036 trace("buffer too small for entry %d\n", i);
3037 break;
3038 }
3039
3040 name = (WCHAR *)(data + offset);
3041 for (c = 0; c < length / 2; c++)
3042 out_buf[c] = GET_BE_WORD(name[c]);
3043 out_buf[c] = 0;
3044
3045 r = TRUE;
3046 break;
3047 }
3048
3049 out:
3050 HeapFree(GetProcessHeap(), 0, data);
3051 return r;
3052 }
3053
3054 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
3055 {
3056 HDC hdc;
3057 HFONT hfont, hfont_old;
3058 TEXTMETRICA tmA;
3059 TT_OS2_V2 tt_os2;
3060 LONG size, ret;
3061 const char *font_name = lf->lfFaceName;
3062 DWORD cmap_first = 0, cmap_last = 0;
3063 UINT ascent, descent, cell_height;
3064 cmap_type cmap_type;
3065 BOOL sys_lang_non_english;
3066
3067 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3068 hdc = GetDC(0);
3069
3070 SetLastError(0xdeadbeef);
3071 hfont = CreateFontIndirectA(lf);
3072 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3073
3074 hfont_old = SelectObject(hdc, hfont);
3075
3076 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3077 if (size == GDI_ERROR)
3078 {
3079 trace("OS/2 chunk was not found\n");
3080 goto end_of_test;
3081 }
3082 if (size > sizeof(tt_os2))
3083 {
3084 trace("got too large OS/2 chunk of size %u\n", size);
3085 size = sizeof(tt_os2);
3086 }
3087
3088 memset(&tt_os2, 0, sizeof(tt_os2));
3089 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3090 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3091
3092 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3093 descent = GET_BE_WORD(tt_os2.usWinDescent);
3094 cell_height = ascent + descent;
3095 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3096 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3097
3098 SetLastError(0xdeadbeef);
3099 ret = GetTextMetricsA(hdc, &tmA);
3100 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3101
3102 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3103 {
3104 skip("Unable to retrieve first and last glyphs from cmap\n");
3105 }
3106 else
3107 {
3108 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3109 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3110 UINT os2_first_char, os2_last_char, default_char, break_char;
3111 USHORT version;
3112 TEXTMETRICW tmW;
3113
3114 version = GET_BE_WORD(tt_os2.version);
3115
3116 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3117 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3118 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3119 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3120
3121 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3122 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3123 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3124
3125 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3126 {
3127 expect_first_W = 0;
3128 switch(GetACP())
3129 {
3130 case 1257: /* Baltic */
3131 expect_last_W = 0xf8fd;
3132 break;
3133 default:
3134 expect_last_W = 0xf0ff;
3135 }
3136 expect_break_W = 0x20;
3137 expect_default_W = expect_break_W - 1;
3138 expect_first_A = 0x1e;
3139 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3140 }
3141 else
3142 {
3143 expect_first_W = cmap_first;
3144 expect_last_W = min(cmap_last, os2_last_char);
3145 if(os2_first_char <= 1)
3146 expect_break_W = os2_first_char + 2;
3147 else if(os2_first_char > 0xff)
3148 expect_break_W = 0x20;
3149 else
3150 expect_break_W = os2_first_char;
3151 expect_default_W = expect_break_W - 1;
3152 expect_first_A = expect_default_W - 1;
3153 expect_last_A = min(expect_last_W, 0xff);
3154 }
3155 expect_break_A = expect_break_W;
3156 expect_default_A = expect_default_W;
3157
3158 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3159 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3160 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3161 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3162 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3163 else
3164 ok(tmA.tmFirstChar == expect_first_A ||
3165 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3166 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3167 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3168 ok(tmA.tmLastChar == expect_last_A ||
3169 tmA.tmLastChar == 0xff /* win9x */,
3170 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3171 else
3172 skip("tmLastChar is DBCS lead byte\n");
3173 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3174 font_name, tmA.tmBreakChar, expect_break_A);
3175 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3176 "A: tmDefaultChar for %s got %02x expected %02x\n",
3177 font_name, tmA.tmDefaultChar, expect_default_A);
3178
3179
3180 SetLastError(0xdeadbeef);
3181 ret = GetTextMetricsW(hdc, &tmW);
3182 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3183 "GetTextMetricsW error %u\n", GetLastError());
3184 if (ret)
3185 {
3186 /* Wine uses the os2 first char */
3187 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3188 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3189 font_name, tmW.tmFirstChar, expect_first_W);
3190 else
3191 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3192 font_name, tmW.tmFirstChar, expect_first_W);
3193
3194 /* Wine uses the os2 last char */
3195 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3196 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3197 font_name, tmW.tmLastChar, expect_last_W);
3198 else
3199 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3200 font_name, tmW.tmLastChar, expect_last_W);
3201 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3202 font_name, tmW.tmBreakChar, expect_break_W);
3203 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3204 "W: tmDefaultChar for %s got %02x expected %02x\n",
3205 font_name, tmW.tmDefaultChar, expect_default_W);
3206
3207 /* Test the aspect ratio while we have tmW */
3208 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3209 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3210 tmW.tmDigitizedAspectX, ret);
3211 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3212 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3213 tmW.tmDigitizedAspectX, ret);
3214 }
3215 }
3216
3217 /* test FF_ values */
3218 switch(tt_os2.panose.bFamilyType)
3219 {
3220 case PAN_ANY:
3221 case PAN_NO_FIT:
3222 case PAN_FAMILY_TEXT_DISPLAY:
3223 case PAN_FAMILY_PICTORIAL:
3224 default:
3225 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3226 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3227 {
3228 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3229 break;
3230 }
3231 switch(tt_os2.panose.bSerifStyle)
3232 {
3233 case PAN_ANY:
3234 case PAN_NO_FIT:
3235 default:
3236 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3237 break;
3238
3239 case PAN_SERIF_COVE:
3240 case PAN_SERIF_OBTUSE_COVE:
3241 case PAN_SERIF_SQUARE_COVE:
3242 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3243 case PAN_SERIF_SQUARE:
3244 case PAN_SERIF_THIN:
3245 case PAN_SERIF_BONE:
3246 case PAN_SERIF_EXAGGERATED:
3247 case PAN_SERIF_TRIANGLE:
3248 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3249 break;
3250
3251 case PAN_SERIF_NORMAL_SANS:
3252 case PAN_SERIF_OBTUSE_SANS:
3253 case PAN_SERIF_PERP_SANS:
3254 case PAN_SERIF_FLARED:
3255 case PAN_SERIF_ROUNDED:
3256 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3257 break;
3258 }
3259 break;
3260
3261 case PAN_FAMILY_SCRIPT:
3262 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3263 break;
3264
3265 case PAN_FAMILY_DECORATIVE:
3266 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3267 break;
3268 }
3269
3270 test_negative_width(hdc, lf);
3271
3272 end_of_test:
3273 SelectObject(hdc, hfont_old);
3274 DeleteObject(hfont);
3275
3276 ReleaseDC(0, hdc);
3277 }
3278
3279 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3280 {
3281 INT *enumed = (INT *)lParam;
3282
3283 if (type == TRUETYPE_FONTTYPE)
3284 {
3285 (*enumed)++;
3286 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3287 }
3288 return 1;
3289 }
3290
3291 static void test_GetTextMetrics(void)
3292 {
3293 LOGFONTA lf;
3294 HDC hdc;
3295 INT enumed;
3296
3297 /* Report only once */
3298 if(!pGetGlyphIndicesA)
3299 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3300
3301 hdc = GetDC(0);
3302
3303 memset(&lf, 0, sizeof(lf));
3304 lf.lfCharSet = DEFAULT_CHARSET;
3305 enumed = 0;
3306 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3307 trace("Tested metrics of %d truetype fonts\n", enumed);
3308
3309 ReleaseDC(0, hdc);
3310 }
3311
3312 static void test_nonexistent_font(void)
3313 {
3314 static const struct
3315 {
3316 const char *name;
3317 int charset;
3318 } font_subst[] =
3319 {
3320 { "Times New Roman Baltic", 186 },
3321 { "Times New Roman CE", 238 },
3322 { "Times New Roman CYR", 204 },
3323 { "Times New Roman Greek", 161 },
3324 { "Times New Roman TUR", 162 }
3325 };
3326 LOGFONTA lf;
3327 HDC hdc;
3328 HFONT hfont;
3329 CHARSETINFO csi;
3330 INT cs, expected_cs, i;
3331 char buf[LF_FACESIZE];
3332
3333 if (!is_truetype_font_installed("Arial") ||
3334 !is_truetype_font_installed("Times New Roman"))
3335 {
3336 skip("Arial or Times New Roman not installed\n");
3337 return;
3338 }
3339
3340 expected_cs = GetACP();
3341 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3342 {
3343 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3344 return;
3345 }
3346 expected_cs = csi.ciCharset;
3347 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3348
3349 hdc = GetDC(0);
3350
3351 memset(&lf, 0, sizeof(lf));
3352 lf.lfHeight = 100;
3353 lf.lfWeight = FW_REGULAR;
3354 lf.lfCharSet = ANSI_CHARSET;
3355 lf.lfPitchAndFamily = FF_SWISS;
3356 strcpy(lf.lfFaceName, "Nonexistent font");
3357 hfont = CreateFontIndirectA(&lf);
3358 hfont = SelectObject(hdc, hfont);
3359 GetTextFaceA(hdc, sizeof(buf), buf);
3360 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3361 cs = GetTextCharset(hdc);
3362 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3363 DeleteObject(SelectObject(hdc, hfont));
3364
3365 memset(&lf, 0, sizeof(lf));
3366 lf.lfHeight = -13;
3367 lf.lfWeight = FW_DONTCARE;
3368 strcpy(lf.lfFaceName, "Nonexistent font");
3369 hfont = CreateFontIndirectA(&lf);
3370 hfont = SelectObject(hdc, hfont);
3371 GetTextFaceA(hdc, sizeof(buf), buf);
3372 todo_wine /* Wine uses Arial for all substitutions */
3373 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3374 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3375 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3376 "Got %s\n", buf);
3377 cs = GetTextCharset(hdc);
3378 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3379 DeleteObject(SelectObject(hdc, hfont));
3380
3381 memset(&lf, 0, sizeof(lf));
3382 lf.lfHeight = -13;
3383 lf.lfWeight = FW_REGULAR;
3384 strcpy(lf.lfFaceName, "Nonexistent font");
3385 hfont = CreateFontIndirectA(&lf);
3386 hfont = SelectObject(hdc, hfont);
3387 GetTextFaceA(hdc, sizeof(buf), buf);
3388 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3389 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3390 cs = GetTextCharset(hdc);
3391 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3392 DeleteObject(SelectObject(hdc, hfont));
3393
3394 memset(&lf, 0, sizeof(lf));
3395 lf.lfHeight = -13;
3396 lf.lfWeight = FW_DONTCARE;
3397 strcpy(lf.lfFaceName, "Times New Roman");
3398 hfont = CreateFontIndirectA(&lf);
3399 hfont = SelectObject(hdc, hfont);
3400 GetTextFaceA(hdc, sizeof(buf), buf);
3401 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3402 cs = GetTextCharset(hdc);
3403 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3404 DeleteObject(SelectObject(hdc, hfont));
3405
3406 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3407 {
3408 memset(&lf, 0, sizeof(lf));
3409 lf.lfHeight = -13;
3410 lf.lfWeight = FW_REGULAR;
3411 strcpy(lf.lfFaceName, font_subst[i].name);
3412 hfont = CreateFontIndirectA(&lf);
3413 hfont = SelectObject(hdc, hfont);
3414 cs = GetTextCharset(hdc);
3415 if (font_subst[i].charset == expected_cs)
3416 {
3417 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3418 GetTextFaceA(hdc, sizeof(buf), buf);
3419 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3420 }
3421 else
3422 {
3423 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3424 GetTextFaceA(hdc, sizeof(buf), buf);
3425 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3426 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3427 }
3428 DeleteObject(SelectObject(hdc, hfont));
3429
3430 memset(&lf, 0, sizeof(lf));
3431 lf.lfHeight = -13;
3432 lf.lfWeight = FW_DONTCARE;
3433 strcpy(lf.lfFaceName, font_subst[i].name);
3434 hfont = CreateFontIndirectA(&lf);
3435 hfont = SelectObject(hdc, hfont);
3436 GetTextFaceA(hdc, sizeof(buf), buf);
3437 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3438 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3439 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3440 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3441 "got %s for font %s\n", buf, font_subst[i].name);
3442 cs = GetTextCharset(hdc);
3443 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3444 DeleteObject(SelectObject(hdc, hfont));
3445 }
3446
3447 ReleaseDC(0, hdc);
3448 }
3449
3450 static void test_GdiRealizationInfo(void)
3451 {
3452 HDC hdc;
3453 DWORD info[4];
3454 BOOL r;
3455 HFONT hfont, hfont_old;
3456 LOGFONTA lf;
3457
3458 if(!pGdiRealizationInfo)
3459 {
3460 win_skip("GdiRealizationInfo not available\n");
3461 return;
3462 }
3463
3464 hdc = GetDC(0);
3465
3466 memset(info, 0xcc, sizeof(info));
3467 r = pGdiRealizationInfo(hdc, info);
3468 ok(r != 0, "ret 0\n");
3469 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3470 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3471
3472 if (!is_truetype_font_installed("Arial"))
3473 {
3474 skip("skipping GdiRealizationInfo with truetype font\n");
3475 goto end;
3476 }
3477
3478 memset(&lf, 0, sizeof(lf));
3479 strcpy(lf.lfFaceName, "Arial");
3480 lf.lfHeight = 20;
3481 lf.lfWeight = FW_NORMAL;
3482 hfont = CreateFontIndirectA(&lf);
3483 hfont_old = SelectObject(hdc, hfont);
3484
3485 memset(info, 0xcc, sizeof(info));
3486 r = pGdiRealizationInfo(hdc, info);
3487 ok(r != 0, "ret 0\n");
3488 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3489 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3490
3491 DeleteObject(SelectObject(hdc, hfont_old));
3492
3493 end:
3494 ReleaseDC(0, hdc);
3495 }
3496
3497 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3498 the nul in the count of characters copied when the face name buffer is not
3499 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3500 always includes it. */
3501 static void test_GetTextFace(void)
3502 {
3503 static const char faceA[] = "Tahoma";
3504 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3505 LOGFONTA fA = {0};
3506 LOGFONTW fW = {0};
3507 char bufA[LF_FACESIZE];
3508 WCHAR bufW[LF_FACESIZE];
3509 HFONT f, g;
3510 HDC dc;
3511 int n;
3512
3513 if(!is_font_installed("Tahoma"))
3514 {
3515 skip("Tahoma is not installed so skipping this test\n");
3516 return;
3517 }
3518
3519 /* 'A' case. */
3520 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3521 f = CreateFontIndirectA(&fA);
3522 ok(f != NULL, "CreateFontIndirectA failed\n");
3523
3524 dc = GetDC(NULL);
3525 g = SelectObject(dc, f);
3526 n = GetTextFaceA(dc, sizeof bufA, bufA);
3527 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3528 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3529
3530 /* Play with the count arg. */
3531 bufA[0] = 'x';
3532 n = GetTextFaceA(dc, 0, bufA);
3533 ok(n == 0, "GetTextFaceA returned %d\n", n);
3534 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3535
3536 bufA[0] = 'x';
3537 n = GetTextFaceA(dc, 1, bufA);
3538 ok(n == 0, "GetTextFaceA returned %d\n", n);
3539 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3540
3541 bufA[0] = 'x'; bufA[1] = 'y';
3542 n = GetTextFaceA(dc, 2, bufA);
3543 ok(n == 1, "GetTextFaceA returned %d\n", n);
3544 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3545
3546 n = GetTextFaceA(dc, 0, NULL);
3547 ok(n == sizeof faceA ||
3548 broken(n == 0), /* win98, winMe */
3549 "GetTextFaceA returned %d\n", n);
3550
3551 DeleteObject(SelectObject(dc, g));
3552 ReleaseDC(NULL, dc);
3553
3554 /* 'W' case. */
3555 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3556 SetLastError(0xdeadbeef);
3557 f = CreateFontIndirectW(&fW);
3558 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3559 {
3560 win_skip("CreateFontIndirectW is not implemented\n");
3561 return;
3562 }
3563 ok(f != NULL, "CreateFontIndirectW failed\n");
3564
3565 dc = GetDC(NULL);
3566 g = SelectObject(dc, f);
3567 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3568 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3569 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3570
3571 /* Play with the count arg. */
3572 bufW[0] = 'x';
3573 n = GetTextFaceW(dc, 0, bufW);
3574 ok(n == 0, "GetTextFaceW returned %d\n", n);
3575 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3576
3577 bufW[0] = 'x';
3578 n = GetTextFaceW(dc, 1, bufW);
3579 ok(n == 1, "GetTextFaceW returned %d\n", n);
3580 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3581
3582 bufW[0] = 'x'; bufW[1] = 'y';
3583 n = GetTextFaceW(dc, 2, bufW);
3584 ok(n == 2, "GetTextFaceW returned %d\n", n);
3585 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3586
3587 n = GetTextFaceW(dc, 0, NULL);
3588 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3589
3590 DeleteObject(SelectObject(dc, g));
3591 ReleaseDC(NULL, dc);
3592 }
3593
3594 static void test_orientation(void)
3595 {
3596 static const char test_str[11] = "Test String";
3597 HDC hdc;
3598 LOGFONTA lf;
3599 HFONT hfont, old_hfont;
3600 SIZE size;
3601
3602 if (!is_truetype_font_installed("Arial"))
3603 {
3604 skip("Arial is not installed\n");
3605 return;
3606 }
3607
3608 hdc = CreateCompatibleDC(0);
3609 memset(&lf, 0, sizeof(lf));
3610 lstrcpyA(lf.lfFaceName, "Arial");
3611 lf.lfHeight = 72;
3612 lf.lfOrientation = lf.lfEscapement = 900;
3613 hfont = create_font("orientation", &lf);
3614 old_hfont = SelectObject(hdc, hfont);
3615 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3616 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3617 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3618 SelectObject(hdc, old_hfont);
3619 DeleteObject(hfont);
3620 DeleteDC(hdc);
3621 }
3622
3623 static void test_oemcharset(void)
3624 {
3625 HDC hdc;
3626 LOGFONTA lf, clf;
3627 HFONT hfont, old_hfont;
3628 int charset;
3629
3630 hdc = CreateCompatibleDC(0);
3631 ZeroMemory(&lf, sizeof(lf));
3632 lf.lfHeight = 12;
3633 lf.lfCharSet = OEM_CHARSET;
3634 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3635 lstrcpyA(lf.lfFaceName, "Terminal");
3636 hfont = CreateFontIndirectA(&lf);
3637 old_hfont = SelectObject(hdc, hfont);
3638 charset = GetTextCharset(hdc);
3639 todo_wine
3640 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3641 hfont = SelectObject(hdc, old_hfont);
3642 GetObjectA(hfont, sizeof(clf), &clf);
3643 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3644 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3645 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3646 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3647 DeleteObject(hfont);
3648 DeleteDC(hdc);
3649 }
3650
3651 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONT *lpelfe,
3652 const TEXTMETRIC *lpntme,
3653 DWORD FontType, LPARAM lParam)
3654 {
3655 const NEWTEXTMETRICEX *lpntmex = (const NEWTEXTMETRICEX *)lpntme;
3656 CHARSETINFO csi;
3657 LOGFONT lf = *lpelfe;
3658 HFONT hfont;
3659
3660 /* skip bitmap, proportional or vertical font */
3661 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
3662 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
3663 lf.lfFaceName[0] == '@')
3664 return 1;
3665
3666 /* skip linked font */
3667 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
3668 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
3669 return 1;
3670
3671 /* test with an odd height */
3672 lf.lfHeight = -19;
3673 lf.lfWidth = 0;
3674 hfont = CreateFontIndirect(&lf);
3675 if (hfont)
3676 {
3677 *(HFONT *)lParam = hfont;
3678 return 0;
3679 }
3680 return 1;
3681 }
3682
3683 static void test_GetGlyphOutline(void)
3684 {
3685 HDC hdc;
3686 GLYPHMETRICS gm, gm2;
3687 LOGFONTA lf;
3688 HFONT hfont, old_hfont;
3689 INT ret, ret2;
3690 static const struct
3691 {
3692 UINT cs;
3693 UINT a;
3694 UINT w;
3695 } c[] =
3696 {
3697 {ANSI_CHARSET, 0x30, 0x30},
3698 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3699 {HANGEUL_CHARSET, 0x8141, 0xac02},
3700 {JOHAB_CHARSET, 0x8446, 0x3135},
3701 {GB2312_CHARSET, 0x8141, 0x4e04},
3702 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3703 };
3704 UINT i;
3705
3706 if (!is_truetype_font_installed("Tahoma"))
3707 {
3708 skip("Tahoma is not installed\n");
3709 return;
3710 }
3711
3712 hdc = CreateCompatibleDC(0);
3713 memset(&lf, 0, sizeof(lf));
3714 lf.lfHeight = 72;
3715 lstrcpyA(lf.lfFaceName, "Tahoma");
3716 SetLastError(0xdeadbeef);
3717 hfont = CreateFontIndirectA(&lf);
3718 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3719 old_hfont = SelectObject(hdc, hfont);
3720
3721 memset(&gm, 0, sizeof(gm));
3722 SetLastError(0xdeadbeef);
3723 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3724 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3725
3726 memset(&gm, 0, sizeof(gm));
3727 SetLastError(0xdeadbeef);
3728 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3729 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3730 ok(GetLastError() == 0xdeadbeef ||
3731 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3732 "expected 0xdeadbeef, got %u\n", GetLastError());
3733
3734 memset(&gm, 0, sizeof(gm));
3735 SetLastError(0xdeadbeef);
3736 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3737 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3738 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3739
3740 memset(&gm, 0, sizeof(gm));
3741 SetLastError(0xdeadbeef);
3742 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3743 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3744 {
3745 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3746 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3747 }
3748
3749 /* test for needed buffer size request on space char */
3750 memset(&gm, 0, sizeof(gm));
3751 SetLastError(0xdeadbeef);
3752 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3753 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3754 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3755
3756 /* requesting buffer size for space char + error */
3757 memset(&gm, 0, sizeof(gm));
3758 SetLastError(0xdeadbeef);
3759 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3760 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3761 {
3762 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3763 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3764 }
3765
3766 SelectObject(hdc, old_hfont);
3767 DeleteObject(hfont);
3768
3769 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3770 {
3771 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
3772
3773 lf.lfFaceName[0] = '\0';
3774 lf.lfCharSet = c[i].cs;
3775 lf.lfPitchAndFamily = 0;
3776 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3777 {
3778 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3779 continue;
3780 }
3781
3782 old_hfont = SelectObject(hdc, hfont);
3783
3784 /* expected to ignore superfluous bytes (sigle-byte character) */
3785 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3786 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3787 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3788
3789 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3790 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3791 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3792
3793 /* expected to ignore superfluous bytes (double-byte character) */
3794 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3795 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3796 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3797 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3798
3799 /* expected to match wide-char version results */
3800 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3801 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3802
3803 if (EnumFontFamiliesEx(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
3804 {
3805 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
3806 continue;
3807 }
3808 DeleteObject(SelectObject(hdc, hfont));
3809 if (c[i].a <= 0xff)
3810 {
3811 DeleteObject(SelectObject(hdc, old_hfont));
3812 continue;
3813 }
3814
3815 ret = GetObject(hfont, sizeof lf, &lf);
3816 ok(ret > 0, "GetObject error %u\n", GetLastError());
3817
3818 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3819 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3820 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
3821 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3822 trace("Tests with height=%d,half=%d,full=%d,face=%s,charset=%d\n",
3823 -lf.lfHeight, gm.gmCellIncX, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
3824 ok(gm2.gmCellIncX == gm.gmCellIncX * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
3825 "expected %d, got %d (%s:%d)\n",
3826 gm.gmCellIncX * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
3827
3828 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
3829 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3830 ok(gm2.gmCellIncY == -lf.lfHeight,
3831 "expected %d, got %d (%s:%d)\n",
3832 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
3833
3834 lf.lfItalic = TRUE;
3835 hfont = CreateFontIndirect(&lf);
3836 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
3837 DeleteObject(SelectObject(hdc, hfont));
3838 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3839 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3840 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
3841 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3842 ok(gm2.gmCellIncX == gm.gmCellIncX * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
3843 "expected %d, got %d (%s:%d)\n",
3844 gm.gmCellIncX * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
3845
3846 lf.lfItalic = FALSE;
3847 lf.lfEscapement = lf.lfOrientation = 2700;
3848 hfont = CreateFontIndirect(&lf);
3849 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
3850 DeleteObject(SelectObject(hdc, hfont));
3851 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
3852 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3853 ok(gm2.gmCellIncY == -lf.lfHeight,
3854 "expected %d, got %d (%s:%d)\n",
3855 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
3856
3857 hfont = SelectObject(hdc, old_hfont);
3858 DeleteObject(hfont);
3859 }
3860
3861 DeleteDC(hdc);
3862 }
3863
3864 /* bug #9995: there is a limit to the character width that can be specified */
3865 static void test_GetTextMetrics2(const char *fontname, int font_height)
3866 {
3867 HFONT of, hf;
3868 HDC hdc;
3869 TEXTMETRICA tm;
3870 BOOL ret;
3871 int ave_width, height, width, ratio, scale;
3872
3873 if (!is_truetype_font_installed( fontname)) {
3874 skip("%s is not installed\n", fontname);
3875 return;
3876 }
3877 hdc = CreateCompatibleDC(0);
3878 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3879 /* select width = 0 */
3880 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3881 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3882 DEFAULT_QUALITY, VARIABLE_PITCH,
3883 fontname);
3884 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3885 of = SelectObject( hdc, hf);
3886 ret = GetTextMetricsA( hdc, &tm);
3887 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3888 height = tm.tmHeight;
3889 ave_width = tm.tmAveCharWidth;
3890 SelectObject( hdc, of);
3891 DeleteObject( hf);
3892
3893 trace("height %d, ave width %d\n", height, ave_width);
3894
3895 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3896 {
3897 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3898 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3899 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3900 ok(hf != 0, "CreateFont failed\n");
3901 of = SelectObject(hdc, hf);
3902 ret = GetTextMetrics(hdc, &tm);
3903 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3904 SelectObject(hdc, of);
3905 DeleteObject(hf);
3906
3907 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3908 break;
3909 }
3910
3911 DeleteDC(hdc);
3912
3913 ratio = width / height;
3914 scale = width / ave_width;
3915
3916 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3917 width, height, ratio, width, ave_width, scale);
3918
3919 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3920 }
3921
3922 static void test_CreateFontIndirect(void)
3923 {
3924 LOGFONTA lf, getobj_lf;
3925 int ret, i;
3926 HFONT hfont;
3927 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3928
3929 memset(&lf, 0, sizeof(lf));
3930 lf.lfCharSet = ANSI_CHARSET;
3931 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3932 lf.lfHeight = 16;
3933 lf.lfWidth = 16;
3934 lf.lfQuality = DEFAULT_QUALITY;
3935 lf.lfItalic = FALSE;
3936 lf.lfWeight = FW_DONTCARE;
3937
3938 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3939 {
3940 lstrcpyA(lf.lfFaceName, TestName[i]);
3941 hfont = CreateFontIndirectA(&lf);
3942 ok(hfont != 0, "CreateFontIndirectA failed\n");
3943 SetLastError(0xdeadbeef);
3944 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3945 ok(ret, "GetObject failed: %d\n", GetLastError());
3946 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3947 ok(lf.lfWeight == getobj_lf.lfWeight ||
3948 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3949 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3950 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3951 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3952 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3953 DeleteObject(hfont);
3954 }
3955 }
3956
3957 static void test_CreateFontIndirectEx(void)
3958 {
3959 ENUMLOGFONTEXDVA lfex;
3960 HFONT hfont;
3961
3962 if (!pCreateFontIndirectExA)
3963 {
3964 win_skip("CreateFontIndirectExA is not available\n");
3965 return;
3966 }
3967
3968 if (!is_truetype_font_installed("Arial"))
3969 {
3970 skip("Arial is not installed\n");
3971 return;
3972 }
3973
3974 SetLastError(0xdeadbeef);
3975 hfont = pCreateFontIndirectExA(NULL);
3976 ok(hfont == NULL, "got %p\n", hfont);
3977 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3978
3979 memset(&lfex, 0, sizeof(lfex));
3980 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3981 hfont = pCreateFontIndirectExA(&lfex);
3982 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3983 if (hfont)
3984 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3985 DeleteObject(hfont);
3986 }
3987
3988 static void free_font(void *font)
3989 {
3990 UnmapViewOfFile(font);
3991 }
3992
3993 static void *load_font(const char *font_name, DWORD *font_size)
3994 {
3995 char file_name[MAX_PATH];
3996 HANDLE file, mapping;
3997 void *font;
3998
3999 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
4000 strcat(file_name, "\\fonts\\");
4001 strcat(file_name, font_name);
4002
4003 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4004 if (file == INVALID_HANDLE_VALUE) return NULL;
4005
4006 *font_size = GetFileSize(file, NULL);
4007
4008 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
4009 if (!mapping)
4010 {
4011 CloseHandle(file);
4012 return NULL;
4013 }
4014
4015 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4016
4017 CloseHandle(file);
4018 CloseHandle(mapping);
4019 return font;
4020 }
4021
4022 static void test_AddFontMemResource(void)
4023 {
4024 void *font;
4025 DWORD font_size, num_fonts;
4026 HANDLE ret;
4027 BOOL bRet;
4028
4029 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4030 {
4031 win_skip("AddFontMemResourceEx is not available on this platform\n");
4032 return;
4033 }
4034
4035 font = load_font("sserife.fon", &font_size);
4036 if (!font)
4037 {
4038 skip("Unable to locate and load font sserife.fon\n");
4039 return;
4040 }
4041
4042 SetLastError(0xdeadbeef);
4043 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4044 ok(!ret, "AddFontMemResourceEx should fail\n");
4045 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4046 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4047 GetLastError());
4048
4049 SetLastError(0xdeadbeef);
4050 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4051 ok(!ret, "AddFontMemResourceEx should fail\n");
4052 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4053 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4054 GetLastError());
4055
4056 SetLastError(0xdeadbeef);
4057 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4058 ok(!ret, "AddFontMemResourceEx should fail\n");
4059 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4060 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4061 GetLastError());
4062
4063 SetLastError(0xdeadbeef);
4064 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4065 ok(!ret, "AddFontMemResourceEx should fail\n");
4066 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4067 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4068 GetLastError());
4069
4070 SetLastError(0xdeadbeef);
4071 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4072 ok(!ret, "AddFontMemResourceEx should fail\n");
4073 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4074 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4075 GetLastError());
4076
4077 SetLastError(0xdeadbeef);
4078 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4079 ok(!ret, "AddFontMemResourceEx should fail\n");
4080 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4081 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4082 GetLastError());
4083
4084 num_fonts = 0xdeadbeef;
4085 SetLastError(0xdeadbeef);
4086 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4087 ok(!ret, "AddFontMemResourceEx should fail\n");
4088 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4089 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4090 GetLastError());
4091 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4092
4093 if (0) /* hangs under windows 2000 */
4094 {
4095 num_fonts = 0xdeadbeef;
4096 SetLastError(0xdeadbeef);
4097 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4098 ok(!ret, "AddFontMemResourceEx should fail\n");
4099 ok(GetLastError() == 0xdeadbeef,
4100 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4101 GetLastError());
4102 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4103 }
4104
4105 num_fonts = 0xdeadbeef;
4106 SetLastError(0xdeadbeef);
4107 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4108 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4109 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4110 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4111
4112 free_font(font);
4113
4114 SetLastError(0xdeadbeef);
4115 bRet = pRemoveFontMemResourceEx(ret);
4116 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4117
4118 /* test invalid pointer to number of loaded fonts */
4119 font = load_font("sserife.fon", &font_size);
4120 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4121
4122 SetLastError(0xdeadbeef);
4123 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4124 ok(!ret, "AddFontMemResourceEx should fail\n");
4125 ok(GetLastError() == 0xdeadbeef,
4126 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4127 GetLastError());
4128
4129 SetLastError(0xdeadbeef);
4130 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4131 ok(!ret, "AddFontMemResourceEx should fail\n");
4132 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4133 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4134 GetLastError());
4135
4136 free_font(font);
4137 }
4138
4139 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
4140 {
4141 LOGFONT *lf;
4142
4143 if (type != TRUETYPE_FONTTYPE) return 1;
4144
4145 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4146
4147 lf = (LOGFONT *)lparam;
4148 *lf = *elf;
4149 return 0;
4150 }
4151
4152 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
4153 {
4154 int ret;
4155 LOGFONT *lf;
4156
4157 if (type != TRUETYPE_FONTTYPE) return 1;
4158
4159 lf = (LOGFONT *)lparam;
4160 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
4161 if(ret == 0)
4162 {
4163 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4164 *lf = *elf;
4165 return 0;
4166 }
4167 return 1;
4168 }
4169
4170 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
4171 {
4172 return lparam;
4173 }
4174
4175 static void test_EnumFonts(void)
4176 {
4177 int ret;
4178 LOGFONT lf;
4179 HDC hdc;
4180
4181 if (!is_truetype_font_installed("Arial"))
4182 {
4183 skip("Arial is not installed\n");
4184 return;
4185 }
4186
4187 /* Windows uses localized font face names, so Arial Bold won't be found */
4188 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4189 {
4190 skip("User locale is not English, skipping the test\n");
4191 return;
4192 }
4193
4194 hdc = CreateCompatibleDC(0);
4195
4196 /* check that the enumproc's retval is returned */
4197 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4198 ok(ret == 0xcafe, "got %08x\n", ret);
4199
4200 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4201 ok(!ret, "font Arial is not enumerated\n");
4202 ret = strcmp(lf.lfFaceName, "Arial");
4203 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4204 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4205
4206 lstrcpy(lf.lfFaceName, "Arial");
4207 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4208 ok(!ret, "font Arial is not enumerated\n");
4209 ret = strcmp(lf.lfFaceName, "Arial");
4210 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4211 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4212
4213 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4214 ok(!ret, "font Arial Bold is not enumerated\n");
4215 ret = strcmp(lf.lfFaceName, "Arial");
4216 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4217 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4218
4219 lstrcpy(lf.lfFaceName, "Arial Bold");
4220 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4221 ok(ret, "font Arial Bold should not be enumerated\n");
4222
4223 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4224 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4225 ret = strcmp(lf.lfFaceName, "Arial");
4226 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4227 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4228
4229 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
4230 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4231 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4232
4233 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4234 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4235
4236 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
4237 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4238 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4239
4240 DeleteDC(hdc);
4241 }
4242
4243 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
4244 {
4245 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
4246 const char *fullname = (const char *)lParam;
4247
4248 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4249
4250 return 1;
4251 }
4252
4253 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4254 {
4255 HDC hdc = GetDC(0);
4256 BOOL ret = FALSE;
4257
4258 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4259 ret = TRUE;
4260
4261 ReleaseDC(0, hdc);
4262 return ret;
4263 }
4264
4265 static void test_fullname(void)
4266 {
4267 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4268 WCHAR bufW[LF_FULLFACESIZE];
4269 char bufA[LF_FULLFACESIZE];
4270 HFONT hfont, of;
4271 LOGFONTA lf;
4272 HDC hdc;
4273 int i;
4274 DWORD ret;
4275
4276 hdc = CreateCompatibleDC(0);
4277 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4278
4279 memset(&lf, 0, sizeof(lf));
4280 lf.lfCharSet = ANSI_CHARSET;
4281 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4282 lf.lfHeight = 16;
4283 lf.lfWidth = 16;
4284 lf.lfQuality = DEFAULT_QUALITY;
4285 lf.lfItalic = FALSE;
4286 lf.lfWeight = FW_DONTCARE;
4287
4288 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4289 {
4290 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4291 {
4292 skip("%s is not installed\n", TestName[i]);
4293 continue;
4294 }
4295
4296 lstrcpyA(lf.lfFaceName, TestName[i]);
4297 hfont = CreateFontIndirectA(&lf);
4298 ok(hfont != 0, "CreateFontIndirectA failed\n");
4299
4300 of = SelectObject(hdc, hfont);
4301 bufW[0] = 0;
4302 bufA[0] = 0;
4303 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4304 ok(ret, "face full name could not be read\n");
4305 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4306 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4307 SelectObject(hdc, of);
4308 DeleteObject(hfont);
4309 }
4310 DeleteDC(hdc);
4311 }
4312
4313 static WCHAR *prepend_at(WCHAR *family)
4314 {
4315 if (!family)
4316 return NULL;
4317
4318 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4319 family[0] = '@';
4320 return family;
4321 }
4322
4323 static void test_fullname2_helper(const char *Family)
4324 {
4325 char *FamilyName, *FaceName, *StyleName, *otmStr;
4326 struct enum_fullname_data efnd;
4327 WCHAR *bufW;
4328 char *bufA;
4329 HFONT hfont, of;
4330 LOGFONTA lf;
4331 HDC hdc;
4332 int i;
4333 DWORD otm_size, ret, buf_size;
4334 OUTLINETEXTMETRICA *otm;
4335 BOOL want_vertical, get_vertical;
4336 want_vertical = ( Family[0] == '@' );
4337
4338 hdc = CreateCompatibleDC(0);
4339 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4340
4341 memset(&lf, 0, sizeof(lf));
4342 lf.lfCharSet = DEFAULT_CHARSET;
4343 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4344 lf.lfHeight = 16;
4345 lf.lfWidth = 16;
4346 lf.lfQuality = DEFAULT_QUALITY;
4347 lf.lfItalic = FALSE;
4348 lf.lfWeight = FW_DONTCARE;
4349 lstrcpy(lf.lfFaceName, Family);
4350 efnd.total = 0;
4351 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4352 if (efnd.total == 0)
4353 skip("%s is not installed\n", lf.lfFaceName);
4354
4355 for (i = 0; i < efnd.total; i++)
4356 {
4357 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4358 FaceName = (char *)efnd.elf[i].elfFullName;
4359 StyleName = (char *)efnd.elf[i].elfStyle;
4360
4361 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4362
4363 get_vertical = ( FamilyName[0] == '@' );
4364 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4365
4366 lstrcpyA(lf.lfFaceName, FaceName);
4367 hfont = CreateFontIndirectA(&lf);
4368 ok(hfont != 0, "CreateFontIndirectA failed\n");
4369
4370 of = SelectObject(hdc, hfont);
4371 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4372 ok(buf_size != GDI_ERROR, "no name table found\n");
4373 if (buf_size == GDI_ERROR) continue;
4374
4375 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4376 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4377
4378 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4379 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4380 memset(otm, 0, otm_size);
4381 ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4382 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4383 if (ret == 0) continue;
4384
4385 bufW[0] = 0;
4386 bufA[0] = 0;
4387 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4388 if (!ret)
4389 {
4390 trace("no localized FONT_FAMILY found.\n");
4391 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4392 }
4393 ok(ret, "FAMILY (family name) could not be read\n");
4394 if (want_vertical) bufW = prepend_at(bufW);
4395 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4396 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4397 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4398 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4399
4400 bufW[0] = 0;
4401 bufA[0] = 0;
4402 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4403 if (!ret)
4404 {
4405 trace("no localized FULL_NAME found.\n");
4406 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4407 }
4408 ok(ret, "FULL_NAME (face name) could not be read\n");
4409 if (want_vertical) bufW = prepend_at(bufW);
4410 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4411 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4412 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4413 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4414
4415 bufW[0] = 0;
4416 bufA[0] = 0;
4417 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4418 if (!ret)
4419 {
4420 trace("no localized FONT_SUBFAMILY found.\n");
4421 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4422 }
4423 ok(ret, "SUBFAMILY (style name) could not be read\n");
4424 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4425 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4426 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4427 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4428
4429 bufW[0] = 0;
4430 bufA[0] = 0;
4431 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4432 if (!ret)
4433 {
4434 trace("no localized UNIQUE_ID found.\n");
4435 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4436 }
4437 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4438 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4439 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4440 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4441
4442 SelectObject(hdc, of);
4443 DeleteObject(hfont);
4444
4445 HeapFree(GetProcessHeap(), 0, otm);
4446 HeapFree(GetProcessHeap(), 0, bufW);
4447 HeapFree(GetProcessHeap(), 0, bufA);
4448 }
4449 DeleteDC(hdc);
4450 }
4451
4452 static void test_fullname2(void)
4453 {
4454 test_fullname2_helper("Arial");
4455 test_fullname2_helper("DejaVu Sans");
4456 test_fullname2_helper("Lucida Sans");
4457 test_fullname2_helper("Tahoma");
4458 test_fullname2_helper("Webdings");
4459 test_fullname2_helper("Wingdings");
4460 test_fullname2_helper("SimSun");
4461 test_fullname2_helper("NSimSun");
4462 test_fullname2_helper("MingLiu");
4463 test_fullname2_helper("PMingLiu");
4464 test_fullname2_helper("WenQuanYi Micro Hei");
4465 test_fullname2_helper("MS UI Gothic");
4466 test_fullname2_helper("Ume UI Gothic");
4467 test_fullname2_helper("MS Gothic");
4468 test_fullname2_helper("Ume Gothic");
4469 test_fullname2_helper("MS PGothic");
4470 test_fullname2_helper("Ume P Gothic");
4471 test_fullname2_helper("Gulim");
4472 test_fullname2_helper("Batang");
4473 test_fullname2_helper("UnBatang");
4474 test_fullname2_helper("UnDotum");
4475 test_fullname2_helper("@SimSun");
4476 test_fullname2_helper("@NSimSun");
4477 test_fullname2_helper("@MingLiu");
4478 test_fullname2_helper("@PMingLiu");
4479 test_fullname2_helper("@WenQuanYi Micro Hei");
4480 test_fullname2_helper("@MS UI Gothic");
4481 test_fullname2_helper("@Ume UI Gothic");
4482 test_fullname2_helper("@MS Gothic");
4483 test_fullname2_helper("@Ume Gothic");
4484 test_fullname2_helper("@MS PGothic");
4485 test_fullname2_helper("@Ume P Gothic");
4486 test_fullname2_helper("@Gulim");
4487 test_fullname2_helper("@Batang");
4488 test_fullname2_helper("@UnBatang");
4489 test_fullname2_helper("@UnDotum");
4490
4491 }
4492
4493 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4494 {
4495 char tmp_path[MAX_PATH];
4496 HRSRC rsrc;
4497 void *rsrc_data;
4498 DWORD rsrc_size;
4499 HANDLE hfile;
4500 BOOL ret;
4501
4502 SetLastError(0xdeadbeef);
4503 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4504 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4505 if (!rsrc) return FALSE;
4506 SetLastError(0xdeadbeef);
4507 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4508 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4509 if (!rsrc_data) return FALSE;
4510 SetLastError(0xdeadbeef);
4511 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4512 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4513 if (!rsrc_size) return FALSE;
4514
4515 SetLastError(0xdeadbeef);
4516 ret = GetTempPath(MAX_PATH, tmp_path);
4517 ok(ret, "GetTempPath() error %d\n", GetLastError());
4518 SetLastError(0xdeadbeef);
4519 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4520 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4521
4522 SetLastError(0xdeadbeef);
4523 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4524 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4525 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4526
4527 SetLastError(0xdeadbeef);
4528 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4529 ok(ret, "WriteFile() error %d\n", GetLastError());
4530
4531 CloseHandle(hfile);
4532 return ret;
4533 }
4534
4535 static void test_GetGlyphOutline_empty_contour(void)
4536 {
4537 HDC hdc;
4538 LOGFONTA lf;
4539 HFONT hfont, hfont_prev;
4540 TTPOLYGONHEADER *header;
4541 GLYPHMETRICS gm;
4542 char buf[1024];
4543 DWORD ret;
4544
4545 memset(&lf, 0, sizeof(lf));
4546 lf.lfHeight = 72;
4547 lstrcpyA(lf.lfFaceName, "wine_test");
4548
4549 hfont = CreateFontIndirectA(&lf);
4550 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4551
4552 hdc = GetDC(NULL);
4553
4554 hfont_prev = SelectObject(hdc, hfont);
4555 ok(hfont_prev != NULL, "SelectObject failed\n");
4556
4557 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
4558 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4559
4560 header = (TTPOLYGONHEADER*)buf;
4561 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
4562 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4563 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
4564 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
4565 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4566 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4567 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4568 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4569
4570 SelectObject(hdc, hfont_prev);
4571 DeleteObject(hfont);
4572 ReleaseDC(NULL, hdc);
4573 }
4574
4575 static void test_CreateScalableFontResource(void)
4576 {
4577 char ttf_name[MAX_PATH];
4578 char tmp_path[MAX_PATH];
4579 char fot_name[MAX_PATH];
4580 char *file_part;
4581 DWORD ret;
4582 int i;
4583
4584 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4585 {
4586 win_skip("AddFontResourceExA is not available on this platform\n");
4587 return;
4588 }
4589
4590 if (!write_ttf_file("wine_test.ttf", ttf_name))
4591 {
4592 skip("Failed to create ttf file for testing\n");
4593 return;
4594 }
4595
4596 trace("created %s\n", ttf_name);
4597
4598 ret = is_truetype_font_installed("wine_test");
4599 ok(!ret, "font wine_test should not be enumerated\n");
4600
4601 ret = GetTempPath(MAX_PATH, tmp_path);
4602 ok(ret, "GetTempPath() error %d\n", GetLastError());
4603 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4604 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4605
4606 ret = GetFileAttributes(fot_name);
4607 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4608
4609 SetLastError(0xdeadbeef);
4610 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4611 ok(!ret, "CreateScalableFontResource() should fail\n");
4612 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4613
4614 SetLastError(0xdeadbeef);
4615 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4616 ok(!ret, "CreateScalableFontResource() should fail\n");
4617 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4618
4619 file_part = strrchr(ttf_name, '\\');
4620 SetLastError(0xdeadbeef);
4621 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4622 ok(!ret, "CreateScalableFontResource() should fail\n");
4623 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4624
4625 SetLastError(0xdeadbeef);
4626 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4627 ok(!ret, "CreateScalableFontResource() should fail\n");
4628 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4629
4630 SetLastError(0xdeadbeef);
4631 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4632 ok(!ret, "CreateScalableFontResource() should fail\n");
4633 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4634
4635 ret = DeleteFile(fot_name);
4636 ok(ret, "DeleteFile() error %d\n", GetLastError());
4637
4638 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4639 ok(!ret, "RemoveFontResourceEx() should fail\n");
4640
4641 /* test public font resource */
4642 SetLastError(0xdeadbeef);
4643 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4644 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4645
4646 ret = is_truetype_font_installed("wine_test");
4647 ok(!ret, "font wine_test should not be enumerated\n");
4648
4649 SetLastError(0xdeadbeef);
4650 ret = pAddFontResourceExA(fot_name, 0, 0);
4651 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4652
4653 ret = is_truetype_font_installed("wine_test");
4654 ok(ret, "font wine_test should be enumerated\n");
4655
4656 test_GetGlyphOutline_empty_contour();
4657
4658 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4659 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4660
4661 SetLastError(0xdeadbeef);
4662 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4663 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4664
4665 ret = is_truetype_font_installed("wine_test");
4666 ok(!ret, "font wine_test should not be enumerated\n");
4667
4668 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4669 ok(!ret, "RemoveFontResourceEx() should fail\n");
4670
4671 /* test refcounting */
4672 for (i = 0; i < 5; i++)
4673 {
4674 SetLastError(0xdeadbeef);
4675 ret = pAddFontResourceExA(fot_name, 0, 0);
4676 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4677 }
4678 for (i = 0; i < 5; i++)
4679 {
4680 SetLastError(0xdeadbeef);
4681 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4682 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4683 }
4684 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4685 ok(!ret, "RemoveFontResourceEx() should fail\n");
4686
4687 DeleteFile(fot_name);
4688
4689 /* test hidden font resource */
4690 SetLastError(0xdeadbeef);
4691 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4692 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4693
4694 ret = is_truetype_font_installed("wine_test");
4695 ok(!ret, "font wine_test should not be enumerated\n");
4696
4697 SetLastError(0xdeadbeef);
4698 ret = pAddFontResourceExA(fot_name, 0, 0);
4699 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4700
4701 ret = is_truetype_font_installed("wine_test");
4702 todo_wine
4703 ok(!ret, "font wine_test should not be enumerated\n");
4704
4705 /* XP allows removing a private font added with 0 flags */
4706 SetLastError(0xdeadbeef);
4707 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4708 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4709
4710 ret = is_truetype_font_installed("wine_test");
4711 ok(!ret, "font wine_test should not be enumerated\n");
4712
4713 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4714 ok(!ret, "RemoveFontResourceEx() should fail\n");
4715
4716 DeleteFile(fot_name);
4717 DeleteFile(ttf_name);
4718 }
4719
4720 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4721 {
4722 LOGFONTA lf;
4723 HFONT hfont, hfont_prev;
4724 HDC hdc;
4725 char facename[100];
4726 DWORD ret;
4727 static const WCHAR str[] = { 0x2025 };
4728
4729 *installed = is_truetype_font_installed(name);
4730
4731 lf.lfHeight = -18;
4732 lf.lfWidth = 0;
4733 lf.lfEscapement = 0;
4734 lf.lfOrientation = 0;
4735 lf.lfWeight = FW_DONTCARE;
4736 lf.lfItalic = 0;
4737 lf.lfUnderline = 0;
4738 lf.lfStrikeOut = 0;
4739 lf.lfCharSet = DEFAULT_CHARSET;
4740 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4741 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4742 lf.lfQuality = DEFAULT_QUALITY;
4743 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4744 strcpy(lf.lfFaceName, name);
4745
4746 hfont = CreateFontIndirectA(&lf);
4747 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4748
4749 hdc = GetDC(NULL);
4750
4751 hfont_prev = SelectObject(hdc, hfont);
4752 ok(hfont_prev != NULL, "SelectObject failed\n");
4753
4754 ret = GetTextFaceA(hdc, sizeof facename, facename);
4755 ok(ret, "GetTextFaceA failed\n");
4756 *selected = !strcmp(facename, name);
4757
4758 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4759 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4760 if (!*selected)
4761 memset(gm, 0, sizeof *gm);
4762
4763 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4764 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4765
4766 SelectObject(hdc, hfont_prev);
4767 DeleteObject(hfont);
4768 ReleaseDC(NULL, hdc);
4769 }
4770
4771 static void test_vertical_font(void)
4772 {
4773 char ttf_name[MAX_PATH];
4774 int num;
4775 BOOL ret, installed, selected;
4776 GLYPHMETRICS gm;
4777 WORD hgi, vgi;
4778
4779 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4780 {
4781 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4782 return;
4783 }
4784
4785 if (!write_ttf_file("vertical.ttf", ttf_name))
4786 {
4787 skip("Failed to create ttf file for testing\n");
4788 return;
4789 }
4790
4791 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4792 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4793
4794 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4795 ok(installed, "@WineTestVertical is not installed\n");
4796 ok(selected, "@WineTestVertical is not selected\n");
4797 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4798 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4799 gm.gmBlackBoxX, gm.gmBlackBoxY);
4800
4801 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4802 ok(installed, "@@WineTestVertical is not installed\n");
4803 ok(selected, "@@WineTestVertical is not selected\n");
4804 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4805 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4806 gm.gmBlackBoxX, gm.gmBlackBoxY);
4807
4808 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4809
4810 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4811 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4812
4813 DeleteFile(ttf_name);
4814 }
4815
4816 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4817 DWORD type, LPARAM lParam)
4818 {
4819 if (lf->lfFaceName[0] == '@') {
4820 return 0;
4821 }
4822 return 1;
4823 }
4824
4825 static void test_east_asian_font_selection(void)
4826 {
4827 HDC hdc;
4828 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4829 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4830 size_t i;
4831
4832 hdc = GetDC(NULL);
4833
4834 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4835 {
4836 LOGFONTA lf;
4837 HFONT hfont;
4838 char face_name[LF_FACESIZE];
4839 int ret;
4840
4841 memset(&lf, 0, sizeof lf);
4842 lf.lfFaceName[0] = '\0';
4843 lf.lfCharSet = charset[i];
4844
4845 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4846 {
4847 skip("Vertical font for charset %u is not installed\n", charset[i]);
4848 continue;
4849 }
4850
4851 hfont = CreateFontIndirectA(&lf);
4852 hfont = SelectObject(hdc, hfont);
4853 memset(face_name, 0, sizeof face_name);
4854 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4855 ok(ret && face_name[0] != '@',
4856 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4857 DeleteObject(SelectObject(hdc, hfont));
4858
4859 memset(&lf, 0, sizeof lf);
4860 strcpy(lf.lfFaceName, "@");
4861 lf.lfCharSet = charset[i];
4862 hfont = CreateFontIndirectA(&lf);
4863 hfont = SelectObject(hdc, hfont);
4864 memset(face_name, 0, sizeof face_name);
4865 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4866 ok(ret && face_name[0] == '@',
4867 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4868 DeleteObject(SelectObject(hdc, hfont));
4869 }
4870 ReleaseDC(NULL, hdc);
4871 }
4872
4873 static int get_font_dpi(const LOGFONT *lf)
4874 {
4875 HDC hdc = CreateCompatibleDC(0);
4876 HFONT hfont;
4877 TEXTMETRIC tm;
4878 int ret;
4879
4880 hfont = CreateFontIndirect(lf);
4881 ok(hfont != 0, "CreateFontIndirect failed\n");
4882
4883 SelectObject(hdc, hfont);
4884 ret = GetTextMetrics(hdc, &tm);
4885 ok(ret, "GetTextMetrics failed\n");
4886 ret = tm.tmDigitizedAspectX;
4887
4888 DeleteDC(hdc);
4889 DeleteObject(hfont);
4890
4891 return ret;
4892 }
4893
4894 static void test_stock_fonts(void)
4895 {
4896 static const int font[] =
4897 {
4898 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4899 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4900 };
4901 static const struct test_data
4902 {
4903 int charset, weight, height, dpi;
4904 const char face_name[LF_FACESIZE];
4905 } td[][11] =
4906 {
4907 { /* ANSI_FIXED_FONT */
4908 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4909 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4910 { 0 }
4911 },
4912 { /* ANSI_VAR_FONT */
4913 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4914 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4915 { 0 }
4916 },
4917 { /* SYSTEM_FONT */
4918 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4919 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4920 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4921 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4922 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4923 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4924 { 0 }
4925 },
4926 { /* DEVICE_DEFAULT_FONT */
4927 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4928 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4929 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4930 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4931 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4932 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4933 { 0 }
4934 },
4935 { /* DEFAULT_GUI_FONT */
4936 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4937 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4938 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4939 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4940 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4941 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4942 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4943 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4944 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4945 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4946 { 0 }
4947 }
4948 };
4949 int i, j;
4950
4951 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4952 {
4953 HFONT hfont;
4954 LOGFONT lf;
4955 int ret;
4956
4957 hfont = GetStockObject(font[i]);
4958 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4959
4960 ret = GetObject(hfont, sizeof(lf), &lf);
4961 if (ret != sizeof(lf))
4962 {
4963 /* NT4 */
4964 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4965 continue;
4966 }
4967
4968 for (j = 0; td[i][j].face_name[0] != 0; j++)
4969 {
4970 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4971 {
4972 continue;
4973 }
4974
4975 ret = get_font_dpi(&lf);
4976 if (ret != td[i][j].dpi)
4977 {
4978 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4979 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4980 continue;
4981 }
4982
4983 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4984 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4985 if (td[i][j].face_name[0] == '?')
4986 {
4987 /* Wine doesn't have this font, skip this case for now.
4988 Actually, the face name is localized on Windows and varies
4989 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4990 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4991 }
4992 else
4993 {
4994 ok(!lstrcmp(td[i][j].face_name, lf.lfFaceName), "%d(%d): expected lfFaceName %s, got %s\n", i, j, td[i][j].face_name, lf.lfFaceName);
4995 }
4996 break;
4997 }
4998 }
4999 }
5000
5001 START_TEST(font)
5002 {
5003 init();
5004
5005 test_stock_fonts();
5006 test_logfont();
5007 test_bitmap_font();
5008 test_outline_font();
5009 test_bitmap_font_metrics();
5010 test_GdiGetCharDimensions();
5011 test_GetCharABCWidths();
5012 test_text_extents();
5013 test_GetGlyphIndices();
5014 test_GetKerningPairs();
5015 test_GetOutlineTextMetrics();
5016 test_SetTextJustification();
5017 test_font_charset();
5018 test_GdiGetCodePage();
5019 test_GetFontUnicodeRanges();
5020 test_nonexistent_font();
5021 test_orientation();
5022 test_height_selection();
5023 test_AddFontMemResource();
5024 test_EnumFonts();
5025
5026 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
5027 * I'd like to avoid them in this test.
5028 */
5029 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
5030 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
5031 if (is_truetype_font_installed("Arial Black") &&
5032 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
5033 {
5034 test_EnumFontFamilies("", ANSI_CHARSET);
5035 test_EnumFontFamilies("", SYMBOL_CHARSET);
5036 test_EnumFontFamilies("", DEFAULT_CHARSET);
5037 }
5038 else
5039 skip("Arial Black or Symbol/Wingdings is not installed\n");
5040 test_EnumFontFamiliesEx_default_charset();
5041 test_GetTextMetrics();
5042 test_GdiRealizationInfo();
5043 test_GetTextFace();
5044 test_GetGlyphOutline();
5045 test_GetTextMetrics2("Tahoma", -11);
5046 test_GetTextMetrics2("Tahoma", -55);
5047 test_GetTextMetrics2("Tahoma", -110);
5048 test_GetTextMetrics2("Arial", -11);
5049 test_GetTextMetrics2("Arial", -55);
5050 test_GetTextMetrics2("Arial", -110);
5051 test_CreateFontIndirect();
5052 test_CreateFontIndirectEx();
5053 test_oemcharset();
5054 test_fullname();
5055 test_fullname2();
5056 test_east_asian_font_selection();
5057
5058 /* These tests should be last test until RemoveFontResource
5059 * is properly implemented.
5060 */
5061 test_vertical_font();
5062 test_CreateScalableFontResource();
5063 }