gdi32: Add helper functions for GetTextExtentExPoint and fix handling of text justifi...
[wine.git] / dlls / gdi32 / tests / font.c
blob337a6b965a17726c30897f9f694846d0d1019032
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
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.
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.
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
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
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)
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);
57 static HMODULE hgdi32 = 0;
58 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
59 static WORD system_lang_id;
61 static void init(void)
63 hgdi32 = GetModuleHandleA("gdi32.dll");
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");
82 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
85 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
87 if (type != TRUETYPE_FONTTYPE) return 1;
89 return 0;
92 static BOOL is_truetype_font_installed(const char *name)
94 HDC hdc = GetDC(0);
95 BOOL ret = FALSE;
97 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
98 ret = TRUE;
100 ReleaseDC(0, hdc);
101 return ret;
104 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
106 return 0;
109 static BOOL is_font_installed(const char *name)
111 HDC hdc = GetDC(0);
112 BOOL ret = FALSE;
114 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
115 ret = TRUE;
117 ReleaseDC(0, hdc);
118 return ret;
121 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
123 LOGFONTA getobj_lf;
124 int ret, minlen = 0;
126 if (!hfont)
127 return;
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);
163 static HFONT create_font(const char* test, const LOGFONTA* lf)
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;
172 static void test_logfont(void)
174 LOGFONTA lf;
175 HFONT hfont;
177 memset(&lf, 0, sizeof lf);
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;
186 lstrcpyA(lf.lfFaceName, "Arial");
187 hfont = create_font("Arial", &lf);
188 DeleteObject(hfont);
190 memset(&lf, 'A', sizeof(lf));
191 hfont = CreateFontIndirectA(&lf);
192 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
194 lf.lfFaceName[LF_FACESIZE - 1] = 0;
195 check_font("AAA...", &lf, hfont);
196 DeleteObject(hfont);
199 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
201 if (type & RASTER_FONTTYPE)
203 LOGFONT *lf = (LOGFONT *)lParam;
204 *lf = *elf;
205 return 0; /* stop enumeration */
208 return 1; /* continue enumeration */
211 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
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);
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)
241 LOGFONTA lf;
242 OUTLINETEXTMETRIC otm;
243 TEXTMETRICA tm;
244 SIZE size;
245 INT width_of_A, cx, cy;
246 UINT ret;
248 if (!hfont)
249 return;
251 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
253 GetObjectA(hfont, sizeof(lf), &lf);
255 if (GetOutlineTextMetricsA(hdc, 0, NULL))
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);
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);
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))
274 ok(0, "tm != otm\n");
275 compare_tm(&tm, &otm.otmTextMetrics);
278 tm = otm.otmTextMetrics;
279 if (0) /* these metrics are scaled too, but with rounding errors */
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);
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);
291 else
293 ret = GetTextMetricsA(hdc, &tm);
294 ok(ret, "GetTextMetricsA failed\n");
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);
307 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
308 if (lf.lfHeight)
310 if (lf.lfWidth)
311 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
313 else
314 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
316 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
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);
321 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
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);
326 /* Test how GDI scales bitmap font metrics */
327 static void test_bitmap_font(void)
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;
337 hdc = CreateCompatibleDC(0);
339 /* "System" has only 1 pixel size defined, otherwise the test breaks */
340 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
341 if (ret)
343 ReleaseDC(0, hdc);
344 trace("no bitmap fonts were found, skipping the test\n");
345 return;
348 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
350 height_orig = bitmap_lf.lfHeight;
351 lfWidth = bitmap_lf.lfWidth;
353 hfont = create_font("bitmap", &bitmap_lf);
354 old_hfont = SelectObject(hdc, hfont);
355 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
356 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
357 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
358 SelectObject(hdc, old_hfont);
359 DeleteObject(hfont);
361 bitmap_lf.lfHeight = 0;
362 bitmap_lf.lfWidth = 4;
363 hfont = create_font("bitmap", &bitmap_lf);
364 old_hfont = SelectObject(hdc, hfont);
365 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
366 SelectObject(hdc, old_hfont);
367 DeleteObject(hfont);
369 bitmap_lf.lfHeight = height_orig;
370 bitmap_lf.lfWidth = lfWidth;
372 /* test fractional scaling */
373 for (i = 1; i <= height_orig * 6; i++)
375 INT nearest_height;
377 bitmap_lf.lfHeight = i;
378 hfont = create_font("fractional", &bitmap_lf);
379 scale = (i + height_orig - 1) / height_orig;
380 nearest_height = scale * height_orig;
381 /* Only jump to the next height if the difference <= 25% original height */
382 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
383 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
384 so we'll not test this particular height. */
385 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
386 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
387 old_hfont = SelectObject(hdc, hfont);
388 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
389 SelectObject(hdc, old_hfont);
390 DeleteObject(hfont);
393 /* test integer scaling 3x2 */
394 bitmap_lf.lfHeight = height_orig * 2;
395 bitmap_lf.lfWidth *= 3;
396 hfont = create_font("3x2", &bitmap_lf);
397 old_hfont = SelectObject(hdc, hfont);
398 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
399 SelectObject(hdc, old_hfont);
400 DeleteObject(hfont);
402 /* test integer scaling 3x3 */
403 bitmap_lf.lfHeight = height_orig * 3;
404 bitmap_lf.lfWidth = 0;
405 hfont = create_font("3x3", &bitmap_lf);
406 old_hfont = SelectObject(hdc, hfont);
407 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
408 SelectObject(hdc, old_hfont);
409 DeleteObject(hfont);
411 DeleteDC(hdc);
414 /* Test how GDI scales outline font metrics */
415 static void test_outline_font(void)
417 static const char test_str[11] = "Test String";
418 HDC hdc, hdc_2;
419 LOGFONTA lf;
420 HFONT hfont, old_hfont, old_hfont_2;
421 OUTLINETEXTMETRICA otm;
422 SIZE size_orig;
423 INT width_orig, height_orig, lfWidth;
424 XFORM xform;
425 GLYPHMETRICS gm;
426 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
427 POINT pt;
428 INT ret;
430 if (!is_truetype_font_installed("Arial"))
432 skip("Arial is not installed\n");
433 return;
436 hdc = CreateCompatibleDC(0);
438 memset(&lf, 0, sizeof(lf));
439 strcpy(lf.lfFaceName, "Arial");
440 lf.lfHeight = 72;
441 hfont = create_font("outline", &lf);
442 old_hfont = SelectObject(hdc, hfont);
443 otm.otmSize = sizeof(otm);
444 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
445 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
446 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
448 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
449 SelectObject(hdc, old_hfont);
450 DeleteObject(hfont);
452 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
453 lf.lfHeight = otm.otmEMSquare;
454 lf.lfHeight = -lf.lfHeight;
455 hfont = create_font("outline", &lf);
456 old_hfont = SelectObject(hdc, hfont);
457 otm.otmSize = sizeof(otm);
458 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
459 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
460 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
461 SelectObject(hdc, old_hfont);
462 DeleteObject(hfont);
464 height_orig = otm.otmTextMetrics.tmHeight;
465 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
467 /* test integer scaling 3x2 */
468 lf.lfHeight = height_orig * 2;
469 lf.lfWidth = lfWidth * 3;
470 hfont = create_font("3x2", &lf);
471 old_hfont = SelectObject(hdc, hfont);
472 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
473 SelectObject(hdc, old_hfont);
474 DeleteObject(hfont);
476 /* test integer scaling 3x3 */
477 lf.lfHeight = height_orig * 3;
478 lf.lfWidth = lfWidth * 3;
479 hfont = create_font("3x3", &lf);
480 old_hfont = SelectObject(hdc, hfont);
481 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
482 SelectObject(hdc, old_hfont);
483 DeleteObject(hfont);
485 /* test integer scaling 1x1 */
486 lf.lfHeight = height_orig * 1;
487 lf.lfWidth = lfWidth * 1;
488 hfont = create_font("1x1", &lf);
489 old_hfont = SelectObject(hdc, hfont);
490 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
491 SelectObject(hdc, old_hfont);
492 DeleteObject(hfont);
494 /* test integer scaling 1x1 */
495 lf.lfHeight = height_orig;
496 lf.lfWidth = 0;
497 hfont = create_font("1x1", &lf);
498 old_hfont = SelectObject(hdc, hfont);
499 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
501 /* with an identity matrix */
502 memset(&gm, 0, sizeof(gm));
503 SetLastError(0xdeadbeef);
504 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
505 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
506 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
507 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
508 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
509 /* with a custom matrix */
510 memset(&gm, 0, sizeof(gm));
511 SetLastError(0xdeadbeef);
512 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
513 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
514 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
515 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
516 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
518 /* Test that changing the DC transformation affects only the font
519 * selected on this DC and doesn't affect the same font selected on
520 * another DC.
522 hdc_2 = CreateCompatibleDC(0);
523 old_hfont_2 = SelectObject(hdc_2, hfont);
524 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
526 SetMapMode(hdc, MM_ANISOTROPIC);
528 /* font metrics on another DC should be unchanged */
529 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
531 /* test restrictions of compatibility mode GM_COMPATIBLE */
532 /* part 1: rescaling only X should not change font scaling on screen.
533 So compressing the X axis by 2 is not done, and this
534 appears as X scaling of 2 that no one requested. */
535 SetWindowExtEx(hdc, 100, 100, NULL);
536 SetViewportExtEx(hdc, 50, 100, NULL);
537 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
538 /* font metrics on another DC should be unchanged */
539 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
541 /* part 2: rescaling only Y should change font scaling.
542 As also X is scaled by a factor of 2, but this is not
543 requested by the DC transformation, we get a scaling factor
544 of 2 in the X coordinate. */
545 SetViewportExtEx(hdc, 100, 200, NULL);
546 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
550 /* restore scaling */
551 SetMapMode(hdc, MM_TEXT);
553 /* font metrics on another DC should be unchanged */
554 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 SelectObject(hdc_2, old_hfont_2);
557 DeleteDC(hdc_2);
559 if (!SetGraphicsMode(hdc, GM_ADVANCED))
561 SelectObject(hdc, old_hfont);
562 DeleteObject(hfont);
563 DeleteDC(hdc);
564 skip("GM_ADVANCED is not supported on this platform\n");
565 return;
568 xform.eM11 = 20.0f;
569 xform.eM12 = 0.0f;
570 xform.eM21 = 0.0f;
571 xform.eM22 = 20.0f;
572 xform.eDx = 0.0f;
573 xform.eDy = 0.0f;
575 SetLastError(0xdeadbeef);
576 ret = SetWorldTransform(hdc, &xform);
577 ok(ret, "SetWorldTransform error %u\n", GetLastError());
579 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
581 /* with an identity matrix */
582 memset(&gm, 0, sizeof(gm));
583 SetLastError(0xdeadbeef);
584 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
585 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
586 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
587 pt.x = width_orig; pt.y = 0;
588 LPtoDP(hdc, &pt, 1);
589 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
590 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
591 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
592 /* with a custom matrix */
593 memset(&gm, 0, sizeof(gm));
594 SetLastError(0xdeadbeef);
595 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
596 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
597 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
598 pt.x = width_orig; pt.y = 0;
599 LPtoDP(hdc, &pt, 1);
600 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
601 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
602 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
604 SetLastError(0xdeadbeef);
605 ret = SetMapMode(hdc, MM_LOMETRIC);
606 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
608 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
610 /* with an identity matrix */
611 memset(&gm, 0, sizeof(gm));
612 SetLastError(0xdeadbeef);
613 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
614 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
615 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
616 pt.x = width_orig; pt.y = 0;
617 LPtoDP(hdc, &pt, 1);
618 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
619 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
620 /* with a custom matrix */
621 memset(&gm, 0, sizeof(gm));
622 SetLastError(0xdeadbeef);
623 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
624 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
625 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
626 pt.x = width_orig; pt.y = 0;
627 LPtoDP(hdc, &pt, 1);
628 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
629 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
631 SetLastError(0xdeadbeef);
632 ret = SetMapMode(hdc, MM_TEXT);
633 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
635 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
637 /* with an identity matrix */
638 memset(&gm, 0, sizeof(gm));
639 SetLastError(0xdeadbeef);
640 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
641 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
642 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
643 pt.x = width_orig; pt.y = 0;
644 LPtoDP(hdc, &pt, 1);
645 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
646 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
647 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
648 /* with a custom matrix */
649 memset(&gm, 0, sizeof(gm));
650 SetLastError(0xdeadbeef);
651 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
652 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
653 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
654 pt.x = width_orig; pt.y = 0;
655 LPtoDP(hdc, &pt, 1);
656 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
657 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
658 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
660 SelectObject(hdc, old_hfont);
661 DeleteObject(hfont);
662 DeleteDC(hdc);
665 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
667 LOGFONT *lf = (LOGFONT *)lParam;
669 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
671 *lf = *elf;
672 return 0; /* stop enumeration */
674 return 1; /* continue enumeration */
677 static BOOL is_CJK(void)
679 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
682 #define FH_SCALE 0x80000000
683 static void test_bitmap_font_metrics(void)
685 static const struct font_data
687 const char face_name[LF_FACESIZE];
688 int weight, height, ascent, descent, int_leading, ext_leading;
689 int ave_char_width, max_char_width, dpi;
690 BYTE first_char, last_char, def_char, break_char;
691 DWORD ansi_bitfield;
692 WORD skip_lang_id;
693 int scaled_height;
694 } fd[] =
696 { "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 },
697 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
698 { "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 },
699 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
700 { "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 },
701 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
702 { "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 },
703 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
704 { "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 },
705 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
707 { "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 },
708 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
709 { "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 },
710 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
711 { "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 },
712 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
713 { "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 },
714 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
715 { "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 },
716 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
718 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
719 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
720 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
721 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
722 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
723 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
724 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
725 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
726 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
727 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
728 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
729 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
730 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
731 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
732 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
733 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
735 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
736 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
737 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
739 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
740 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
741 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
742 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
743 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
744 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
745 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
746 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
748 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
749 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
750 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
751 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
752 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
753 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
754 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
755 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
756 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
757 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
758 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
759 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
760 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
761 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
762 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
763 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
764 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
766 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
767 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
768 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
769 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
770 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
771 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
772 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
773 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
774 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
775 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
776 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
778 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
779 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
780 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
782 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
783 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
784 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
786 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
787 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
788 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
790 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
791 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
793 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
794 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
795 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
796 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
797 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
798 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
799 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
800 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
801 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
802 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
803 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
804 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
805 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
806 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
807 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
808 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
809 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
810 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
811 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
812 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
813 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
815 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
816 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
817 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
818 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
819 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
820 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
821 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
822 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
823 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
824 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
826 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
828 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
830 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
832 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
834 /* FIXME: add "Terminal" */
836 static const int font_log_pixels[] = { 96, 120 };
837 HDC hdc;
838 LOGFONT lf;
839 HFONT hfont, old_hfont;
840 TEXTMETRIC tm;
841 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
842 char face_name[LF_FACESIZE];
843 CHARSETINFO csi;
845 trace("system language id %04x\n", system_lang_id);
847 expected_cs = GetACP();
848 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
850 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
851 return;
853 expected_cs = csi.ciCharset;
854 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
856 hdc = CreateCompatibleDC(0);
857 assert(hdc);
859 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
860 GetDeviceCaps(hdc, LOGPIXELSY));
862 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
863 diff = 32768;
864 font_res = 0;
865 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
867 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
868 if (new_diff < diff)
870 diff = new_diff;
871 font_res = font_log_pixels[i];
874 trace("best font resolution is %d\n", font_res);
876 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
878 int bit, height;
880 memset(&lf, 0, sizeof(lf));
882 height = fd[i].height & ~FH_SCALE;
883 lf.lfHeight = height;
884 strcpy(lf.lfFaceName, fd[i].face_name);
886 for(bit = 0; bit < 32; bit++)
888 GLYPHMETRICS gm;
889 DWORD fs[2];
890 BOOL bRet;
892 fs[0] = 1L << bit;
893 fs[1] = 0;
894 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
895 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
897 lf.lfCharSet = csi.ciCharset;
898 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
899 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
900 if (fd[i].height & FH_SCALE)
901 ok(ret, "scaled font height %d should not be enumerated\n", height);
902 else
904 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
906 if (ret) /* FIXME: Remove once Wine is fixed */
907 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
908 else
909 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
912 if (ret && !(fd[i].height & FH_SCALE))
913 continue;
915 hfont = create_font(lf.lfFaceName, &lf);
916 old_hfont = SelectObject(hdc, hfont);
918 SetLastError(0xdeadbeef);
919 ret = GetTextFace(hdc, sizeof(face_name), face_name);
920 ok(ret, "GetTextFace error %u\n", GetLastError());
922 if (lstrcmp(face_name, fd[i].face_name) != 0)
924 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
925 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
926 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
927 SelectObject(hdc, old_hfont);
928 DeleteObject(hfont);
929 continue;
932 memset(&gm, 0, sizeof(gm));
933 SetLastError(0xdeadbeef);
934 ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
935 todo_wine {
936 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
937 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
940 bRet = GetTextMetrics(hdc, &tm);
941 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
943 SetLastError(0xdeadbeef);
944 ret = GetTextCharset(hdc);
945 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
946 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
947 else
948 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
950 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
951 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
953 if(fd[i].dpi == tm.tmDigitizedAspectX)
955 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
956 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
958 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
959 if (fd[i].height & FH_SCALE)
960 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);
961 else
962 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);
963 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
964 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
965 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);
966 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);
967 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);
968 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
969 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
970 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
971 make default char test fail */
972 if (tm.tmCharSet == lf.lfCharSet)
973 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
974 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
975 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);
977 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
978 that make the max width bigger */
979 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
980 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);
982 else
983 skip("Skipping font metrics test for system langid 0x%x\n",
984 system_lang_id);
986 SelectObject(hdc, old_hfont);
987 DeleteObject(hfont);
991 DeleteDC(hdc);
994 static void test_GdiGetCharDimensions(void)
996 HDC hdc;
997 TEXTMETRICW tm;
998 LONG ret;
999 SIZE size;
1000 LONG avgwidth, height;
1001 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1003 if (!pGdiGetCharDimensions)
1005 win_skip("GdiGetCharDimensions not available on this platform\n");
1006 return;
1009 hdc = CreateCompatibleDC(NULL);
1011 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1012 avgwidth = ((size.cx / 26) + 1) / 2;
1014 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1015 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1016 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1018 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1019 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1021 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1022 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1024 height = 0;
1025 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1026 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1027 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1029 DeleteDC(hdc);
1032 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1033 const TEXTMETRIC *lpntme,
1034 DWORD FontType, LPARAM lParam)
1036 if (FontType & TRUETYPE_FONTTYPE)
1038 HFONT hfont;
1040 hfont = CreateFontIndirect(lpelfe);
1041 if (hfont)
1043 *(HFONT *)lParam = hfont;
1044 return 0;
1048 return 1;
1051 static void test_GetCharABCWidths(void)
1053 static const WCHAR str[] = {'a',0};
1054 BOOL ret;
1055 HDC hdc;
1056 LOGFONTA lf;
1057 HFONT hfont;
1058 ABC abc[1];
1059 ABCFLOAT abcf[1];
1060 WORD glyphs[1];
1061 DWORD nb;
1062 static const struct
1064 UINT first;
1065 UINT last;
1066 } range[] =
1068 {0xff, 0xff},
1069 {0x100, 0x100},
1070 {0xff, 0x100},
1071 {0x1ff, 0xff00},
1072 {0xffff, 0xffff},
1073 {0x10000, 0x10000},
1074 {0xffff, 0x10000},
1075 {0xffffff, 0xffffff},
1076 {0x1000000, 0x1000000},
1077 {0xffffff, 0x1000000},
1078 {0xffffffff, 0xffffffff},
1079 {0x00, 0xff}
1081 static const struct
1083 UINT cs;
1084 UINT a;
1085 UINT w;
1086 BOOL r[sizeof range / sizeof range[0]];
1087 } c[] =
1089 {ANSI_CHARSET, 0x30, 0x30,
1090 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1091 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1092 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1093 {HANGEUL_CHARSET, 0x8141, 0xac02,
1094 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1095 {JOHAB_CHARSET, 0x8446, 0x3135,
1096 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1097 {GB2312_CHARSET, 0x8141, 0x4e04,
1098 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1099 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1100 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1102 UINT i;
1104 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1106 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1107 return;
1110 memset(&lf, 0, sizeof(lf));
1111 strcpy(lf.lfFaceName, "System");
1112 lf.lfHeight = 20;
1114 hfont = CreateFontIndirectA(&lf);
1115 hdc = GetDC(0);
1116 hfont = SelectObject(hdc, hfont);
1118 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1119 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1121 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1122 ok(!ret, "GetCharABCWidthsI should have failed\n");
1124 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1125 ok(!ret, "GetCharABCWidthsI should have failed\n");
1127 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1128 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1130 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1131 ok(!ret, "GetCharABCWidthsW should have failed\n");
1133 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1134 ok(!ret, "GetCharABCWidthsW should have failed\n");
1136 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1137 ok(!ret, "GetCharABCWidthsW should have failed\n");
1139 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1140 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1142 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1143 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1145 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1146 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1148 hfont = SelectObject(hdc, hfont);
1149 DeleteObject(hfont);
1151 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1153 ABC a[2], w[2];
1154 ABC full[256];
1155 UINT code = 0x41, j;
1157 lf.lfFaceName[0] = '\0';
1158 lf.lfCharSet = c[i].cs;
1159 lf.lfPitchAndFamily = 0;
1160 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1162 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1163 continue;
1166 memset(a, 0, sizeof a);
1167 memset(w, 0, sizeof w);
1168 hfont = SelectObject(hdc, hfont);
1169 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1170 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1171 memcmp(a, w, sizeof a) == 0,
1172 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1174 memset(a, 0xbb, sizeof a);
1175 ret = pGetCharABCWidthsA(hdc, code, code, a);
1176 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1177 memset(full, 0xcc, sizeof full);
1178 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1179 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1180 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1181 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1183 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1185 memset(full, 0xdd, sizeof full);
1186 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1187 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1188 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1189 if (ret)
1191 UINT last = range[j].last - range[j].first;
1192 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1193 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1194 "GetCharABCWidthsA %x should match. codepage = %u\n",
1195 range[j].last, c[i].cs);
1199 hfont = SelectObject(hdc, hfont);
1200 DeleteObject(hfont);
1203 ReleaseDC(NULL, hdc);
1206 static void test_text_extents(void)
1208 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1209 LPINT extents;
1210 INT i, len, fit1, fit2;
1211 LOGFONTA lf;
1212 TEXTMETRICA tm;
1213 HDC hdc;
1214 HFONT hfont;
1215 SIZE sz;
1216 SIZE sz1, sz2;
1217 BOOL ret;
1219 memset(&lf, 0, sizeof(lf));
1220 strcpy(lf.lfFaceName, "Arial");
1221 lf.lfHeight = 20;
1223 hfont = CreateFontIndirectA(&lf);
1224 hdc = GetDC(0);
1225 hfont = SelectObject(hdc, hfont);
1226 GetTextMetricsA(hdc, &tm);
1227 GetTextExtentPointA(hdc, "o", 1, &sz);
1228 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1230 SetLastError(0xdeadbeef);
1231 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1232 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1234 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1235 hfont = SelectObject(hdc, hfont);
1236 DeleteObject(hfont);
1237 ReleaseDC(0, hdc);
1238 return;
1241 len = lstrlenW(wt);
1242 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1243 extents[0] = 1; /* So that the increasing sequence test will fail
1244 if the extents array is untouched. */
1245 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1246 GetTextExtentPointW(hdc, wt, len, &sz2);
1247 ok(sz1.cy == sz2.cy,
1248 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1249 /* Because of the '\n' in the string GetTextExtentExPoint and
1250 GetTextExtentPoint return different widths under Win2k, but
1251 under WinXP they return the same width. So we don't test that
1252 here. */
1254 for (i = 1; i < len; ++i)
1255 ok(extents[i-1] <= extents[i],
1256 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1258 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1259 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1260 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1261 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1262 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1263 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1264 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1265 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1266 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1267 ok(extents[0] == extents[2] && extents[1] == extents[3],
1268 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1269 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1270 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1271 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1272 HeapFree(GetProcessHeap(), 0, extents);
1274 /* extents functions fail with -ve counts (the interesting case being -1) */
1275 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1276 ok(ret == FALSE, "got %d\n", ret);
1277 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1278 ok(ret == FALSE, "got %d\n", ret);
1279 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1280 ok(ret == FALSE, "got %d\n", ret);
1282 /* max_extent = 0 succeeds and returns zero */
1283 fit1 = fit2 = -215;
1284 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1285 ok(ret == TRUE ||
1286 broken(ret == FALSE), /* NT4, 2k */
1287 "got %d\n", ret);
1288 ok(fit1 == 0 ||
1289 broken(fit1 == -215), /* NT4, 2k */
1290 "fit = %d\n", fit1);
1291 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1292 ok(ret == TRUE, "got %d\n", ret);
1293 ok(fit2 == 0, "fit = %d\n", fit2);
1295 /* max_extent = -1 is interpreted as a very large width that will
1296 * definitely fit our three characters */
1297 fit1 = fit2 = -215;
1298 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1299 ok(ret == TRUE, "got %d\n", ret);
1300 ok(fit1 == 3, "fit = %d\n", fit1);
1301 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1302 ok(ret == TRUE, "got %d\n", ret);
1303 ok(fit2 == 3, "fit = %d\n", fit2);
1305 /* max_extent = -2 is interpreted similarly, but the Ansi version
1306 * rejects it while the Unicode one accepts it */
1307 fit1 = fit2 = -215;
1308 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1309 ok(ret == FALSE, "got %d\n", ret);
1310 ok(fit1 == -215, "fit = %d\n", fit1);
1311 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1312 ok(ret == TRUE, "got %d\n", ret);
1313 ok(fit2 == 3, "fit = %d\n", fit2);
1315 hfont = SelectObject(hdc, hfont);
1316 DeleteObject(hfont);
1317 ReleaseDC(NULL, hdc);
1320 static void test_GetGlyphIndices(void)
1322 HDC hdc;
1323 HFONT hfont;
1324 DWORD charcount;
1325 LOGFONTA lf;
1326 DWORD flags = 0;
1327 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1328 WORD glyphs[(sizeof(testtext)/2)-1];
1329 TEXTMETRIC textm;
1330 HFONT hOldFont;
1332 if (!pGetGlyphIndicesW) {
1333 win_skip("GetGlyphIndicesW not available on platform\n");
1334 return;
1337 hdc = GetDC(0);
1339 memset(&lf, 0, sizeof(lf));
1340 strcpy(lf.lfFaceName, "System");
1341 lf.lfHeight = 16;
1342 lf.lfCharSet = ANSI_CHARSET;
1344 hfont = CreateFontIndirectA(&lf);
1345 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1346 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1347 if (textm.tmCharSet == ANSI_CHARSET)
1349 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1350 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1351 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1352 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1353 flags = 0;
1354 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1355 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1356 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1357 textm.tmDefaultChar, glyphs[4]);
1359 else
1360 /* FIXME: Write tests for non-ANSI charsets. */
1361 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1363 if(!is_font_installed("Tahoma"))
1365 skip("Tahoma is not installed so skipping this test\n");
1366 return;
1368 memset(&lf, 0, sizeof(lf));
1369 strcpy(lf.lfFaceName, "Tahoma");
1370 lf.lfHeight = 20;
1372 hfont = CreateFontIndirectA(&lf);
1373 hOldFont = SelectObject(hdc, hfont);
1374 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1375 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1376 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1377 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1378 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1379 flags = 0;
1380 testtext[0] = textm.tmDefaultChar;
1381 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1382 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1383 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1384 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1385 DeleteObject(SelectObject(hdc, hOldFont));
1388 static void test_GetKerningPairs(void)
1390 static const struct kerning_data
1392 const char face_name[LF_FACESIZE];
1393 LONG height;
1394 /* some interesting fields from OUTLINETEXTMETRIC */
1395 LONG tmHeight, tmAscent, tmDescent;
1396 UINT otmEMSquare;
1397 INT otmAscent;
1398 INT otmDescent;
1399 UINT otmLineGap;
1400 UINT otmsCapEmHeight;
1401 UINT otmsXHeight;
1402 INT otmMacAscent;
1403 INT otmMacDescent;
1404 UINT otmMacLineGap;
1405 UINT otmusMinimumPPEM;
1406 /* small subset of kerning pairs to test */
1407 DWORD total_kern_pairs;
1408 const KERNINGPAIR kern_pair[26];
1409 } kd[] =
1411 {"Arial", 12, 12, 9, 3,
1412 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1415 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1416 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1417 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1418 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1419 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1420 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1421 {933,970,+1},{933,972,-1}
1424 {"Arial", -34, 39, 32, 7,
1425 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1428 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1429 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1430 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1431 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1432 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1433 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1434 {933,970,+2},{933,972,-3}
1437 { "Arial", 120, 120, 97, 23,
1438 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1441 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1442 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1443 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1444 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1445 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1446 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1447 {933,970,+6},{933,972,-10}
1450 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1451 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1452 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1455 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1456 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1457 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1458 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1459 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1460 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1461 {933,970,+54},{933,972,-83}
1464 #endif
1466 LOGFONT lf;
1467 HFONT hfont, hfont_old;
1468 KERNINGPAIR *kern_pair;
1469 HDC hdc;
1470 DWORD total_kern_pairs, ret, i, n, matches;
1472 hdc = GetDC(0);
1474 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1475 * which may render this test unusable, so we're trying to avoid that.
1477 SetLastError(0xdeadbeef);
1478 GetKerningPairsW(hdc, 0, NULL);
1479 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1481 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1482 ReleaseDC(0, hdc);
1483 return;
1486 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1488 OUTLINETEXTMETRICW otm;
1489 UINT uiRet;
1491 if (!is_font_installed(kd[i].face_name))
1493 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1494 continue;
1497 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1499 memset(&lf, 0, sizeof(lf));
1500 strcpy(lf.lfFaceName, kd[i].face_name);
1501 lf.lfHeight = kd[i].height;
1502 hfont = CreateFontIndirect(&lf);
1503 assert(hfont != 0);
1505 hfont_old = SelectObject(hdc, hfont);
1507 SetLastError(0xdeadbeef);
1508 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1509 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1510 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1512 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1513 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1514 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1515 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1516 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1517 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1519 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1520 kd[i].otmEMSquare, otm.otmEMSquare);
1521 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1522 kd[i].otmAscent, otm.otmAscent);
1523 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1524 kd[i].otmDescent, otm.otmDescent);
1525 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1526 kd[i].otmLineGap, otm.otmLineGap);
1527 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1528 kd[i].otmMacDescent, otm.otmMacDescent);
1529 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1530 kd[i].otmMacAscent, otm.otmMacAscent);
1531 todo_wine {
1532 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1533 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1534 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1535 kd[i].otmsXHeight, otm.otmsXHeight);
1536 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1537 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1538 kd[i].otmMacLineGap, otm.otmMacLineGap);
1539 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1540 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1543 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1544 trace("total_kern_pairs %u\n", total_kern_pairs);
1545 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1547 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1548 * passes on XP.
1550 SetLastError(0xdeadbeef);
1551 ret = GetKerningPairsW(hdc, 0, kern_pair);
1552 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1553 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1554 ok(ret == 0, "got %u, expected 0\n", ret);
1556 ret = GetKerningPairsW(hdc, 100, NULL);
1557 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1559 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1560 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1562 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1563 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1565 matches = 0;
1567 for (n = 0; n < ret; n++)
1569 DWORD j;
1570 /* Disabled to limit console spam */
1571 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1572 trace("{'%c','%c',%d},\n",
1573 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1574 for (j = 0; j < kd[i].total_kern_pairs; j++)
1576 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1577 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1579 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1580 "pair %d:%d got %d, expected %d\n",
1581 kern_pair[n].wFirst, kern_pair[n].wSecond,
1582 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1583 matches++;
1588 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1589 matches, kd[i].total_kern_pairs);
1591 HeapFree(GetProcessHeap(), 0, kern_pair);
1593 SelectObject(hdc, hfont_old);
1594 DeleteObject(hfont);
1597 ReleaseDC(0, hdc);
1600 static void test_height_selection(void)
1602 static const struct font_data
1604 const char face_name[LF_FACESIZE];
1605 int requested_height;
1606 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1607 } fd[] =
1609 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1610 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1611 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1612 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1613 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1614 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1615 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1616 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1617 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1618 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1620 HDC hdc;
1621 LOGFONT lf;
1622 HFONT hfont, old_hfont;
1623 TEXTMETRIC tm;
1624 INT ret, i;
1626 hdc = CreateCompatibleDC(0);
1627 assert(hdc);
1629 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1631 if (!is_truetype_font_installed(fd[i].face_name))
1633 skip("%s is not installed\n", fd[i].face_name);
1634 continue;
1637 memset(&lf, 0, sizeof(lf));
1638 lf.lfHeight = fd[i].requested_height;
1639 lf.lfWeight = fd[i].weight;
1640 strcpy(lf.lfFaceName, fd[i].face_name);
1642 hfont = CreateFontIndirect(&lf);
1643 assert(hfont);
1645 old_hfont = SelectObject(hdc, hfont);
1646 ret = GetTextMetrics(hdc, &tm);
1647 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1648 if(fd[i].dpi == tm.tmDigitizedAspectX)
1650 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1651 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);
1652 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);
1653 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);
1654 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);
1655 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1656 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);
1657 #endif
1658 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);
1661 SelectObject(hdc, old_hfont);
1662 DeleteObject(hfont);
1665 DeleteDC(hdc);
1668 static void test_GetOutlineTextMetrics(void)
1670 OUTLINETEXTMETRIC *otm;
1671 LOGFONT lf;
1672 HFONT hfont, hfont_old;
1673 HDC hdc;
1674 DWORD ret, otm_size;
1675 LPSTR unset_ptr;
1677 if (!is_font_installed("Arial"))
1679 skip("Arial is not installed\n");
1680 return;
1683 hdc = GetDC(0);
1685 memset(&lf, 0, sizeof(lf));
1686 strcpy(lf.lfFaceName, "Arial");
1687 lf.lfHeight = -13;
1688 lf.lfWeight = FW_NORMAL;
1689 lf.lfPitchAndFamily = DEFAULT_PITCH;
1690 lf.lfQuality = PROOF_QUALITY;
1691 hfont = CreateFontIndirect(&lf);
1692 assert(hfont != 0);
1694 hfont_old = SelectObject(hdc, hfont);
1695 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1696 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1698 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1700 memset(otm, 0xAA, otm_size);
1701 SetLastError(0xdeadbeef);
1702 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1703 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1704 ok(ret == 1 /* Win9x */ ||
1705 ret == otm->otmSize /* XP*/,
1706 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1707 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1709 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1710 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1711 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1712 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1715 memset(otm, 0xAA, otm_size);
1716 SetLastError(0xdeadbeef);
1717 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1718 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1719 ok(ret == 1 /* Win9x */ ||
1720 ret == otm->otmSize /* XP*/,
1721 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1722 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1724 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1725 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1726 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1727 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1730 /* ask about truncated data */
1731 memset(otm, 0xAA, otm_size);
1732 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1733 SetLastError(0xdeadbeef);
1734 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1735 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1736 ok(ret == 1 /* Win9x */ ||
1737 ret == otm->otmSize /* XP*/,
1738 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1739 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1741 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1742 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1743 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1745 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1747 HeapFree(GetProcessHeap(), 0, otm);
1749 SelectObject(hdc, hfont_old);
1750 DeleteObject(hfont);
1752 ReleaseDC(0, hdc);
1755 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1757 INT y,
1758 breakCount,
1759 areaWidth = clientArea->right - clientArea->left,
1760 nErrors = 0, e;
1761 PSTR pFirstChar, pLastChar;
1762 SIZE size;
1763 TEXTMETRICA tm;
1764 struct err
1766 char *start;
1767 int len;
1768 int GetTextExtentExPointWWidth;
1769 } error[20];
1771 GetTextMetricsA(hdc, &tm);
1772 y = clientArea->top;
1773 do {
1774 breakCount = 0;
1775 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1776 pFirstChar = str;
1778 do {
1779 pLastChar = str;
1781 /* if not at the end of the string, ... */
1782 if (*str == '\0') break;
1783 /* ... add the next word to the current extent */
1784 while (*str != '\0' && *str++ != tm.tmBreakChar);
1785 breakCount++;
1786 SetTextJustification(hdc, 0, 0);
1787 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1788 } while ((int) size.cx < areaWidth);
1790 /* ignore trailing break chars */
1791 breakCount--;
1792 while (*(pLastChar - 1) == tm.tmBreakChar)
1794 pLastChar--;
1795 breakCount--;
1798 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1800 SetTextJustification(hdc, 0, 0);
1801 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1803 /* do not justify the last extent */
1804 if (*str != '\0' && breakCount > 0)
1806 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1807 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1808 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
1810 error[nErrors].start = pFirstChar;
1811 error[nErrors].len = pLastChar - pFirstChar;
1812 error[nErrors].GetTextExtentExPointWWidth = size.cx;
1813 nErrors++;
1817 trace( "%u %.*s\n", size.cx, (int)(pLastChar - pFirstChar), pFirstChar);
1819 y += size.cy;
1820 str = pLastChar;
1821 } while (*str && y < clientArea->bottom);
1823 for (e = 0; e < nErrors; e++)
1825 /* The width returned by GetTextExtentPoint32() is exactly the same
1826 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1827 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1828 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
1829 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
1833 static void test_SetTextJustification(void)
1835 HDC hdc;
1836 RECT clientArea;
1837 LOGFONTA lf;
1838 HFONT hfont;
1839 HWND hwnd;
1840 SIZE size, expect;
1841 int i;
1842 WORD indices[2];
1843 static char testText[] =
1844 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1845 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1846 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1847 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1848 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1849 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1850 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1852 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1853 GetClientRect( hwnd, &clientArea );
1854 hdc = GetDC( hwnd );
1856 memset(&lf, 0, sizeof lf);
1857 lf.lfCharSet = ANSI_CHARSET;
1858 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1859 lf.lfWeight = FW_DONTCARE;
1860 lf.lfHeight = 20;
1861 lf.lfQuality = DEFAULT_QUALITY;
1862 lstrcpyA(lf.lfFaceName, "Times New Roman");
1863 hfont = create_font("Times New Roman", &lf);
1864 SelectObject(hdc, hfont);
1866 testJustification(hdc, testText, &clientArea);
1868 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
1869 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
1871 SetTextJustification(hdc, 0, 0);
1872 GetTextExtentPoint32(hdc, " ", 1, &expect);
1873 GetTextExtentPoint32(hdc, " ", 3, &size);
1874 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
1875 SetTextJustification(hdc, 4, 1);
1876 GetTextExtentPoint32(hdc, " ", 1, &size);
1877 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
1878 SetTextJustification(hdc, 9, 2);
1879 GetTextExtentPoint32(hdc, " ", 2, &size);
1880 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
1881 SetTextJustification(hdc, 7, 3);
1882 GetTextExtentPoint32(hdc, " ", 3, &size);
1883 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
1884 SetTextJustification(hdc, 7, 3);
1885 SetTextCharacterExtra(hdc, 2 );
1886 GetTextExtentPoint32(hdc, " ", 3, &size);
1887 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
1888 SetTextJustification(hdc, 0, 0);
1889 SetTextCharacterExtra(hdc, 0);
1890 size.cx = size.cy = 1234;
1891 GetTextExtentPoint32(hdc, " ", 0, &size);
1892 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
1893 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
1894 SetTextJustification(hdc, 5, 1);
1895 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
1896 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
1897 SetTextJustification(hdc, 0, 0);
1899 SetMapMode( hdc, MM_ANISOTROPIC );
1900 SetWindowExtEx( hdc, 2, 2, NULL );
1901 GetClientRect( hwnd, &clientArea );
1902 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1903 testJustification(hdc, testText, &clientArea);
1905 GetTextExtentPoint32(hdc, "A", 1, &expect);
1906 for (i = 0; i < 10; i++)
1908 SetTextCharacterExtra(hdc, i);
1909 GetTextExtentPoint32(hdc, "A", 1, &size);
1910 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1912 SetTextCharacterExtra(hdc, 0);
1913 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
1914 for (i = 0; i < 10; i++)
1916 SetTextCharacterExtra(hdc, i);
1917 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
1918 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1920 SetTextCharacterExtra(hdc, 0);
1922 SetViewportExtEx( hdc, 3, 3, NULL );
1923 GetClientRect( hwnd, &clientArea );
1924 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1925 testJustification(hdc, testText, &clientArea);
1927 GetTextExtentPoint32(hdc, "A", 1, &expect);
1928 for (i = 0; i < 10; i++)
1930 SetTextCharacterExtra(hdc, i);
1931 GetTextExtentPoint32(hdc, "A", 1, &size);
1932 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1935 done:
1936 DeleteObject(hfont);
1937 ReleaseDC(hwnd, hdc);
1938 DestroyWindow(hwnd);
1941 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1943 HDC hdc;
1944 LOGFONTA lf;
1945 HFONT hfont, hfont_old;
1946 CHARSETINFO csi;
1947 FONTSIGNATURE fs;
1948 INT cs;
1949 DWORD i, ret;
1950 char name[64];
1952 assert(count <= 128);
1954 memset(&lf, 0, sizeof(lf));
1956 lf.lfCharSet = charset;
1957 lf.lfHeight = 10;
1958 lstrcpyA(lf.lfFaceName, "Arial");
1959 SetLastError(0xdeadbeef);
1960 hfont = CreateFontIndirectA(&lf);
1961 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1963 hdc = GetDC(0);
1964 hfont_old = SelectObject(hdc, hfont);
1966 cs = GetTextCharsetInfo(hdc, &fs, 0);
1967 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1969 SetLastError(0xdeadbeef);
1970 ret = GetTextFaceA(hdc, sizeof(name), name);
1971 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1973 if (charset == SYMBOL_CHARSET)
1975 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1976 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1978 else
1980 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1981 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1984 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1986 trace("Can't find codepage for charset %d\n", cs);
1987 ReleaseDC(0, hdc);
1988 return FALSE;
1990 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1992 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1994 skip("Font code page %d, looking for code page %d\n",
1995 pGdiGetCodePage(hdc), code_page);
1996 ReleaseDC(0, hdc);
1997 return FALSE;
2000 if (unicode)
2002 char ansi_buf[128];
2003 WCHAR unicode_buf[128];
2005 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2007 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2009 SetLastError(0xdeadbeef);
2010 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2011 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2012 count, ret, GetLastError());
2014 else
2016 char ansi_buf[128];
2018 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2020 SetLastError(0xdeadbeef);
2021 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2022 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2023 count, ret, GetLastError());
2026 SelectObject(hdc, hfont_old);
2027 DeleteObject(hfont);
2029 ReleaseDC(0, hdc);
2031 return TRUE;
2034 static void test_font_charset(void)
2036 static struct charset_data
2038 INT charset;
2039 UINT code_page;
2040 WORD font_idxA[128], font_idxW[128];
2041 } cd[] =
2043 { ANSI_CHARSET, 1252 },
2044 { RUSSIAN_CHARSET, 1251 },
2045 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2047 int i;
2049 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2051 win_skip("Skipping the font charset test on a Win9x platform\n");
2052 return;
2055 if (!is_font_installed("Arial"))
2057 skip("Arial is not installed\n");
2058 return;
2061 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2063 if (cd[i].charset == SYMBOL_CHARSET)
2065 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2067 skip("Symbol or Wingdings is not installed\n");
2068 break;
2071 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2072 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2073 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2076 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2077 if (i > 2)
2079 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2080 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2082 else
2083 skip("Symbol or Wingdings is not installed\n");
2086 static void test_GetFontUnicodeRanges(void)
2088 LOGFONTA lf;
2089 HDC hdc;
2090 HFONT hfont, hfont_old;
2091 DWORD size;
2092 GLYPHSET *gs;
2093 DWORD i;
2095 if (!pGetFontUnicodeRanges)
2097 win_skip("GetFontUnicodeRanges not available before W2K\n");
2098 return;
2101 memset(&lf, 0, sizeof(lf));
2102 lstrcpyA(lf.lfFaceName, "Arial");
2103 hfont = create_font("Arial", &lf);
2105 hdc = GetDC(0);
2106 hfont_old = SelectObject(hdc, hfont);
2108 size = pGetFontUnicodeRanges(NULL, NULL);
2109 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2111 size = pGetFontUnicodeRanges(hdc, NULL);
2112 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2114 gs = HeapAlloc(GetProcessHeap(), 0, size);
2116 size = pGetFontUnicodeRanges(hdc, gs);
2117 ok(size, "GetFontUnicodeRanges failed\n");
2119 if (0) /* Disabled to limit console spam */
2120 for (i = 0; i < gs->cRanges; i++)
2121 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2122 trace("found %u ranges\n", gs->cRanges);
2124 HeapFree(GetProcessHeap(), 0, gs);
2126 SelectObject(hdc, hfont_old);
2127 DeleteObject(hfont);
2128 ReleaseDC(NULL, hdc);
2131 #define MAX_ENUM_FONTS 4096
2133 struct enum_font_data
2135 int total;
2136 LOGFONT lf[MAX_ENUM_FONTS];
2139 struct enum_fullname_data
2141 int total;
2142 ENUMLOGFONT elf[MAX_ENUM_FONTS];
2145 struct enum_font_dataW
2147 int total;
2148 LOGFONTW lf[MAX_ENUM_FONTS];
2151 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2153 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2154 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2156 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2157 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2159 if (type != TRUETYPE_FONTTYPE) return 1;
2161 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2163 if (0) /* Disabled to limit console spam */
2164 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2165 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2166 if (efd->total < MAX_ENUM_FONTS)
2167 efd->lf[efd->total++] = *lf;
2168 else
2169 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2171 return 1;
2174 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2176 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2177 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2179 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2180 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2182 if (type != TRUETYPE_FONTTYPE) return 1;
2184 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2186 if (0) /* Disabled to limit console spam */
2187 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2188 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2189 if (efd->total < MAX_ENUM_FONTS)
2190 efd->lf[efd->total++] = *lf;
2191 else
2192 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2194 return 1;
2197 static void get_charset_stats(struct enum_font_data *efd,
2198 int *ansi_charset, int *symbol_charset,
2199 int *russian_charset)
2201 int i;
2203 *ansi_charset = 0;
2204 *symbol_charset = 0;
2205 *russian_charset = 0;
2207 for (i = 0; i < efd->total; i++)
2209 switch (efd->lf[i].lfCharSet)
2211 case ANSI_CHARSET:
2212 (*ansi_charset)++;
2213 break;
2214 case SYMBOL_CHARSET:
2215 (*symbol_charset)++;
2216 break;
2217 case RUSSIAN_CHARSET:
2218 (*russian_charset)++;
2219 break;
2224 static void get_charset_statsW(struct enum_font_dataW *efd,
2225 int *ansi_charset, int *symbol_charset,
2226 int *russian_charset)
2228 int i;
2230 *ansi_charset = 0;
2231 *symbol_charset = 0;
2232 *russian_charset = 0;
2234 for (i = 0; i < efd->total; i++)
2236 switch (efd->lf[i].lfCharSet)
2238 case ANSI_CHARSET:
2239 (*ansi_charset)++;
2240 break;
2241 case SYMBOL_CHARSET:
2242 (*symbol_charset)++;
2243 break;
2244 case RUSSIAN_CHARSET:
2245 (*russian_charset)++;
2246 break;
2251 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2253 struct enum_font_data efd;
2254 struct enum_font_dataW efdw;
2255 LOGFONT lf;
2256 HDC hdc;
2257 int i, ret, ansi_charset, symbol_charset, russian_charset;
2259 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2261 if (*font_name && !is_truetype_font_installed(font_name))
2263 skip("%s is not installed\n", font_name);
2264 return;
2267 hdc = GetDC(0);
2269 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2270 * while EnumFontFamiliesEx doesn't.
2272 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2275 * Use EnumFontFamiliesW since win98 crashes when the
2276 * second parameter is NULL using EnumFontFamilies
2278 efdw.total = 0;
2279 SetLastError(0xdeadbeef);
2280 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2281 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2282 if(ret)
2284 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2285 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2286 ansi_charset, symbol_charset, russian_charset);
2287 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2288 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2289 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2290 ok(russian_charset > 0 ||
2291 broken(russian_charset == 0), /* NT4 */
2292 "NULL family should enumerate RUSSIAN_CHARSET\n");
2295 efdw.total = 0;
2296 SetLastError(0xdeadbeef);
2297 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2298 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2299 if(ret)
2301 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2302 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2303 ansi_charset, symbol_charset, russian_charset);
2304 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2305 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2306 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2307 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2311 efd.total = 0;
2312 SetLastError(0xdeadbeef);
2313 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2314 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2315 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2316 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2317 ansi_charset, symbol_charset, russian_charset,
2318 *font_name ? font_name : "<empty>");
2319 if (*font_name)
2320 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2321 else
2322 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2323 for (i = 0; i < efd.total; i++)
2325 /* FIXME: remove completely once Wine is fixed */
2326 if (efd.lf[i].lfCharSet != font_charset)
2328 todo_wine
2329 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2331 else
2332 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2333 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2334 font_name, efd.lf[i].lfFaceName);
2337 memset(&lf, 0, sizeof(lf));
2338 lf.lfCharSet = ANSI_CHARSET;
2339 lstrcpy(lf.lfFaceName, font_name);
2340 efd.total = 0;
2341 SetLastError(0xdeadbeef);
2342 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2343 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2344 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2345 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2346 ansi_charset, symbol_charset, russian_charset,
2347 *font_name ? font_name : "<empty>");
2348 if (font_charset == SYMBOL_CHARSET)
2350 if (*font_name)
2351 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2352 else
2353 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2355 else
2357 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2358 for (i = 0; i < efd.total; i++)
2360 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2361 if (*font_name)
2362 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2363 font_name, efd.lf[i].lfFaceName);
2367 /* DEFAULT_CHARSET should enumerate all available charsets */
2368 memset(&lf, 0, sizeof(lf));
2369 lf.lfCharSet = DEFAULT_CHARSET;
2370 lstrcpy(lf.lfFaceName, font_name);
2371 efd.total = 0;
2372 SetLastError(0xdeadbeef);
2373 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2374 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2375 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2376 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2377 ansi_charset, symbol_charset, russian_charset,
2378 *font_name ? font_name : "<empty>");
2379 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2380 for (i = 0; i < efd.total; i++)
2382 if (*font_name)
2383 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2384 font_name, efd.lf[i].lfFaceName);
2386 if (*font_name)
2388 switch (font_charset)
2390 case ANSI_CHARSET:
2391 ok(ansi_charset > 0,
2392 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2393 ok(!symbol_charset,
2394 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2395 ok(russian_charset > 0,
2396 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2397 break;
2398 case SYMBOL_CHARSET:
2399 ok(!ansi_charset,
2400 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2401 ok(symbol_charset,
2402 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2403 ok(!russian_charset,
2404 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2405 break;
2406 case DEFAULT_CHARSET:
2407 ok(ansi_charset > 0,
2408 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2409 ok(symbol_charset > 0,
2410 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2411 ok(russian_charset > 0,
2412 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2413 break;
2416 else
2418 ok(ansi_charset > 0,
2419 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2420 ok(symbol_charset > 0,
2421 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2422 ok(russian_charset > 0,
2423 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2426 memset(&lf, 0, sizeof(lf));
2427 lf.lfCharSet = SYMBOL_CHARSET;
2428 lstrcpy(lf.lfFaceName, font_name);
2429 efd.total = 0;
2430 SetLastError(0xdeadbeef);
2431 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2432 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2433 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2434 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2435 ansi_charset, symbol_charset, russian_charset,
2436 *font_name ? font_name : "<empty>");
2437 if (*font_name && font_charset == ANSI_CHARSET)
2438 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2439 else
2441 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2442 for (i = 0; i < efd.total; i++)
2444 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2445 if (*font_name)
2446 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2447 font_name, efd.lf[i].lfFaceName);
2450 ok(!ansi_charset,
2451 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2452 ok(symbol_charset > 0,
2453 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2454 ok(!russian_charset,
2455 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2458 ReleaseDC(0, hdc);
2461 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2463 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2465 if (type != TRUETYPE_FONTTYPE) return 1;
2467 if (efd->total < MAX_ENUM_FONTS)
2468 efd->lf[efd->total++] = *lf;
2469 else
2470 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2472 return 1;
2475 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2477 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2479 if (type != TRUETYPE_FONTTYPE) return 1;
2481 if (efnd->total < MAX_ENUM_FONTS)
2482 efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2483 else
2484 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2486 return 1;
2489 static void test_EnumFontFamiliesEx_default_charset(void)
2491 struct enum_font_data efd;
2492 LOGFONT gui_font, enum_font;
2493 DWORD ret;
2494 HDC hdc;
2496 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2497 ok(ret, "GetObject failed.\n");
2498 if (!ret)
2499 return;
2501 efd.total = 0;
2503 hdc = GetDC(0);
2504 memset(&enum_font, 0, sizeof(enum_font));
2505 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2506 enum_font.lfCharSet = DEFAULT_CHARSET;
2507 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2508 ReleaseDC(0, hdc);
2510 if (efd.total == 0) {
2511 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2512 return;
2514 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2516 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet || broken(system_lang_id == LANG_ARABIC),
2517 "(%s) got charset %d expected %d\n",
2518 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2520 return;
2523 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2525 HFONT hfont, hfont_prev;
2526 DWORD ret;
2527 GLYPHMETRICS gm1, gm2;
2528 LOGFONTA lf2 = *lf;
2529 WORD idx;
2531 if(!pGetGlyphIndicesA)
2532 return;
2534 /* negative widths are handled just as positive ones */
2535 lf2.lfWidth = -lf->lfWidth;
2537 SetLastError(0xdeadbeef);
2538 hfont = CreateFontIndirectA(lf);
2539 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2540 check_font("original", lf, hfont);
2542 hfont_prev = SelectObject(hdc, hfont);
2544 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2545 if (ret == GDI_ERROR || idx == 0xffff)
2547 SelectObject(hdc, hfont_prev);
2548 DeleteObject(hfont);
2549 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2550 return;
2553 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2554 memset(&gm1, 0xab, sizeof(gm1));
2555 SetLastError(0xdeadbeef);
2556 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2557 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2559 SelectObject(hdc, hfont_prev);
2560 DeleteObject(hfont);
2562 SetLastError(0xdeadbeef);
2563 hfont = CreateFontIndirectA(&lf2);
2564 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2565 check_font("negative width", &lf2, hfont);
2567 hfont_prev = SelectObject(hdc, hfont);
2569 memset(&gm2, 0xbb, sizeof(gm2));
2570 SetLastError(0xdeadbeef);
2571 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2572 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2574 SelectObject(hdc, hfont_prev);
2575 DeleteObject(hfont);
2577 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2578 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2579 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2580 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2581 gm1.gmCellIncX == gm2.gmCellIncX &&
2582 gm1.gmCellIncY == gm2.gmCellIncY,
2583 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2584 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2585 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2586 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2587 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2590 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2591 #include "pshpack2.h"
2592 typedef struct
2594 USHORT version;
2595 SHORT xAvgCharWidth;
2596 USHORT usWeightClass;
2597 USHORT usWidthClass;
2598 SHORT fsType;
2599 SHORT ySubscriptXSize;
2600 SHORT ySubscriptYSize;
2601 SHORT ySubscriptXOffset;
2602 SHORT ySubscriptYOffset;
2603 SHORT ySuperscriptXSize;
2604 SHORT ySuperscriptYSize;
2605 SHORT ySuperscriptXOffset;
2606 SHORT ySuperscriptYOffset;
2607 SHORT yStrikeoutSize;
2608 SHORT yStrikeoutPosition;
2609 SHORT sFamilyClass;
2610 PANOSE panose;
2611 ULONG ulUnicodeRange1;
2612 ULONG ulUnicodeRange2;
2613 ULONG ulUnicodeRange3;
2614 ULONG ulUnicodeRange4;
2615 CHAR achVendID[4];
2616 USHORT fsSelection;
2617 USHORT usFirstCharIndex;
2618 USHORT usLastCharIndex;
2619 /* According to the Apple spec, original version didn't have the below fields,
2620 * version numbers were taken from the OpenType spec.
2622 /* version 0 (TrueType 1.5) */
2623 USHORT sTypoAscender;
2624 USHORT sTypoDescender;
2625 USHORT sTypoLineGap;
2626 USHORT usWinAscent;
2627 USHORT usWinDescent;
2628 /* version 1 (TrueType 1.66) */
2629 ULONG ulCodePageRange1;
2630 ULONG ulCodePageRange2;
2631 /* version 2 (OpenType 1.2) */
2632 SHORT sxHeight;
2633 SHORT sCapHeight;
2634 USHORT usDefaultChar;
2635 USHORT usBreakChar;
2636 USHORT usMaxContext;
2637 } TT_OS2_V2;
2638 #include "poppack.h"
2640 #ifdef WORDS_BIGENDIAN
2641 #define GET_BE_WORD(x) (x)
2642 #define GET_BE_DWORD(x) (x)
2643 #else
2644 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2645 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2646 #endif
2648 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2649 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2650 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2651 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2652 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2653 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2655 typedef struct
2657 USHORT version;
2658 USHORT num_tables;
2659 } cmap_header;
2661 typedef struct
2663 USHORT plat_id;
2664 USHORT enc_id;
2665 ULONG offset;
2666 } cmap_encoding_record;
2668 typedef struct
2670 USHORT format;
2671 USHORT length;
2672 USHORT language;
2674 BYTE glyph_ids[256];
2675 } cmap_format_0;
2677 typedef struct
2679 USHORT format;
2680 USHORT length;
2681 USHORT language;
2683 USHORT seg_countx2;
2684 USHORT search_range;
2685 USHORT entry_selector;
2686 USHORT range_shift;
2688 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2689 /* Then follows:
2690 USHORT pad;
2691 USHORT start_count[seg_countx2 / 2];
2692 USHORT id_delta[seg_countx2 / 2];
2693 USHORT id_range_offset[seg_countx2 / 2];
2694 USHORT glyph_ids[];
2696 } cmap_format_4;
2698 typedef struct
2700 USHORT end_count;
2701 USHORT start_count;
2702 USHORT id_delta;
2703 USHORT id_range_offset;
2704 } cmap_format_4_seg;
2706 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2708 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2709 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2710 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2711 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2712 os2->panose.bWeight, os2->panose.bProportion);
2715 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2717 int i;
2718 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2720 *first = 256;
2722 for(i = 0; i < 256; i++)
2724 if(cmap->glyph_ids[i] == 0) continue;
2725 *last = i;
2726 if(*first == 256) *first = i;
2728 if(*first == 256) return FALSE;
2729 return TRUE;
2732 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2734 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2735 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2736 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2737 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2738 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2741 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2743 int i;
2744 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2745 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2746 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2748 *first = 0x10000;
2750 for(i = 0; i < seg_count; i++)
2752 DWORD code, index;
2753 cmap_format_4_seg seg;
2755 get_seg4(cmap, i, &seg);
2756 for(code = seg.start_count; code <= seg.end_count; code++)
2758 if(seg.id_range_offset == 0)
2759 index = (seg.id_delta + code) & 0xffff;
2760 else
2762 index = seg.id_range_offset / 2
2763 + code - seg.start_count
2764 + i - seg_count;
2766 /* some fonts have broken last segment */
2767 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2768 index = GET_BE_WORD(glyph_ids[index]);
2769 else
2771 trace("segment %04x/%04x index %04x points to nowhere\n",
2772 seg.start_count, seg.end_count, index);
2773 index = 0;
2775 if(index) index += seg.id_delta;
2777 if(*first == 0x10000)
2778 *last = *first = code;
2779 else if(index)
2780 *last = code;
2784 if(*first == 0x10000) return FALSE;
2785 return TRUE;
2788 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2790 USHORT i;
2791 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2793 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2795 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2796 return (BYTE *)header + GET_BE_DWORD(record->offset);
2797 record++;
2799 return NULL;
2802 typedef enum
2804 cmap_none,
2805 cmap_ms_unicode,
2806 cmap_ms_symbol
2807 } cmap_type;
2809 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2811 LONG size, ret;
2812 cmap_header *header;
2813 void *cmap;
2814 BOOL r = FALSE;
2815 WORD format;
2817 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2818 ok(size != GDI_ERROR, "no cmap table found\n");
2819 if(size == GDI_ERROR) return FALSE;
2821 header = HeapAlloc(GetProcessHeap(), 0, size);
2822 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2823 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2824 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2826 cmap = get_cmap(header, 3, 1);
2827 if(cmap)
2828 *cmap_type = cmap_ms_unicode;
2829 else
2831 cmap = get_cmap(header, 3, 0);
2832 if(cmap) *cmap_type = cmap_ms_symbol;
2834 if(!cmap)
2836 *cmap_type = cmap_none;
2837 goto end;
2840 format = GET_BE_WORD(*(WORD *)cmap);
2841 switch(format)
2843 case 0:
2844 r = get_first_last_from_cmap0(cmap, first, last);
2845 break;
2846 case 4:
2847 r = get_first_last_from_cmap4(cmap, first, last, size);
2848 break;
2849 default:
2850 trace("unhandled cmap format %d\n", format);
2851 break;
2854 end:
2855 HeapFree(GetProcessHeap(), 0, header);
2856 return r;
2859 #define TT_PLATFORM_MICROSOFT 3
2860 #define TT_MS_ID_SYMBOL_CS 0
2861 #define TT_MS_ID_UNICODE_CS 1
2862 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2863 #define TT_NAME_ID_FONT_FAMILY 1
2864 #define TT_NAME_ID_FONT_SUBFAMILY 2
2865 #define TT_NAME_ID_UNIQUE_ID 3
2866 #define TT_NAME_ID_FULL_NAME 4
2868 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2870 struct sfnt_name_header
2872 USHORT format;
2873 USHORT number_of_record;
2874 USHORT storage_offset;
2875 } *header;
2876 struct sfnt_name
2878 USHORT platform_id;
2879 USHORT encoding_id;
2880 USHORT language_id;
2881 USHORT name_id;
2882 USHORT length;
2883 USHORT offset;
2884 } *entry;
2885 BOOL r = FALSE;
2886 LONG size, offset, length;
2887 LONG c, ret;
2888 WCHAR *name;
2889 BYTE *data;
2890 USHORT i;
2892 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2893 ok(size != GDI_ERROR, "no name table found\n");
2894 if(size == GDI_ERROR) return FALSE;
2896 data = HeapAlloc(GetProcessHeap(), 0, size);
2897 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2898 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2900 header = (void *)data;
2901 header->format = GET_BE_WORD(header->format);
2902 header->number_of_record = GET_BE_WORD(header->number_of_record);
2903 header->storage_offset = GET_BE_WORD(header->storage_offset);
2904 if (header->format != 0)
2906 trace("got format %u\n", header->format);
2907 goto out;
2909 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2911 trace("number records out of range: %d\n", header->number_of_record);
2912 goto out;
2914 if (header->storage_offset >= size)
2916 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2917 goto out;
2920 entry = (void *)&header[1];
2921 for (i = 0; i < header->number_of_record; i++)
2923 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2924 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
2925 GET_BE_WORD(entry[i].language_id) != language_id ||
2926 GET_BE_WORD(entry[i].name_id) != name_id)
2928 continue;
2931 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2932 length = GET_BE_WORD(entry[i].length);
2933 if (offset + length > size)
2935 trace("entry %d is out of range\n", i);
2936 break;
2938 if (length >= out_size)
2940 trace("buffer too small for entry %d\n", i);
2941 break;
2944 name = (WCHAR *)(data + offset);
2945 for (c = 0; c < length / 2; c++)
2946 out_buf[c] = GET_BE_WORD(name[c]);
2947 out_buf[c] = 0;
2949 r = TRUE;
2950 break;
2953 out:
2954 HeapFree(GetProcessHeap(), 0, data);
2955 return r;
2958 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2960 HDC hdc;
2961 HFONT hfont, hfont_old;
2962 TEXTMETRICA tmA;
2963 TT_OS2_V2 tt_os2;
2964 LONG size, ret;
2965 const char *font_name = lf->lfFaceName;
2966 DWORD cmap_first = 0, cmap_last = 0;
2967 UINT ascent, descent, cell_height;
2968 cmap_type cmap_type;
2969 BOOL sys_lang_non_english;
2971 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2972 hdc = GetDC(0);
2974 SetLastError(0xdeadbeef);
2975 hfont = CreateFontIndirectA(lf);
2976 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2978 hfont_old = SelectObject(hdc, hfont);
2980 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2981 if (size == GDI_ERROR)
2983 trace("OS/2 chunk was not found\n");
2984 goto end_of_test;
2986 if (size > sizeof(tt_os2))
2988 trace("got too large OS/2 chunk of size %u\n", size);
2989 size = sizeof(tt_os2);
2992 memset(&tt_os2, 0, sizeof(tt_os2));
2993 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2994 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2996 ascent = GET_BE_WORD(tt_os2.usWinAscent);
2997 descent = GET_BE_WORD(tt_os2.usWinDescent);
2998 cell_height = ascent + descent;
2999 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3000 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3002 SetLastError(0xdeadbeef);
3003 ret = GetTextMetricsA(hdc, &tmA);
3004 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3006 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3008 skip("Unable to retrieve first and last glyphs from cmap\n");
3010 else
3012 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3013 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3014 UINT os2_first_char, os2_last_char, default_char, break_char;
3015 USHORT version;
3016 TEXTMETRICW tmW;
3018 version = GET_BE_WORD(tt_os2.version);
3020 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3021 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3022 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3023 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3025 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3026 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3027 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3029 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3031 expect_first_W = 0;
3032 switch(GetACP())
3034 case 1257: /* Baltic */
3035 expect_last_W = 0xf8fd;
3036 break;
3037 default:
3038 expect_last_W = 0xf0ff;
3040 expect_break_W = 0x20;
3041 expect_default_W = expect_break_W - 1;
3042 expect_first_A = 0x1e;
3043 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3045 else
3047 expect_first_W = cmap_first;
3048 expect_last_W = min(cmap_last, os2_last_char);
3049 if(os2_first_char <= 1)
3050 expect_break_W = os2_first_char + 2;
3051 else if(os2_first_char > 0xff)
3052 expect_break_W = 0x20;
3053 else
3054 expect_break_W = os2_first_char;
3055 expect_default_W = expect_break_W - 1;
3056 expect_first_A = expect_default_W - 1;
3057 expect_last_A = min(expect_last_W, 0xff);
3059 expect_break_A = expect_break_W;
3060 expect_default_A = expect_default_W;
3062 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3063 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3064 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3065 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3066 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3067 else
3068 ok(tmA.tmFirstChar == expect_first_A ||
3069 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3070 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3071 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3072 ok(tmA.tmLastChar == expect_last_A ||
3073 tmA.tmLastChar == 0xff /* win9x */,
3074 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3075 else
3076 skip("tmLastChar is DBCS lead byte\n");
3077 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3078 font_name, tmA.tmBreakChar, expect_break_A);
3079 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3080 "A: tmDefaultChar for %s got %02x expected %02x\n",
3081 font_name, tmA.tmDefaultChar, expect_default_A);
3084 SetLastError(0xdeadbeef);
3085 ret = GetTextMetricsW(hdc, &tmW);
3086 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3087 "GetTextMetricsW error %u\n", GetLastError());
3088 if (ret)
3090 /* Wine uses the os2 first char */
3091 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3092 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3093 font_name, tmW.tmFirstChar, expect_first_W);
3094 else
3095 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3096 font_name, tmW.tmFirstChar, expect_first_W);
3098 /* Wine uses the os2 last char */
3099 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3100 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3101 font_name, tmW.tmLastChar, expect_last_W);
3102 else
3103 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3104 font_name, tmW.tmLastChar, expect_last_W);
3105 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3106 font_name, tmW.tmBreakChar, expect_break_W);
3107 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3108 "W: tmDefaultChar for %s got %02x expected %02x\n",
3109 font_name, tmW.tmDefaultChar, expect_default_W);
3111 /* Test the aspect ratio while we have tmW */
3112 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3113 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3114 tmW.tmDigitizedAspectX, ret);
3115 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3116 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3117 tmW.tmDigitizedAspectX, ret);
3121 /* test FF_ values */
3122 switch(tt_os2.panose.bFamilyType)
3124 case PAN_ANY:
3125 case PAN_NO_FIT:
3126 case PAN_FAMILY_TEXT_DISPLAY:
3127 case PAN_FAMILY_PICTORIAL:
3128 default:
3129 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3130 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3132 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3133 break;
3135 switch(tt_os2.panose.bSerifStyle)
3137 case PAN_ANY:
3138 case PAN_NO_FIT:
3139 default:
3140 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3141 break;
3143 case PAN_SERIF_COVE:
3144 case PAN_SERIF_OBTUSE_COVE:
3145 case PAN_SERIF_SQUARE_COVE:
3146 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3147 case PAN_SERIF_SQUARE:
3148 case PAN_SERIF_THIN:
3149 case PAN_SERIF_BONE:
3150 case PAN_SERIF_EXAGGERATED:
3151 case PAN_SERIF_TRIANGLE:
3152 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3153 break;
3155 case PAN_SERIF_NORMAL_SANS:
3156 case PAN_SERIF_OBTUSE_SANS:
3157 case PAN_SERIF_PERP_SANS:
3158 case PAN_SERIF_FLARED:
3159 case PAN_SERIF_ROUNDED:
3160 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3161 break;
3163 break;
3165 case PAN_FAMILY_SCRIPT:
3166 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3167 break;
3169 case PAN_FAMILY_DECORATIVE:
3170 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3171 break;
3174 test_negative_width(hdc, lf);
3176 end_of_test:
3177 SelectObject(hdc, hfont_old);
3178 DeleteObject(hfont);
3180 ReleaseDC(0, hdc);
3183 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3185 INT *enumed = (INT *)lParam;
3187 if (type == TRUETYPE_FONTTYPE)
3189 (*enumed)++;
3190 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3192 return 1;
3195 static void test_GetTextMetrics(void)
3197 LOGFONTA lf;
3198 HDC hdc;
3199 INT enumed;
3201 /* Report only once */
3202 if(!pGetGlyphIndicesA)
3203 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3205 hdc = GetDC(0);
3207 memset(&lf, 0, sizeof(lf));
3208 lf.lfCharSet = DEFAULT_CHARSET;
3209 enumed = 0;
3210 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3211 trace("Tested metrics of %d truetype fonts\n", enumed);
3213 ReleaseDC(0, hdc);
3216 static void test_nonexistent_font(void)
3218 static const struct
3220 const char *name;
3221 int charset;
3222 } font_subst[] =
3224 { "Times New Roman Baltic", 186 },
3225 { "Times New Roman CE", 238 },
3226 { "Times New Roman CYR", 204 },
3227 { "Times New Roman Greek", 161 },
3228 { "Times New Roman TUR", 162 }
3230 LOGFONTA lf;
3231 HDC hdc;
3232 HFONT hfont;
3233 CHARSETINFO csi;
3234 INT cs, expected_cs, i;
3235 char buf[LF_FACESIZE];
3237 if (!is_truetype_font_installed("Arial") ||
3238 !is_truetype_font_installed("Times New Roman"))
3240 skip("Arial or Times New Roman not installed\n");
3241 return;
3244 expected_cs = GetACP();
3245 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3247 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3248 return;
3250 expected_cs = csi.ciCharset;
3251 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3253 hdc = GetDC(0);
3255 memset(&lf, 0, sizeof(lf));
3256 lf.lfHeight = 100;
3257 lf.lfWeight = FW_REGULAR;
3258 lf.lfCharSet = ANSI_CHARSET;
3259 lf.lfPitchAndFamily = FF_SWISS;
3260 strcpy(lf.lfFaceName, "Nonexistent font");
3261 hfont = CreateFontIndirectA(&lf);
3262 hfont = SelectObject(hdc, hfont);
3263 GetTextFaceA(hdc, sizeof(buf), buf);
3264 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3265 cs = GetTextCharset(hdc);
3266 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3267 DeleteObject(SelectObject(hdc, hfont));
3269 memset(&lf, 0, sizeof(lf));
3270 lf.lfHeight = -13;
3271 lf.lfWeight = FW_DONTCARE;
3272 strcpy(lf.lfFaceName, "Nonexistent font");
3273 hfont = CreateFontIndirectA(&lf);
3274 hfont = SelectObject(hdc, hfont);
3275 GetTextFaceA(hdc, sizeof(buf), buf);
3276 todo_wine /* Wine uses Arial for all substitutions */
3277 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3278 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3279 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3280 "Got %s\n", buf);
3281 cs = GetTextCharset(hdc);
3282 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3283 DeleteObject(SelectObject(hdc, hfont));
3285 memset(&lf, 0, sizeof(lf));
3286 lf.lfHeight = -13;
3287 lf.lfWeight = FW_REGULAR;
3288 strcpy(lf.lfFaceName, "Nonexistent font");
3289 hfont = CreateFontIndirectA(&lf);
3290 hfont = SelectObject(hdc, hfont);
3291 GetTextFaceA(hdc, sizeof(buf), buf);
3292 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3293 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3294 cs = GetTextCharset(hdc);
3295 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3296 DeleteObject(SelectObject(hdc, hfont));
3298 memset(&lf, 0, sizeof(lf));
3299 lf.lfHeight = -13;
3300 lf.lfWeight = FW_DONTCARE;
3301 strcpy(lf.lfFaceName, "Times New Roman");
3302 hfont = CreateFontIndirectA(&lf);
3303 hfont = SelectObject(hdc, hfont);
3304 GetTextFaceA(hdc, sizeof(buf), buf);
3305 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3306 cs = GetTextCharset(hdc);
3307 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3308 DeleteObject(SelectObject(hdc, hfont));
3310 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3312 memset(&lf, 0, sizeof(lf));
3313 lf.lfHeight = -13;
3314 lf.lfWeight = FW_REGULAR;
3315 strcpy(lf.lfFaceName, font_subst[i].name);
3316 hfont = CreateFontIndirectA(&lf);
3317 hfont = SelectObject(hdc, hfont);
3318 cs = GetTextCharset(hdc);
3319 if (font_subst[i].charset == expected_cs)
3321 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3322 GetTextFaceA(hdc, sizeof(buf), buf);
3323 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3325 else
3327 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3328 GetTextFaceA(hdc, sizeof(buf), buf);
3329 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3330 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3332 DeleteObject(SelectObject(hdc, hfont));
3334 memset(&lf, 0, sizeof(lf));
3335 lf.lfHeight = -13;
3336 lf.lfWeight = FW_DONTCARE;
3337 strcpy(lf.lfFaceName, font_subst[i].name);
3338 hfont = CreateFontIndirectA(&lf);
3339 hfont = SelectObject(hdc, hfont);
3340 GetTextFaceA(hdc, sizeof(buf), buf);
3341 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3342 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3343 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3344 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3345 "got %s for font %s\n", buf, font_subst[i].name);
3346 cs = GetTextCharset(hdc);
3347 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3348 DeleteObject(SelectObject(hdc, hfont));
3351 ReleaseDC(0, hdc);
3354 static void test_GdiRealizationInfo(void)
3356 HDC hdc;
3357 DWORD info[4];
3358 BOOL r;
3359 HFONT hfont, hfont_old;
3360 LOGFONTA lf;
3362 if(!pGdiRealizationInfo)
3364 win_skip("GdiRealizationInfo not available\n");
3365 return;
3368 hdc = GetDC(0);
3370 memset(info, 0xcc, sizeof(info));
3371 r = pGdiRealizationInfo(hdc, info);
3372 ok(r != 0, "ret 0\n");
3373 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3374 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3376 if (!is_truetype_font_installed("Arial"))
3378 skip("skipping GdiRealizationInfo with truetype font\n");
3379 goto end;
3382 memset(&lf, 0, sizeof(lf));
3383 strcpy(lf.lfFaceName, "Arial");
3384 lf.lfHeight = 20;
3385 lf.lfWeight = FW_NORMAL;
3386 hfont = CreateFontIndirectA(&lf);
3387 hfont_old = SelectObject(hdc, hfont);
3389 memset(info, 0xcc, sizeof(info));
3390 r = pGdiRealizationInfo(hdc, info);
3391 ok(r != 0, "ret 0\n");
3392 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3393 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3395 DeleteObject(SelectObject(hdc, hfont_old));
3397 end:
3398 ReleaseDC(0, hdc);
3401 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3402 the nul in the count of characters copied when the face name buffer is not
3403 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3404 always includes it. */
3405 static void test_GetTextFace(void)
3407 static const char faceA[] = "Tahoma";
3408 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3409 LOGFONTA fA = {0};
3410 LOGFONTW fW = {0};
3411 char bufA[LF_FACESIZE];
3412 WCHAR bufW[LF_FACESIZE];
3413 HFONT f, g;
3414 HDC dc;
3415 int n;
3417 if(!is_font_installed("Tahoma"))
3419 skip("Tahoma is not installed so skipping this test\n");
3420 return;
3423 /* 'A' case. */
3424 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3425 f = CreateFontIndirectA(&fA);
3426 ok(f != NULL, "CreateFontIndirectA failed\n");
3428 dc = GetDC(NULL);
3429 g = SelectObject(dc, f);
3430 n = GetTextFaceA(dc, sizeof bufA, bufA);
3431 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3432 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3434 /* Play with the count arg. */
3435 bufA[0] = 'x';
3436 n = GetTextFaceA(dc, 0, bufA);
3437 ok(n == 0, "GetTextFaceA returned %d\n", n);
3438 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3440 bufA[0] = 'x';
3441 n = GetTextFaceA(dc, 1, bufA);
3442 ok(n == 0, "GetTextFaceA returned %d\n", n);
3443 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3445 bufA[0] = 'x'; bufA[1] = 'y';
3446 n = GetTextFaceA(dc, 2, bufA);
3447 ok(n == 1, "GetTextFaceA returned %d\n", n);
3448 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3450 n = GetTextFaceA(dc, 0, NULL);
3451 ok(n == sizeof faceA ||
3452 broken(n == 0), /* win98, winMe */
3453 "GetTextFaceA returned %d\n", n);
3455 DeleteObject(SelectObject(dc, g));
3456 ReleaseDC(NULL, dc);
3458 /* 'W' case. */
3459 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3460 SetLastError(0xdeadbeef);
3461 f = CreateFontIndirectW(&fW);
3462 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3464 win_skip("CreateFontIndirectW is not implemented\n");
3465 return;
3467 ok(f != NULL, "CreateFontIndirectW failed\n");
3469 dc = GetDC(NULL);
3470 g = SelectObject(dc, f);
3471 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3472 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3473 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3475 /* Play with the count arg. */
3476 bufW[0] = 'x';
3477 n = GetTextFaceW(dc, 0, bufW);
3478 ok(n == 0, "GetTextFaceW returned %d\n", n);
3479 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3481 bufW[0] = 'x';
3482 n = GetTextFaceW(dc, 1, bufW);
3483 ok(n == 1, "GetTextFaceW returned %d\n", n);
3484 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3486 bufW[0] = 'x'; bufW[1] = 'y';
3487 n = GetTextFaceW(dc, 2, bufW);
3488 ok(n == 2, "GetTextFaceW returned %d\n", n);
3489 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3491 n = GetTextFaceW(dc, 0, NULL);
3492 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3494 DeleteObject(SelectObject(dc, g));
3495 ReleaseDC(NULL, dc);
3498 static void test_orientation(void)
3500 static const char test_str[11] = "Test String";
3501 HDC hdc;
3502 LOGFONTA lf;
3503 HFONT hfont, old_hfont;
3504 SIZE size;
3506 if (!is_truetype_font_installed("Arial"))
3508 skip("Arial is not installed\n");
3509 return;
3512 hdc = CreateCompatibleDC(0);
3513 memset(&lf, 0, sizeof(lf));
3514 lstrcpyA(lf.lfFaceName, "Arial");
3515 lf.lfHeight = 72;
3516 lf.lfOrientation = lf.lfEscapement = 900;
3517 hfont = create_font("orientation", &lf);
3518 old_hfont = SelectObject(hdc, hfont);
3519 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3520 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3521 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3522 SelectObject(hdc, old_hfont);
3523 DeleteObject(hfont);
3524 DeleteDC(hdc);
3527 static void test_oemcharset(void)
3529 HDC hdc;
3530 LOGFONTA lf, clf;
3531 HFONT hfont, old_hfont;
3532 int charset;
3534 hdc = CreateCompatibleDC(0);
3535 ZeroMemory(&lf, sizeof(lf));
3536 lf.lfHeight = 12;
3537 lf.lfCharSet = OEM_CHARSET;
3538 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3539 lstrcpyA(lf.lfFaceName, "Terminal");
3540 hfont = CreateFontIndirectA(&lf);
3541 old_hfont = SelectObject(hdc, hfont);
3542 charset = GetTextCharset(hdc);
3543 todo_wine
3544 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3545 hfont = SelectObject(hdc, old_hfont);
3546 GetObjectA(hfont, sizeof(clf), &clf);
3547 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3548 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3549 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3550 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3551 DeleteObject(hfont);
3552 DeleteDC(hdc);
3555 static void test_GetGlyphOutline(void)
3557 HDC hdc;
3558 GLYPHMETRICS gm, gm2;
3559 LOGFONTA lf;
3560 HFONT hfont, old_hfont;
3561 INT ret, ret2;
3562 static const struct
3564 UINT cs;
3565 UINT a;
3566 UINT w;
3567 } c[] =
3569 {ANSI_CHARSET, 0x30, 0x30},
3570 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3571 {HANGEUL_CHARSET, 0x8141, 0xac02},
3572 {JOHAB_CHARSET, 0x8446, 0x3135},
3573 {GB2312_CHARSET, 0x8141, 0x4e04},
3574 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3576 UINT i;
3578 if (!is_truetype_font_installed("Tahoma"))
3580 skip("Tahoma is not installed\n");
3581 return;
3584 hdc = CreateCompatibleDC(0);
3585 memset(&lf, 0, sizeof(lf));
3586 lf.lfHeight = 72;
3587 lstrcpyA(lf.lfFaceName, "Tahoma");
3588 SetLastError(0xdeadbeef);
3589 hfont = CreateFontIndirectA(&lf);
3590 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3591 old_hfont = SelectObject(hdc, hfont);
3593 memset(&gm, 0, sizeof(gm));
3594 SetLastError(0xdeadbeef);
3595 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3596 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3598 memset(&gm, 0, sizeof(gm));
3599 SetLastError(0xdeadbeef);
3600 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3601 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3602 ok(GetLastError() == 0xdeadbeef ||
3603 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3604 "expected 0xdeadbeef, got %u\n", GetLastError());
3606 memset(&gm, 0, sizeof(gm));
3607 SetLastError(0xdeadbeef);
3608 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3609 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3610 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3612 memset(&gm, 0, sizeof(gm));
3613 SetLastError(0xdeadbeef);
3614 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3615 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3617 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3618 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3621 /* test for needed buffer size request on space char */
3622 memset(&gm, 0, sizeof(gm));
3623 SetLastError(0xdeadbeef);
3624 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3625 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3626 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3628 /* requesting buffer size for space char + error */
3629 memset(&gm, 0, sizeof(gm));
3630 SetLastError(0xdeadbeef);
3631 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3632 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3634 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3635 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3638 SelectObject(hdc, old_hfont);
3639 DeleteObject(hfont);
3641 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3643 lf.lfFaceName[0] = '\0';
3644 lf.lfCharSet = c[i].cs;
3645 lf.lfPitchAndFamily = 0;
3646 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3648 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3649 continue;
3652 old_hfont = SelectObject(hdc, hfont);
3654 /* expected to ignore superfluous bytes (sigle-byte character) */
3655 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3656 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3657 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3659 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3660 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3661 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3663 /* expected to ignore superfluous bytes (double-byte character) */
3664 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3665 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3666 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3667 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3669 /* expected to match wide-char version results */
3670 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3671 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3673 hfont = SelectObject(hdc, old_hfont);
3674 DeleteObject(hfont);
3677 DeleteDC(hdc);
3680 /* bug #9995: there is a limit to the character width that can be specified */
3681 static void test_GetTextMetrics2(const char *fontname, int font_height)
3683 HFONT of, hf;
3684 HDC hdc;
3685 TEXTMETRICA tm;
3686 BOOL ret;
3687 int ave_width, height, width, ratio, scale;
3689 if (!is_truetype_font_installed( fontname)) {
3690 skip("%s is not installed\n", fontname);
3691 return;
3693 hdc = CreateCompatibleDC(0);
3694 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3695 /* select width = 0 */
3696 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3697 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3698 DEFAULT_QUALITY, VARIABLE_PITCH,
3699 fontname);
3700 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3701 of = SelectObject( hdc, hf);
3702 ret = GetTextMetricsA( hdc, &tm);
3703 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3704 height = tm.tmHeight;
3705 ave_width = tm.tmAveCharWidth;
3706 SelectObject( hdc, of);
3707 DeleteObject( hf);
3709 trace("height %d, ave width %d\n", height, ave_width);
3711 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3713 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3714 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3715 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3716 ok(hf != 0, "CreateFont failed\n");
3717 of = SelectObject(hdc, hf);
3718 ret = GetTextMetrics(hdc, &tm);
3719 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3720 SelectObject(hdc, of);
3721 DeleteObject(hf);
3723 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3724 break;
3727 DeleteDC(hdc);
3729 ratio = width / height;
3730 scale = width / ave_width;
3732 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3733 width, height, ratio, width, ave_width, scale);
3735 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3738 static void test_CreateFontIndirect(void)
3740 LOGFONTA lf, getobj_lf;
3741 int ret, i;
3742 HFONT hfont;
3743 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3745 memset(&lf, 0, sizeof(lf));
3746 lf.lfCharSet = ANSI_CHARSET;
3747 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3748 lf.lfHeight = 16;
3749 lf.lfWidth = 16;
3750 lf.lfQuality = DEFAULT_QUALITY;
3751 lf.lfItalic = FALSE;
3752 lf.lfWeight = FW_DONTCARE;
3754 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3756 lstrcpyA(lf.lfFaceName, TestName[i]);
3757 hfont = CreateFontIndirectA(&lf);
3758 ok(hfont != 0, "CreateFontIndirectA failed\n");
3759 SetLastError(0xdeadbeef);
3760 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3761 ok(ret, "GetObject failed: %d\n", GetLastError());
3762 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3763 ok(lf.lfWeight == getobj_lf.lfWeight ||
3764 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3765 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3766 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3767 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3768 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3769 DeleteObject(hfont);
3773 static void test_CreateFontIndirectEx(void)
3775 ENUMLOGFONTEXDVA lfex;
3776 HFONT hfont;
3778 if (!pCreateFontIndirectExA)
3780 win_skip("CreateFontIndirectExA is not available\n");
3781 return;
3784 if (!is_truetype_font_installed("Arial"))
3786 skip("Arial is not installed\n");
3787 return;
3790 SetLastError(0xdeadbeef);
3791 hfont = pCreateFontIndirectExA(NULL);
3792 ok(hfont == NULL, "got %p\n", hfont);
3793 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3795 memset(&lfex, 0, sizeof(lfex));
3796 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3797 hfont = pCreateFontIndirectExA(&lfex);
3798 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3799 if (hfont)
3800 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3801 DeleteObject(hfont);
3804 static void free_font(void *font)
3806 UnmapViewOfFile(font);
3809 static void *load_font(const char *font_name, DWORD *font_size)
3811 char file_name[MAX_PATH];
3812 HANDLE file, mapping;
3813 void *font;
3815 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3816 strcat(file_name, "\\fonts\\");
3817 strcat(file_name, font_name);
3819 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3820 if (file == INVALID_HANDLE_VALUE) return NULL;
3822 *font_size = GetFileSize(file, NULL);
3824 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3825 if (!mapping)
3827 CloseHandle(file);
3828 return NULL;
3831 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3833 CloseHandle(file);
3834 CloseHandle(mapping);
3835 return font;
3838 static void test_AddFontMemResource(void)
3840 void *font;
3841 DWORD font_size, num_fonts;
3842 HANDLE ret;
3843 BOOL bRet;
3845 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3847 win_skip("AddFontMemResourceEx is not available on this platform\n");
3848 return;
3851 font = load_font("sserife.fon", &font_size);
3852 if (!font)
3854 skip("Unable to locate and load font sserife.fon\n");
3855 return;
3858 SetLastError(0xdeadbeef);
3859 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3860 ok(!ret, "AddFontMemResourceEx should fail\n");
3861 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3862 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3863 GetLastError());
3865 SetLastError(0xdeadbeef);
3866 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3867 ok(!ret, "AddFontMemResourceEx should fail\n");
3868 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3869 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3870 GetLastError());
3872 SetLastError(0xdeadbeef);
3873 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3874 ok(!ret, "AddFontMemResourceEx should fail\n");
3875 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3876 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3877 GetLastError());
3879 SetLastError(0xdeadbeef);
3880 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3881 ok(!ret, "AddFontMemResourceEx should fail\n");
3882 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3883 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3884 GetLastError());
3886 SetLastError(0xdeadbeef);
3887 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3888 ok(!ret, "AddFontMemResourceEx should fail\n");
3889 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3890 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3891 GetLastError());
3893 SetLastError(0xdeadbeef);
3894 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3895 ok(!ret, "AddFontMemResourceEx should fail\n");
3896 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3897 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3898 GetLastError());
3900 num_fonts = 0xdeadbeef;
3901 SetLastError(0xdeadbeef);
3902 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3903 ok(!ret, "AddFontMemResourceEx should fail\n");
3904 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3905 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3906 GetLastError());
3907 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3909 if (0) /* hangs under windows 2000 */
3911 num_fonts = 0xdeadbeef;
3912 SetLastError(0xdeadbeef);
3913 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3914 ok(!ret, "AddFontMemResourceEx should fail\n");
3915 ok(GetLastError() == 0xdeadbeef,
3916 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3917 GetLastError());
3918 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3921 num_fonts = 0xdeadbeef;
3922 SetLastError(0xdeadbeef);
3923 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3924 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3925 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3926 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3928 free_font(font);
3930 SetLastError(0xdeadbeef);
3931 bRet = pRemoveFontMemResourceEx(ret);
3932 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3934 /* test invalid pointer to number of loaded fonts */
3935 font = load_font("sserife.fon", &font_size);
3936 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3938 SetLastError(0xdeadbeef);
3939 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3940 ok(!ret, "AddFontMemResourceEx should fail\n");
3941 ok(GetLastError() == 0xdeadbeef,
3942 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3943 GetLastError());
3945 SetLastError(0xdeadbeef);
3946 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3947 ok(!ret, "AddFontMemResourceEx should fail\n");
3948 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3949 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3950 GetLastError());
3952 free_font(font);
3955 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3957 LOGFONT *lf;
3959 if (type != TRUETYPE_FONTTYPE) return 1;
3961 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3963 lf = (LOGFONT *)lparam;
3964 *lf = *elf;
3965 return 0;
3968 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3970 int ret;
3971 LOGFONT *lf;
3973 if (type != TRUETYPE_FONTTYPE) return 1;
3975 lf = (LOGFONT *)lparam;
3976 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3977 if(ret == 0)
3979 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3980 *lf = *elf;
3981 return 0;
3983 return 1;
3986 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3988 return lparam;
3991 static void test_EnumFonts(void)
3993 int ret;
3994 LOGFONT lf;
3995 HDC hdc;
3997 if (!is_truetype_font_installed("Arial"))
3999 skip("Arial is not installed\n");
4000 return;
4003 /* Windows uses localized font face names, so Arial Bold won't be found */
4004 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4006 skip("User locale is not English, skipping the test\n");
4007 return;
4010 hdc = CreateCompatibleDC(0);
4012 /* check that the enumproc's retval is returned */
4013 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4014 ok(ret == 0xcafe, "got %08x\n", ret);
4016 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4017 ok(!ret, "font Arial is not enumerated\n");
4018 ret = strcmp(lf.lfFaceName, "Arial");
4019 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4020 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4022 lstrcpy(lf.lfFaceName, "Arial");
4023 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4024 ok(!ret, "font Arial is not enumerated\n");
4025 ret = strcmp(lf.lfFaceName, "Arial");
4026 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4027 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4029 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4030 ok(!ret, "font Arial Bold is not enumerated\n");
4031 ret = strcmp(lf.lfFaceName, "Arial");
4032 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4033 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4035 lstrcpy(lf.lfFaceName, "Arial Bold");
4036 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4037 ok(ret, "font Arial Bold should not be enumerated\n");
4039 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4040 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4041 ret = strcmp(lf.lfFaceName, "Arial");
4042 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4043 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4045 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
4046 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4047 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4049 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4050 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4052 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
4053 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4054 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4056 DeleteDC(hdc);
4059 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
4061 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
4062 const char *fullname = (const char *)lParam;
4064 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4066 return 1;
4069 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4071 HDC hdc = GetDC(0);
4072 BOOL ret = FALSE;
4074 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4075 ret = TRUE;
4077 ReleaseDC(0, hdc);
4078 return ret;
4081 static void test_fullname(void)
4083 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4084 WCHAR bufW[LF_FULLFACESIZE];
4085 char bufA[LF_FULLFACESIZE];
4086 HFONT hfont, of;
4087 LOGFONTA lf;
4088 HDC hdc;
4089 int i;
4090 DWORD ret;
4092 hdc = CreateCompatibleDC(0);
4093 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4095 memset(&lf, 0, sizeof(lf));
4096 lf.lfCharSet = ANSI_CHARSET;
4097 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4098 lf.lfHeight = 16;
4099 lf.lfWidth = 16;
4100 lf.lfQuality = DEFAULT_QUALITY;
4101 lf.lfItalic = FALSE;
4102 lf.lfWeight = FW_DONTCARE;
4104 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4106 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4108 skip("%s is not installed\n", TestName[i]);
4109 continue;
4112 lstrcpyA(lf.lfFaceName, TestName[i]);
4113 hfont = CreateFontIndirectA(&lf);
4114 ok(hfont != 0, "CreateFontIndirectA failed\n");
4116 of = SelectObject(hdc, hfont);
4117 bufW[0] = 0;
4118 bufA[0] = 0;
4119 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4120 ok(ret, "face full name could not be read\n");
4121 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4122 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4123 SelectObject(hdc, of);
4124 DeleteObject(hfont);
4126 DeleteDC(hdc);
4129 static WCHAR *prepend_at(WCHAR *family)
4131 if (!family)
4132 return NULL;
4134 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4135 family[0] = '@';
4136 return family;
4139 static void test_fullname2_helper(const char *Family)
4141 char *FamilyName, *FaceName, *StyleName, *otmStr;
4142 struct enum_fullname_data efnd;
4143 WCHAR *bufW;
4144 char *bufA;
4145 HFONT hfont, of;
4146 LOGFONTA lf;
4147 HDC hdc;
4148 int i;
4149 DWORD otm_size, ret, buf_size;
4150 OUTLINETEXTMETRICA *otm;
4151 BOOL want_vertical, get_vertical;
4152 want_vertical = ( Family[0] == '@' );
4154 hdc = CreateCompatibleDC(0);
4155 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4157 memset(&lf, 0, sizeof(lf));
4158 lf.lfCharSet = DEFAULT_CHARSET;
4159 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4160 lf.lfHeight = 16;
4161 lf.lfWidth = 16;
4162 lf.lfQuality = DEFAULT_QUALITY;
4163 lf.lfItalic = FALSE;
4164 lf.lfWeight = FW_DONTCARE;
4165 lstrcpy(lf.lfFaceName, Family);
4166 efnd.total = 0;
4167 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4168 if (efnd.total == 0)
4169 skip("%s is not installed\n", lf.lfFaceName);
4171 for (i = 0; i < efnd.total; i++)
4173 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4174 FaceName = (char *)efnd.elf[i].elfFullName;
4175 StyleName = (char *)efnd.elf[i].elfStyle;
4177 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4179 get_vertical = ( FamilyName[0] == '@' );
4180 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4182 lstrcpyA(lf.lfFaceName, FaceName);
4183 hfont = CreateFontIndirectA(&lf);
4184 ok(hfont != 0, "CreateFontIndirectA failed\n");
4186 of = SelectObject(hdc, hfont);
4187 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4188 ok(buf_size != GDI_ERROR, "no name table found\n");
4189 if (buf_size == GDI_ERROR) continue;
4191 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4192 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4194 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4195 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4196 memset(otm, 0, otm_size);
4197 ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4198 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4199 if (ret == 0) continue;
4201 bufW[0] = 0;
4202 bufA[0] = 0;
4203 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4204 if (!ret)
4206 trace("no localized FONT_FAMILY found.\n");
4207 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4209 ok(ret, "FAMILY (family name) could not be read\n");
4210 if (want_vertical) bufW = prepend_at(bufW);
4211 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4212 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4213 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4214 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4216 bufW[0] = 0;
4217 bufA[0] = 0;
4218 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4219 if (!ret)
4221 trace("no localized FULL_NAME found.\n");
4222 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4224 ok(ret, "FULL_NAME (face name) could not be read\n");
4225 if (want_vertical) bufW = prepend_at(bufW);
4226 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4227 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4228 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4229 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4231 bufW[0] = 0;
4232 bufA[0] = 0;
4233 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4234 if (!ret)
4236 trace("no localized FONT_SUBFAMILY found.\n");
4237 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4239 ok(ret, "SUBFAMILY (style name) could not be read\n");
4240 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4241 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4242 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4243 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4245 bufW[0] = 0;
4246 bufA[0] = 0;
4247 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4248 if (!ret)
4250 trace("no localized UNIQUE_ID found.\n");
4251 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4253 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4254 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4255 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4256 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4258 SelectObject(hdc, of);
4259 DeleteObject(hfont);
4261 HeapFree(GetProcessHeap(), 0, otm);
4262 HeapFree(GetProcessHeap(), 0, bufW);
4263 HeapFree(GetProcessHeap(), 0, bufA);
4265 DeleteDC(hdc);
4268 static void test_fullname2(void)
4270 test_fullname2_helper("Arial");
4271 test_fullname2_helper("DejaVu Sans");
4272 test_fullname2_helper("Lucida Sans");
4273 test_fullname2_helper("Tahoma");
4274 test_fullname2_helper("Webdings");
4275 test_fullname2_helper("Wingdings");
4276 test_fullname2_helper("SimSun");
4277 test_fullname2_helper("NSimSun");
4278 test_fullname2_helper("MingLiu");
4279 test_fullname2_helper("PMingLiu");
4280 test_fullname2_helper("WenQuanYi Micro Hei");
4281 test_fullname2_helper("MS UI Gothic");
4282 test_fullname2_helper("Ume UI Gothic");
4283 test_fullname2_helper("MS Gothic");
4284 test_fullname2_helper("Ume Gothic");
4285 test_fullname2_helper("MS PGothic");
4286 test_fullname2_helper("Ume P Gothic");
4287 test_fullname2_helper("Gulim");
4288 test_fullname2_helper("Batang");
4289 test_fullname2_helper("UnBatang");
4290 test_fullname2_helper("UnDotum");
4291 test_fullname2_helper("@SimSun");
4292 test_fullname2_helper("@NSimSun");
4293 test_fullname2_helper("@MingLiu");
4294 test_fullname2_helper("@PMingLiu");
4295 test_fullname2_helper("@WenQuanYi Micro Hei");
4296 test_fullname2_helper("@MS UI Gothic");
4297 test_fullname2_helper("@Ume UI Gothic");
4298 test_fullname2_helper("@MS Gothic");
4299 test_fullname2_helper("@Ume Gothic");
4300 test_fullname2_helper("@MS PGothic");
4301 test_fullname2_helper("@Ume P Gothic");
4302 test_fullname2_helper("@Gulim");
4303 test_fullname2_helper("@Batang");
4304 test_fullname2_helper("@UnBatang");
4305 test_fullname2_helper("@UnDotum");
4309 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4311 char tmp_path[MAX_PATH];
4312 HRSRC rsrc;
4313 void *rsrc_data;
4314 DWORD rsrc_size;
4315 HANDLE hfile;
4316 BOOL ret;
4318 SetLastError(0xdeadbeef);
4319 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4320 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4321 if (!rsrc) return FALSE;
4322 SetLastError(0xdeadbeef);
4323 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4324 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4325 if (!rsrc_data) return FALSE;
4326 SetLastError(0xdeadbeef);
4327 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4328 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4329 if (!rsrc_size) return FALSE;
4331 SetLastError(0xdeadbeef);
4332 ret = GetTempPath(MAX_PATH, tmp_path);
4333 ok(ret, "GetTempPath() error %d\n", GetLastError());
4334 SetLastError(0xdeadbeef);
4335 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4336 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4338 SetLastError(0xdeadbeef);
4339 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4340 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4341 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4343 SetLastError(0xdeadbeef);
4344 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4345 ok(ret, "WriteFile() error %d\n", GetLastError());
4347 CloseHandle(hfile);
4348 return ret;
4351 static void test_GetGlyphOutline_empty_contour(void)
4353 HDC hdc;
4354 LOGFONTA lf;
4355 HFONT hfont, hfont_prev;
4356 TTPOLYGONHEADER *header;
4357 GLYPHMETRICS gm;
4358 char buf[1024];
4359 DWORD ret;
4361 memset(&lf, 0, sizeof(lf));
4362 lf.lfHeight = 72;
4363 lstrcpyA(lf.lfFaceName, "wine_test");
4365 hfont = CreateFontIndirectA(&lf);
4366 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4368 hdc = GetDC(NULL);
4370 hfont_prev = SelectObject(hdc, hfont);
4371 ok(hfont_prev != NULL, "SelectObject failed\n");
4373 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
4374 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4376 header = (TTPOLYGONHEADER*)buf;
4377 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
4378 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4379 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
4380 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
4381 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4382 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4383 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4384 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4386 SelectObject(hdc, hfont_prev);
4387 DeleteObject(hfont);
4388 ReleaseDC(NULL, hdc);
4391 static void test_CreateScalableFontResource(void)
4393 char ttf_name[MAX_PATH];
4394 char tmp_path[MAX_PATH];
4395 char fot_name[MAX_PATH];
4396 char *file_part;
4397 DWORD ret;
4399 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4401 win_skip("AddFontResourceExA is not available on this platform\n");
4402 return;
4405 if (!write_ttf_file("wine_test.ttf", ttf_name))
4407 skip("Failed to create ttf file for testing\n");
4408 return;
4411 trace("created %s\n", ttf_name);
4413 ret = is_truetype_font_installed("wine_test");
4414 ok(!ret, "font wine_test should not be enumerated\n");
4416 ret = GetTempPath(MAX_PATH, tmp_path);
4417 ok(ret, "GetTempPath() error %d\n", GetLastError());
4418 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4419 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4421 ret = GetFileAttributes(fot_name);
4422 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4424 SetLastError(0xdeadbeef);
4425 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4426 ok(!ret, "CreateScalableFontResource() should fail\n");
4427 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4429 SetLastError(0xdeadbeef);
4430 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4431 ok(!ret, "CreateScalableFontResource() should fail\n");
4432 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4434 file_part = strrchr(ttf_name, '\\');
4435 SetLastError(0xdeadbeef);
4436 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4437 ok(!ret, "CreateScalableFontResource() should fail\n");
4438 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4440 SetLastError(0xdeadbeef);
4441 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4442 ok(!ret, "CreateScalableFontResource() should fail\n");
4443 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4445 SetLastError(0xdeadbeef);
4446 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4447 ok(!ret, "CreateScalableFontResource() should fail\n");
4448 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4450 ret = DeleteFile(fot_name);
4451 ok(ret, "DeleteFile() error %d\n", GetLastError());
4453 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4454 todo_wine
4455 ok(!ret, "RemoveFontResourceEx() should fail\n");
4457 /* test public font resource */
4458 SetLastError(0xdeadbeef);
4459 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4460 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4462 ret = is_truetype_font_installed("wine_test");
4463 ok(!ret, "font wine_test should not be enumerated\n");
4465 SetLastError(0xdeadbeef);
4466 ret = pAddFontResourceExA(fot_name, 0, 0);
4467 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4469 ret = is_truetype_font_installed("wine_test");
4470 ok(ret, "font wine_test should be enumerated\n");
4472 test_GetGlyphOutline_empty_contour();
4474 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4475 todo_wine
4476 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4478 SetLastError(0xdeadbeef);
4479 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4480 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4482 ret = is_truetype_font_installed("wine_test");
4483 todo_wine
4484 ok(!ret, "font wine_test should not be enumerated\n");
4486 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4487 if (ret)
4489 /* remove once RemoveFontResource is implemented */
4490 DeleteFile(fot_name);
4491 DeleteFile(ttf_name);
4492 return;
4495 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4496 ok(!ret, "RemoveFontResourceEx() should fail\n");
4498 DeleteFile(fot_name);
4500 /* test hidden font resource */
4501 SetLastError(0xdeadbeef);
4502 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4503 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4505 ret = is_truetype_font_installed("wine_test");
4506 ok(!ret, "font wine_test should not be enumerated\n");
4508 SetLastError(0xdeadbeef);
4509 ret = pAddFontResourceExA(fot_name, 0, 0);
4510 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4512 ret = is_truetype_font_installed("wine_test");
4513 ok(!ret, "font wine_test should not be enumerated\n");
4515 /* XP allows removing a private font added with 0 flags */
4516 SetLastError(0xdeadbeef);
4517 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4518 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4520 ret = is_truetype_font_installed("wine_test");
4521 ok(!ret, "font wine_test should not be enumerated\n");
4523 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4524 ok(!ret, "RemoveFontResourceEx() should fail\n");
4526 DeleteFile(fot_name);
4527 DeleteFile(ttf_name);
4530 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4532 LOGFONTA lf;
4533 HFONT hfont, hfont_prev;
4534 HDC hdc;
4535 char facename[100];
4536 DWORD ret;
4537 static const WCHAR str[] = { 0x2025 };
4539 *installed = is_truetype_font_installed(name);
4541 lf.lfHeight = -18;
4542 lf.lfWidth = 0;
4543 lf.lfEscapement = 0;
4544 lf.lfOrientation = 0;
4545 lf.lfWeight = FW_DONTCARE;
4546 lf.lfItalic = 0;
4547 lf.lfUnderline = 0;
4548 lf.lfStrikeOut = 0;
4549 lf.lfCharSet = DEFAULT_CHARSET;
4550 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4551 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4552 lf.lfQuality = DEFAULT_QUALITY;
4553 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4554 strcpy(lf.lfFaceName, name);
4556 hfont = CreateFontIndirectA(&lf);
4557 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4559 hdc = GetDC(NULL);
4561 hfont_prev = SelectObject(hdc, hfont);
4562 ok(hfont_prev != NULL, "SelectObject failed\n");
4564 ret = GetTextFaceA(hdc, sizeof facename, facename);
4565 ok(ret, "GetTextFaceA failed\n");
4566 *selected = !strcmp(facename, name);
4568 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4569 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4570 if (!*selected)
4571 memset(gm, 0, sizeof *gm);
4573 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4574 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4576 SelectObject(hdc, hfont_prev);
4577 DeleteObject(hfont);
4578 ReleaseDC(NULL, hdc);
4581 static void test_vertical_font(void)
4583 char ttf_name[MAX_PATH];
4584 int num;
4585 BOOL ret, installed, selected;
4586 GLYPHMETRICS gm;
4587 WORD hgi, vgi;
4589 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4591 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4592 return;
4595 if (!write_ttf_file("vertical.ttf", ttf_name))
4597 skip("Failed to create ttf file for testing\n");
4598 return;
4601 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4602 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4604 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4605 ok(installed, "@WineTestVertical is not installed\n");
4606 ok(selected, "@WineTestVertical is not selected\n");
4607 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4608 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4609 gm.gmBlackBoxX, gm.gmBlackBoxY);
4611 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4612 ok(installed, "@@WineTestVertical is not installed\n");
4613 ok(selected, "@@WineTestVertical is not selected\n");
4614 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4615 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4616 gm.gmBlackBoxX, gm.gmBlackBoxY);
4618 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4620 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4621 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4623 DeleteFile(ttf_name);
4626 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4627 DWORD type, LPARAM lParam)
4629 if (lf->lfFaceName[0] == '@') {
4630 return 0;
4632 return 1;
4635 static void test_east_asian_font_selection(void)
4637 HDC hdc;
4638 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4639 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4640 size_t i;
4642 hdc = GetDC(NULL);
4644 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4646 LOGFONTA lf;
4647 HFONT hfont;
4648 char face_name[LF_FACESIZE];
4649 int ret;
4651 memset(&lf, 0, sizeof lf);
4652 lf.lfFaceName[0] = '\0';
4653 lf.lfCharSet = charset[i];
4655 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4657 skip("Vertical font for charset %u is not installed\n", charset[i]);
4658 continue;
4661 hfont = CreateFontIndirectA(&lf);
4662 hfont = SelectObject(hdc, hfont);
4663 memset(face_name, 0, sizeof face_name);
4664 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4665 ok(ret && face_name[0] != '@',
4666 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4667 DeleteObject(SelectObject(hdc, hfont));
4669 memset(&lf, 0, sizeof lf);
4670 strcpy(lf.lfFaceName, "@");
4671 lf.lfCharSet = charset[i];
4672 hfont = CreateFontIndirectA(&lf);
4673 hfont = SelectObject(hdc, hfont);
4674 memset(face_name, 0, sizeof face_name);
4675 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4676 ok(ret && face_name[0] == '@',
4677 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4678 DeleteObject(SelectObject(hdc, hfont));
4680 ReleaseDC(NULL, hdc);
4683 static int get_font_dpi(const LOGFONT *lf)
4685 HDC hdc = CreateCompatibleDC(0);
4686 HFONT hfont;
4687 TEXTMETRIC tm;
4688 int ret;
4690 hfont = CreateFontIndirect(lf);
4691 ok(hfont != 0, "CreateFontIndirect failed\n");
4693 SelectObject(hdc, hfont);
4694 ret = GetTextMetrics(hdc, &tm);
4695 ok(ret, "GetTextMetrics failed\n");
4696 ret = tm.tmDigitizedAspectX;
4698 DeleteDC(hdc);
4699 DeleteObject(hfont);
4701 return ret;
4704 static void test_stock_fonts(void)
4706 static const int font[] =
4708 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4709 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4711 static const struct test_data
4713 int charset, weight, height, dpi;
4714 const char face_name[LF_FACESIZE];
4715 } td[][11] =
4717 { /* ANSI_FIXED_FONT */
4718 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4719 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4720 { 0 }
4722 { /* ANSI_VAR_FONT */
4723 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4724 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4725 { 0 }
4727 { /* SYSTEM_FONT */
4728 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4729 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4730 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4731 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4732 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4733 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4734 { 0 }
4736 { /* DEVICE_DEFAULT_FONT */
4737 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4738 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4739 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4740 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4741 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4742 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4743 { 0 }
4745 { /* DEFAULT_GUI_FONT */
4746 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4747 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4748 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4749 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4750 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4751 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4752 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4753 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4754 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4755 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4756 { 0 }
4759 int i, j;
4761 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4763 HFONT hfont;
4764 LOGFONT lf;
4765 int ret;
4767 hfont = GetStockObject(font[i]);
4768 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4770 ret = GetObject(hfont, sizeof(lf), &lf);
4771 if (ret != sizeof(lf))
4773 /* NT4 */
4774 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4775 continue;
4778 for (j = 0; td[i][j].face_name[0] != 0; j++)
4780 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4782 continue;
4785 ret = get_font_dpi(&lf);
4786 if (ret != td[i][j].dpi)
4788 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4789 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4790 continue;
4793 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4794 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4795 if (td[i][j].face_name[0] == '?')
4797 /* Wine doesn't have this font, skip this case for now.
4798 Actually, the face name is localized on Windows and varies
4799 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4800 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4802 else
4804 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);
4806 break;
4811 START_TEST(font)
4813 init();
4815 test_stock_fonts();
4816 test_logfont();
4817 test_bitmap_font();
4818 test_outline_font();
4819 test_bitmap_font_metrics();
4820 test_GdiGetCharDimensions();
4821 test_GetCharABCWidths();
4822 test_text_extents();
4823 test_GetGlyphIndices();
4824 test_GetKerningPairs();
4825 test_GetOutlineTextMetrics();
4826 test_SetTextJustification();
4827 test_font_charset();
4828 test_GetFontUnicodeRanges();
4829 test_nonexistent_font();
4830 test_orientation();
4831 test_height_selection();
4832 test_AddFontMemResource();
4833 test_EnumFonts();
4835 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4836 * I'd like to avoid them in this test.
4838 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4839 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4840 if (is_truetype_font_installed("Arial Black") &&
4841 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4843 test_EnumFontFamilies("", ANSI_CHARSET);
4844 test_EnumFontFamilies("", SYMBOL_CHARSET);
4845 test_EnumFontFamilies("", DEFAULT_CHARSET);
4847 else
4848 skip("Arial Black or Symbol/Wingdings is not installed\n");
4849 test_EnumFontFamiliesEx_default_charset();
4850 test_GetTextMetrics();
4851 test_GdiRealizationInfo();
4852 test_GetTextFace();
4853 test_GetGlyphOutline();
4854 test_GetTextMetrics2("Tahoma", -11);
4855 test_GetTextMetrics2("Tahoma", -55);
4856 test_GetTextMetrics2("Tahoma", -110);
4857 test_GetTextMetrics2("Arial", -11);
4858 test_GetTextMetrics2("Arial", -55);
4859 test_GetTextMetrics2("Arial", -110);
4860 test_CreateFontIndirect();
4861 test_CreateFontIndirectEx();
4862 test_oemcharset();
4863 test_fullname();
4864 test_fullname2();
4865 test_east_asian_font_selection();
4867 /* These tests should be last test until RemoveFontResource
4868 * is properly implemented.
4870 test_vertical_font();
4871 test_CreateScalableFontResource();