gdi32/tests: Make GetStockObject tests pass on East-Asian machines.
[wine/multimedia.git] / dlls / gdi32 / tests / font.c
blob218b98067f4def0b51d8717ef97e1570e07c4ebb
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 *pGdiRealizationInfo)(HDC hdc, DWORD *);
49 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
50 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
51 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
53 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
55 static HMODULE hgdi32 = 0;
56 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
58 static void init(void)
60 hgdi32 = GetModuleHandleA("gdi32.dll");
62 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
63 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
64 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
65 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
66 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
67 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
68 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
69 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
70 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
71 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
72 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
73 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
74 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
75 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
76 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
79 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
81 if (type != TRUETYPE_FONTTYPE) return 1;
83 return 0;
86 static BOOL is_truetype_font_installed(const char *name)
88 HDC hdc = GetDC(0);
89 BOOL ret = FALSE;
91 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
92 ret = TRUE;
94 ReleaseDC(0, hdc);
95 return ret;
98 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
100 return 0;
103 static BOOL is_font_installed(const char *name)
105 HDC hdc = GetDC(0);
106 BOOL ret = FALSE;
108 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
109 ret = TRUE;
111 ReleaseDC(0, hdc);
112 return ret;
115 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
117 LOGFONTA getobj_lf;
118 int ret, minlen = 0;
120 if (!hfont)
121 return;
123 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
124 /* NT4 tries to be clever and only returns the minimum length */
125 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
126 minlen++;
127 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
128 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
129 ok(lf->lfHeight == getobj_lf.lfHeight ||
130 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
131 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
132 ok(lf->lfWidth == getobj_lf.lfWidth ||
133 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
134 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
135 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
136 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
137 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
138 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
139 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
140 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
141 ok(lf->lfWeight == getobj_lf.lfWeight ||
142 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
143 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
144 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
145 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
146 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
147 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
148 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
149 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
150 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
151 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
152 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
153 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
154 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
157 static HFONT create_font(const char* test, const LOGFONTA* lf)
159 HFONT hfont = CreateFontIndirectA(lf);
160 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
161 if (hfont)
162 check_font(test, lf, hfont);
163 return hfont;
166 static void test_logfont(void)
168 LOGFONTA lf;
169 HFONT hfont;
171 memset(&lf, 0, sizeof lf);
173 lf.lfCharSet = ANSI_CHARSET;
174 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
175 lf.lfWeight = FW_DONTCARE;
176 lf.lfHeight = 16;
177 lf.lfWidth = 16;
178 lf.lfQuality = DEFAULT_QUALITY;
180 lstrcpyA(lf.lfFaceName, "Arial");
181 hfont = create_font("Arial", &lf);
182 DeleteObject(hfont);
184 memset(&lf, 'A', sizeof(lf));
185 hfont = CreateFontIndirectA(&lf);
186 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
188 lf.lfFaceName[LF_FACESIZE - 1] = 0;
189 check_font("AAA...", &lf, hfont);
190 DeleteObject(hfont);
193 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
195 if (type & RASTER_FONTTYPE)
197 LOGFONT *lf = (LOGFONT *)lParam;
198 *lf = *elf;
199 return 0; /* stop enumeration */
202 return 1; /* continue enumeration */
205 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
207 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
208 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
209 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
210 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
211 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
212 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
213 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
214 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
215 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
216 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
217 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
218 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
219 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
220 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
221 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
222 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
223 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
224 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
225 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
226 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
229 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
230 LONG lfWidth, const char *test_str,
231 INT test_str_len, const TEXTMETRICA *tm_orig,
232 const SIZE *size_orig, INT width_of_A_orig,
233 INT scale_x, INT scale_y)
235 LOGFONTA lf;
236 OUTLINETEXTMETRIC otm;
237 TEXTMETRICA tm;
238 SIZE size;
239 INT width_of_A, cx, cy;
240 UINT ret;
242 if (!hfont)
243 return;
245 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
247 GetObjectA(hfont, sizeof(lf), &lf);
249 if (GetOutlineTextMetricsA(hdc, 0, NULL))
251 otm.otmSize = sizeof(otm) / 2;
252 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253 ok(ret == sizeof(otm)/2 /* XP */ ||
254 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
256 memset(&otm, 0x1, sizeof(otm));
257 otm.otmSize = sizeof(otm);
258 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259 ok(ret == sizeof(otm) /* XP */ ||
260 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
262 memset(&tm, 0x2, sizeof(tm));
263 ret = GetTextMetricsA(hdc, &tm);
264 ok(ret, "GetTextMetricsA failed\n");
265 /* the structure size is aligned */
266 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
268 ok(0, "tm != otm\n");
269 compare_tm(&tm, &otm.otmTextMetrics);
272 tm = otm.otmTextMetrics;
273 if (0) /* these metrics are scaled too, but with rounding errors */
275 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
276 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
278 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
279 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
280 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
281 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
282 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
283 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
285 else
287 ret = GetTextMetricsA(hdc, &tm);
288 ok(ret, "GetTextMetricsA failed\n");
291 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
292 cy = tm.tmHeight / tm_orig->tmHeight;
293 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
294 lfHeight, scale_x, scale_y, cx, cy);
295 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
296 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
297 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
298 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
299 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
301 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
302 if (lf.lfHeight)
304 if (lf.lfWidth)
305 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
307 else
308 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
310 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
312 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
313 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
315 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
317 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);
320 /* Test how GDI scales bitmap font metrics */
321 static void test_bitmap_font(void)
323 static const char test_str[11] = "Test String";
324 HDC hdc;
325 LOGFONTA bitmap_lf;
326 HFONT hfont, old_hfont;
327 TEXTMETRICA tm_orig;
328 SIZE size_orig;
329 INT ret, i, width_orig, height_orig, scale, lfWidth;
331 hdc = CreateCompatibleDC(0);
333 /* "System" has only 1 pixel size defined, otherwise the test breaks */
334 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
335 if (ret)
337 ReleaseDC(0, hdc);
338 trace("no bitmap fonts were found, skipping the test\n");
339 return;
342 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
344 height_orig = bitmap_lf.lfHeight;
345 lfWidth = bitmap_lf.lfWidth;
347 hfont = create_font("bitmap", &bitmap_lf);
348 old_hfont = SelectObject(hdc, hfont);
349 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
350 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
351 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
352 SelectObject(hdc, old_hfont);
353 DeleteObject(hfont);
355 bitmap_lf.lfHeight = 0;
356 bitmap_lf.lfWidth = 4;
357 hfont = create_font("bitmap", &bitmap_lf);
358 old_hfont = SelectObject(hdc, hfont);
359 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
360 SelectObject(hdc, old_hfont);
361 DeleteObject(hfont);
363 bitmap_lf.lfHeight = height_orig;
364 bitmap_lf.lfWidth = lfWidth;
366 /* test fractional scaling */
367 for (i = 1; i <= height_orig * 6; i++)
369 INT nearest_height;
371 bitmap_lf.lfHeight = i;
372 hfont = create_font("fractional", &bitmap_lf);
373 scale = (i + height_orig - 1) / height_orig;
374 nearest_height = scale * height_orig;
375 /* Only jump to the next height if the difference <= 25% original height */
376 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
377 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
378 so we'll not test this particular height. */
379 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
380 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
381 old_hfont = SelectObject(hdc, hfont);
382 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
383 SelectObject(hdc, old_hfont);
384 DeleteObject(hfont);
387 /* test integer scaling 3x2 */
388 bitmap_lf.lfHeight = height_orig * 2;
389 bitmap_lf.lfWidth *= 3;
390 hfont = create_font("3x2", &bitmap_lf);
391 old_hfont = SelectObject(hdc, hfont);
392 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
393 SelectObject(hdc, old_hfont);
394 DeleteObject(hfont);
396 /* test integer scaling 3x3 */
397 bitmap_lf.lfHeight = height_orig * 3;
398 bitmap_lf.lfWidth = 0;
399 hfont = create_font("3x3", &bitmap_lf);
400 old_hfont = SelectObject(hdc, hfont);
401 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
402 SelectObject(hdc, old_hfont);
403 DeleteObject(hfont);
405 DeleteDC(hdc);
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
411 static const char test_str[11] = "Test String";
412 HDC hdc, hdc_2;
413 LOGFONTA lf;
414 HFONT hfont, old_hfont, old_hfont_2;
415 OUTLINETEXTMETRICA otm;
416 SIZE size_orig;
417 INT width_orig, height_orig, lfWidth;
418 XFORM xform;
419 GLYPHMETRICS gm;
420 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
421 POINT pt;
422 INT ret;
424 if (!is_truetype_font_installed("Arial"))
426 skip("Arial is not installed\n");
427 return;
430 hdc = CreateCompatibleDC(0);
432 memset(&lf, 0, sizeof(lf));
433 strcpy(lf.lfFaceName, "Arial");
434 lf.lfHeight = 72;
435 hfont = create_font("outline", &lf);
436 old_hfont = SelectObject(hdc, hfont);
437 otm.otmSize = sizeof(otm);
438 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
442 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
443 SelectObject(hdc, old_hfont);
444 DeleteObject(hfont);
446 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
447 lf.lfHeight = otm.otmEMSquare;
448 lf.lfHeight = -lf.lfHeight;
449 hfont = create_font("outline", &lf);
450 old_hfont = SelectObject(hdc, hfont);
451 otm.otmSize = sizeof(otm);
452 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
453 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
454 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
455 SelectObject(hdc, old_hfont);
456 DeleteObject(hfont);
458 height_orig = otm.otmTextMetrics.tmHeight;
459 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
461 /* test integer scaling 3x2 */
462 lf.lfHeight = height_orig * 2;
463 lf.lfWidth = lfWidth * 3;
464 hfont = create_font("3x2", &lf);
465 old_hfont = SelectObject(hdc, hfont);
466 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
467 SelectObject(hdc, old_hfont);
468 DeleteObject(hfont);
470 /* test integer scaling 3x3 */
471 lf.lfHeight = height_orig * 3;
472 lf.lfWidth = lfWidth * 3;
473 hfont = create_font("3x3", &lf);
474 old_hfont = SelectObject(hdc, hfont);
475 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
476 SelectObject(hdc, old_hfont);
477 DeleteObject(hfont);
479 /* test integer scaling 1x1 */
480 lf.lfHeight = height_orig * 1;
481 lf.lfWidth = lfWidth * 1;
482 hfont = create_font("1x1", &lf);
483 old_hfont = SelectObject(hdc, hfont);
484 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 SelectObject(hdc, old_hfont);
486 DeleteObject(hfont);
488 /* test integer scaling 1x1 */
489 lf.lfHeight = height_orig;
490 lf.lfWidth = 0;
491 hfont = create_font("1x1", &lf);
492 old_hfont = SelectObject(hdc, hfont);
493 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
495 /* with an identity matrix */
496 memset(&gm, 0, sizeof(gm));
497 SetLastError(0xdeadbeef);
498 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
499 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
500 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
501 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
502 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
503 /* with a custom matrix */
504 memset(&gm, 0, sizeof(gm));
505 SetLastError(0xdeadbeef);
506 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
507 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
508 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
509 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
510 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
512 /* Test that changing the DC transformation affects only the font
513 * selected on this DC and doesn't affect the same font selected on
514 * another DC.
516 hdc_2 = CreateCompatibleDC(0);
517 old_hfont_2 = SelectObject(hdc_2, hfont);
518 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
520 SetMapMode(hdc, MM_ANISOTROPIC);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* test restrictions of compatibility mode GM_COMPATIBLE */
526 /* part 1: rescaling only X should not change font scaling on screen.
527 So compressing the X axis by 2 is not done, and this
528 appears as X scaling of 2 that no one requested. */
529 SetWindowExtEx(hdc, 100, 100, NULL);
530 SetViewportExtEx(hdc, 50, 100, NULL);
531 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
532 /* font metrics on another DC should be unchanged */
533 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
535 /* part 2: rescaling only Y should change font scaling.
536 As also X is scaled by a factor of 2, but this is not
537 requested by the DC transformation, we get a scaling factor
538 of 2 in the X coordinate. */
539 SetViewportExtEx(hdc, 100, 200, NULL);
540 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
541 /* font metrics on another DC should be unchanged */
542 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
544 /* restore scaling */
545 SetMapMode(hdc, MM_TEXT);
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 SelectObject(hdc_2, old_hfont_2);
551 DeleteDC(hdc_2);
553 if (!SetGraphicsMode(hdc, GM_ADVANCED))
555 SelectObject(hdc, old_hfont);
556 DeleteObject(hfont);
557 DeleteDC(hdc);
558 skip("GM_ADVANCED is not supported on this platform\n");
559 return;
562 xform.eM11 = 20.0f;
563 xform.eM12 = 0.0f;
564 xform.eM21 = 0.0f;
565 xform.eM22 = 20.0f;
566 xform.eDx = 0.0f;
567 xform.eDy = 0.0f;
569 SetLastError(0xdeadbeef);
570 ret = SetWorldTransform(hdc, &xform);
571 ok(ret, "SetWorldTransform error %u\n", GetLastError());
573 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
575 /* with an identity matrix */
576 memset(&gm, 0, sizeof(gm));
577 SetLastError(0xdeadbeef);
578 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581 pt.x = width_orig; pt.y = 0;
582 LPtoDP(hdc, &pt, 1);
583 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
584 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
585 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
586 /* with a custom matrix */
587 memset(&gm, 0, sizeof(gm));
588 SetLastError(0xdeadbeef);
589 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
590 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
591 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
592 pt.x = width_orig; pt.y = 0;
593 LPtoDP(hdc, &pt, 1);
594 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
595 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
596 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598 SetLastError(0xdeadbeef);
599 ret = SetMapMode(hdc, MM_LOMETRIC);
600 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
604 /* with an identity matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
611 LPtoDP(hdc, &pt, 1);
612 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
614 /* with a custom matrix */
615 memset(&gm, 0, sizeof(gm));
616 SetLastError(0xdeadbeef);
617 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
618 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
619 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
620 pt.x = width_orig; pt.y = 0;
621 LPtoDP(hdc, &pt, 1);
622 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
623 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
625 SetLastError(0xdeadbeef);
626 ret = SetMapMode(hdc, MM_TEXT);
627 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
629 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
631 /* with an identity matrix */
632 memset(&gm, 0, sizeof(gm));
633 SetLastError(0xdeadbeef);
634 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
635 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
636 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
637 pt.x = width_orig; pt.y = 0;
638 LPtoDP(hdc, &pt, 1);
639 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
640 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
641 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
642 /* with a custom matrix */
643 memset(&gm, 0, sizeof(gm));
644 SetLastError(0xdeadbeef);
645 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
646 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
647 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
648 pt.x = width_orig; pt.y = 0;
649 LPtoDP(hdc, &pt, 1);
650 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
651 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
652 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
654 SelectObject(hdc, old_hfont);
655 DeleteObject(hfont);
656 DeleteDC(hdc);
659 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
661 LOGFONT *lf = (LOGFONT *)lParam;
663 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
665 *lf = *elf;
666 return 0; /* stop enumeration */
668 return 1; /* continue enumeration */
671 #define FH_SCALE 0x80000000
672 static void test_bitmap_font_metrics(void)
674 static const struct font_data
676 const char face_name[LF_FACESIZE];
677 int weight, height, ascent, descent, int_leading, ext_leading;
678 int ave_char_width, max_char_width, dpi;
679 BYTE first_char, last_char, def_char, break_char;
680 DWORD ansi_bitfield;
681 WORD skip_lang_id;
682 int scaled_height;
683 } fd[] =
685 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
686 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
687 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
688 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
689 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
690 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
691 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
692 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
693 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
694 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
696 { "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 },
697 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
698 { "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 },
699 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
700 { "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 },
701 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
702 { "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 },
703 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
704 { "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 },
705 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
707 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
708 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
709 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
710 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
711 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
712 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
713 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
714 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
715 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
716 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
717 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
718 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
719 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
720 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
721 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
722 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
724 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
725 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
726 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
727 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
728 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
729 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
730 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
731 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
732 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
733 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
734 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
735 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
737 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
739 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
740 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
741 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
742 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
743 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
744 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
745 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
746 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
747 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
748 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
749 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
750 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
751 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
752 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
753 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
755 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
756 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
757 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
758 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
759 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
760 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
761 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
762 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
763 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
764 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
765 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
767 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
768 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
769 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
771 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
772 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
773 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
775 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
776 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
777 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
779 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
780 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
782 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
783 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
784 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN },
785 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
786 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
787 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN },
788 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
789 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
790 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC },
791 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN },
792 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
793 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
794 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC },
795 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN },
796 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
797 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
798 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC },
799 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN },
800 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
801 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC },
802 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN },
804 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
805 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
806 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
807 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
808 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
809 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
810 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
811 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
812 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
813 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
814 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
815 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
817 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
818 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
819 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
821 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
823 /* FIXME: add "Terminal" */
825 static const int font_log_pixels[] = { 96, 120 };
826 HDC hdc;
827 LOGFONT lf;
828 HFONT hfont, old_hfont;
829 TEXTMETRIC tm;
830 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
831 WORD system_lang_id;
832 char face_name[LF_FACESIZE];
833 CHARSETINFO csi;
835 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
836 trace("system language id %04x\n", system_lang_id);
838 expected_cs = GetACP();
839 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
841 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
842 return;
844 expected_cs = csi.ciCharset;
845 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
847 hdc = CreateCompatibleDC(0);
848 assert(hdc);
850 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
851 GetDeviceCaps(hdc, LOGPIXELSY));
853 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
854 diff = 32768;
855 font_res = 0;
856 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
858 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
859 if (new_diff < diff)
861 diff = new_diff;
862 font_res = font_log_pixels[i];
865 trace("best font resolution is %d\n", font_res);
867 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
869 int bit, height;
871 memset(&lf, 0, sizeof(lf));
873 height = fd[i].height & ~FH_SCALE;
874 lf.lfHeight = height;
875 strcpy(lf.lfFaceName, fd[i].face_name);
877 for(bit = 0; bit < 32; bit++)
879 GLYPHMETRICS gm;
880 DWORD fs[2];
881 BOOL bRet;
883 fs[0] = 1L << bit;
884 fs[1] = 0;
885 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
886 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
888 lf.lfCharSet = csi.ciCharset;
889 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
890 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
891 if (fd[i].height & FH_SCALE)
892 ok(ret, "scaled font height %d should not be enumerated\n", height);
893 else
895 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
897 if (ret) /* FIXME: Remove once Wine is fixed */
898 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
899 else
900 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
903 if (ret && !(fd[i].height & FH_SCALE))
904 continue;
906 hfont = create_font(lf.lfFaceName, &lf);
907 old_hfont = SelectObject(hdc, hfont);
909 SetLastError(0xdeadbeef);
910 ret = GetTextFace(hdc, sizeof(face_name), face_name);
911 ok(ret, "GetTextFace error %u\n", GetLastError());
913 if (lstrcmp(face_name, fd[i].face_name) != 0)
915 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
916 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
917 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
918 SelectObject(hdc, old_hfont);
919 DeleteObject(hfont);
920 continue;
923 memset(&gm, 0, sizeof(gm));
924 SetLastError(0xdeadbeef);
925 ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
926 todo_wine {
927 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
928 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
931 bRet = GetTextMetrics(hdc, &tm);
932 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
934 SetLastError(0xdeadbeef);
935 ret = GetTextCharset(hdc);
936 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
938 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
939 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
941 if(fd[i].dpi == tm.tmDigitizedAspectX)
943 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
944 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
946 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
947 if (fd[i].height & FH_SCALE)
948 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);
949 else
950 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);
951 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
952 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
953 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);
954 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);
955 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);
956 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
957 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
958 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
959 make default char test fail */
960 if (tm.tmCharSet == lf.lfCharSet)
961 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
962 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
963 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);
965 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
966 that make the max width bigger */
967 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
968 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);
970 else
971 skip("Skipping font metrics test for system langid 0x%x\n",
972 system_lang_id);
974 SelectObject(hdc, old_hfont);
975 DeleteObject(hfont);
979 DeleteDC(hdc);
982 static void test_GdiGetCharDimensions(void)
984 HDC hdc;
985 TEXTMETRICW tm;
986 LONG ret;
987 SIZE size;
988 LONG avgwidth, height;
989 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
991 if (!pGdiGetCharDimensions)
993 win_skip("GdiGetCharDimensions not available on this platform\n");
994 return;
997 hdc = CreateCompatibleDC(NULL);
999 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1000 avgwidth = ((size.cx / 26) + 1) / 2;
1002 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1003 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1004 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1006 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1007 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1009 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1010 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1012 height = 0;
1013 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1014 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1015 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1017 DeleteDC(hdc);
1020 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1021 const TEXTMETRIC *lpntme,
1022 DWORD FontType, LPARAM lParam)
1024 if (FontType & TRUETYPE_FONTTYPE)
1026 HFONT hfont;
1028 hfont = CreateFontIndirect(lpelfe);
1029 if (hfont)
1031 *(HFONT *)lParam = hfont;
1032 return 0;
1036 return 1;
1039 static void test_GetCharABCWidths(void)
1041 static const WCHAR str[] = {'a',0};
1042 BOOL ret;
1043 HDC hdc;
1044 LOGFONTA lf;
1045 HFONT hfont;
1046 ABC abc[1];
1047 ABCFLOAT abcf[1];
1048 WORD glyphs[1];
1049 DWORD nb;
1050 static const struct
1052 UINT first;
1053 UINT last;
1054 } range[] =
1056 {0xff, 0xff},
1057 {0x100, 0x100},
1058 {0xff, 0x100},
1059 {0x1ff, 0xff00},
1060 {0xffff, 0xffff},
1061 {0x10000, 0x10000},
1062 {0xffff, 0x10000},
1063 {0xffffff, 0xffffff},
1064 {0x1000000, 0x1000000},
1065 {0xffffff, 0x1000000},
1066 {0xffffffff, 0xffffffff},
1067 {0x00, 0xff}
1069 static const struct
1071 UINT cs;
1072 UINT a;
1073 UINT w;
1074 BOOL r[sizeof range / sizeof range[0]];
1075 } c[] =
1077 {ANSI_CHARSET, 0x30, 0x30,
1078 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1079 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1080 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1081 {HANGEUL_CHARSET, 0x8141, 0xac02,
1082 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1083 {JOHAB_CHARSET, 0x8446, 0x3135,
1084 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1085 {GB2312_CHARSET, 0x8141, 0x4e04,
1086 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1087 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1088 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1090 UINT i;
1092 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1094 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1095 return;
1098 memset(&lf, 0, sizeof(lf));
1099 strcpy(lf.lfFaceName, "System");
1100 lf.lfHeight = 20;
1102 hfont = CreateFontIndirectA(&lf);
1103 hdc = GetDC(0);
1104 hfont = SelectObject(hdc, hfont);
1106 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1107 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1109 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1110 ok(!ret, "GetCharABCWidthsI should have failed\n");
1112 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1113 ok(!ret, "GetCharABCWidthsI should have failed\n");
1115 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1116 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1118 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1119 ok(!ret, "GetCharABCWidthsW should have failed\n");
1121 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1122 ok(!ret, "GetCharABCWidthsW should have failed\n");
1124 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1125 ok(!ret, "GetCharABCWidthsW should have failed\n");
1127 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1128 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1130 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1131 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1133 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1134 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1136 hfont = SelectObject(hdc, hfont);
1137 DeleteObject(hfont);
1139 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1141 ABC a[2], w[2];
1142 ABC full[256];
1143 UINT code = 0x41, j;
1145 lf.lfFaceName[0] = '\0';
1146 lf.lfCharSet = c[i].cs;
1147 lf.lfPitchAndFamily = 0;
1148 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1150 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1151 continue;
1154 memset(a, 0, sizeof a);
1155 memset(w, 0, sizeof w);
1156 hfont = SelectObject(hdc, hfont);
1157 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1158 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1159 memcmp(a, w, sizeof a) == 0,
1160 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1162 memset(a, 0xbb, sizeof a);
1163 ret = pGetCharABCWidthsA(hdc, code, code, a);
1164 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1165 memset(full, 0xcc, sizeof full);
1166 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1167 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1168 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1169 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1171 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1173 memset(full, 0xdd, sizeof full);
1174 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1175 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1176 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1177 if (ret)
1179 UINT last = range[j].last - range[j].first;
1180 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1181 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1182 "GetCharABCWidthsA %x should match. codepage = %u\n",
1183 range[j].last, c[i].cs);
1187 hfont = SelectObject(hdc, hfont);
1188 DeleteObject(hfont);
1191 ReleaseDC(NULL, hdc);
1194 static void test_text_extents(void)
1196 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1197 LPINT extents;
1198 INT i, len, fit1, fit2;
1199 LOGFONTA lf;
1200 TEXTMETRICA tm;
1201 HDC hdc;
1202 HFONT hfont;
1203 SIZE sz;
1204 SIZE sz1, sz2;
1205 BOOL ret;
1207 memset(&lf, 0, sizeof(lf));
1208 strcpy(lf.lfFaceName, "Arial");
1209 lf.lfHeight = 20;
1211 hfont = CreateFontIndirectA(&lf);
1212 hdc = GetDC(0);
1213 hfont = SelectObject(hdc, hfont);
1214 GetTextMetricsA(hdc, &tm);
1215 GetTextExtentPointA(hdc, "o", 1, &sz);
1216 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1218 SetLastError(0xdeadbeef);
1219 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1220 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1222 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1223 hfont = SelectObject(hdc, hfont);
1224 DeleteObject(hfont);
1225 ReleaseDC(0, hdc);
1226 return;
1229 len = lstrlenW(wt);
1230 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1231 extents[0] = 1; /* So that the increasing sequence test will fail
1232 if the extents array is untouched. */
1233 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1234 GetTextExtentPointW(hdc, wt, len, &sz2);
1235 ok(sz1.cy == sz2.cy,
1236 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1237 /* Because of the '\n' in the string GetTextExtentExPoint and
1238 GetTextExtentPoint return different widths under Win2k, but
1239 under WinXP they return the same width. So we don't test that
1240 here. */
1242 for (i = 1; i < len; ++i)
1243 ok(extents[i-1] <= extents[i],
1244 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1246 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1247 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1248 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1249 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1250 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1251 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1252 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1253 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1254 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1255 ok(extents[0] == extents[2] && extents[1] == extents[3],
1256 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1257 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1258 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1259 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1260 HeapFree(GetProcessHeap(), 0, extents);
1262 /* extents functions fail with -ve counts (the interesting case being -1) */
1263 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1264 ok(ret == FALSE, "got %d\n", ret);
1265 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1266 ok(ret == FALSE, "got %d\n", ret);
1267 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1268 ok(ret == FALSE, "got %d\n", ret);
1270 /* max_extent = 0 succeeds and returns zero */
1271 fit1 = fit2 = -215;
1272 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1273 ok(ret == TRUE ||
1274 broken(ret == FALSE), /* NT4, 2k */
1275 "got %d\n", ret);
1276 ok(fit1 == 0 ||
1277 broken(fit1 == -215), /* NT4, 2k */
1278 "fit = %d\n", fit1);
1279 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1280 ok(ret == TRUE, "got %d\n", ret);
1281 ok(fit2 == 0, "fit = %d\n", fit2);
1283 /* max_extent = -1 is interpreted as a very large width that will
1284 * definitely fit our three characters */
1285 fit1 = fit2 = -215;
1286 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1287 ok(ret == TRUE, "got %d\n", ret);
1288 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1289 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1290 ok(ret == TRUE, "got %d\n", ret);
1291 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1293 /* max_extent = -2 is interpreted similarly, but the Ansi version
1294 * rejects it while the Unicode one accepts it */
1295 fit1 = fit2 = -215;
1296 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1297 todo_wine ok(ret == FALSE, "got %d\n", ret);
1298 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1299 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1300 ok(ret == TRUE, "got %d\n", ret);
1301 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1303 hfont = SelectObject(hdc, hfont);
1304 DeleteObject(hfont);
1305 ReleaseDC(NULL, hdc);
1308 static void test_GetGlyphIndices(void)
1310 HDC hdc;
1311 HFONT hfont;
1312 DWORD charcount;
1313 LOGFONTA lf;
1314 DWORD flags = 0;
1315 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1316 WORD glyphs[(sizeof(testtext)/2)-1];
1317 TEXTMETRIC textm;
1318 HFONT hOldFont;
1320 if (!pGetGlyphIndicesW) {
1321 win_skip("GetGlyphIndicesW not available on platform\n");
1322 return;
1325 hdc = GetDC(0);
1327 memset(&lf, 0, sizeof(lf));
1328 strcpy(lf.lfFaceName, "System");
1329 lf.lfHeight = 16;
1330 lf.lfCharSet = ANSI_CHARSET;
1332 hfont = CreateFontIndirectA(&lf);
1333 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1334 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1335 if (textm.tmCharSet == ANSI_CHARSET)
1337 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1338 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1339 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1340 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1341 flags = 0;
1342 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1343 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1344 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1345 textm.tmDefaultChar, glyphs[4]);
1347 else
1348 /* FIXME: Write tests for non-ANSI charsets. */
1349 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1351 if(!is_font_installed("Tahoma"))
1353 skip("Tahoma is not installed so skipping this test\n");
1354 return;
1356 memset(&lf, 0, sizeof(lf));
1357 strcpy(lf.lfFaceName, "Tahoma");
1358 lf.lfHeight = 20;
1360 hfont = CreateFontIndirectA(&lf);
1361 hOldFont = SelectObject(hdc, hfont);
1362 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1363 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1364 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1365 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1366 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1367 flags = 0;
1368 testtext[0] = textm.tmDefaultChar;
1369 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1370 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1371 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1372 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1373 DeleteObject(SelectObject(hdc, hOldFont));
1376 static void test_GetKerningPairs(void)
1378 static const struct kerning_data
1380 const char face_name[LF_FACESIZE];
1381 LONG height;
1382 /* some interesting fields from OUTLINETEXTMETRIC */
1383 LONG tmHeight, tmAscent, tmDescent;
1384 UINT otmEMSquare;
1385 INT otmAscent;
1386 INT otmDescent;
1387 UINT otmLineGap;
1388 UINT otmsCapEmHeight;
1389 UINT otmsXHeight;
1390 INT otmMacAscent;
1391 INT otmMacDescent;
1392 UINT otmMacLineGap;
1393 UINT otmusMinimumPPEM;
1394 /* small subset of kerning pairs to test */
1395 DWORD total_kern_pairs;
1396 const KERNINGPAIR kern_pair[26];
1397 } kd[] =
1399 {"Arial", 12, 12, 9, 3,
1400 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1403 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1404 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1405 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1406 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1407 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1408 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1409 {933,970,+1},{933,972,-1}
1412 {"Arial", -34, 39, 32, 7,
1413 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1416 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1417 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1418 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1419 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1420 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1421 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1422 {933,970,+2},{933,972,-3}
1425 { "Arial", 120, 120, 97, 23,
1426 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1429 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1430 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1431 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1432 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1433 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1434 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1435 {933,970,+6},{933,972,-10}
1438 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1439 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1440 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1443 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1444 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1445 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1446 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1447 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1448 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1449 {933,970,+54},{933,972,-83}
1452 #endif
1454 LOGFONT lf;
1455 HFONT hfont, hfont_old;
1456 KERNINGPAIR *kern_pair;
1457 HDC hdc;
1458 DWORD total_kern_pairs, ret, i, n, matches;
1460 hdc = GetDC(0);
1462 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1463 * which may render this test unusable, so we're trying to avoid that.
1465 SetLastError(0xdeadbeef);
1466 GetKerningPairsW(hdc, 0, NULL);
1467 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1469 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1470 ReleaseDC(0, hdc);
1471 return;
1474 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1476 OUTLINETEXTMETRICW otm;
1477 UINT uiRet;
1479 if (!is_font_installed(kd[i].face_name))
1481 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1482 continue;
1485 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1487 memset(&lf, 0, sizeof(lf));
1488 strcpy(lf.lfFaceName, kd[i].face_name);
1489 lf.lfHeight = kd[i].height;
1490 hfont = CreateFontIndirect(&lf);
1491 assert(hfont != 0);
1493 hfont_old = SelectObject(hdc, hfont);
1495 SetLastError(0xdeadbeef);
1496 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1497 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1498 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1500 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1501 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1502 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1503 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1504 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1505 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1507 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1508 kd[i].otmEMSquare, otm.otmEMSquare);
1509 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1510 kd[i].otmAscent, otm.otmAscent);
1511 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1512 kd[i].otmDescent, otm.otmDescent);
1513 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1514 kd[i].otmLineGap, otm.otmLineGap);
1515 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1516 kd[i].otmMacDescent, otm.otmMacDescent);
1517 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1518 kd[i].otmMacAscent, otm.otmMacAscent);
1519 todo_wine {
1520 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1521 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1522 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1523 kd[i].otmsXHeight, otm.otmsXHeight);
1524 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1525 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1526 kd[i].otmMacLineGap, otm.otmMacLineGap);
1527 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1528 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1531 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1532 trace("total_kern_pairs %u\n", total_kern_pairs);
1533 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1535 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1536 * passes on XP.
1538 SetLastError(0xdeadbeef);
1539 ret = GetKerningPairsW(hdc, 0, kern_pair);
1540 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1541 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1542 ok(ret == 0, "got %u, expected 0\n", ret);
1544 ret = GetKerningPairsW(hdc, 100, NULL);
1545 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1547 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1548 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1550 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1551 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1553 matches = 0;
1555 for (n = 0; n < ret; n++)
1557 DWORD j;
1558 /* Disabled to limit console spam */
1559 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1560 trace("{'%c','%c',%d},\n",
1561 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1562 for (j = 0; j < kd[i].total_kern_pairs; j++)
1564 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1565 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1567 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1568 "pair %d:%d got %d, expected %d\n",
1569 kern_pair[n].wFirst, kern_pair[n].wSecond,
1570 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1571 matches++;
1576 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1577 matches, kd[i].total_kern_pairs);
1579 HeapFree(GetProcessHeap(), 0, kern_pair);
1581 SelectObject(hdc, hfont_old);
1582 DeleteObject(hfont);
1585 ReleaseDC(0, hdc);
1588 static void test_height_selection(void)
1590 static const struct font_data
1592 const char face_name[LF_FACESIZE];
1593 int requested_height;
1594 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1595 } fd[] =
1597 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1598 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1599 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1600 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1601 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1602 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1603 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1604 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1605 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1606 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1608 HDC hdc;
1609 LOGFONT lf;
1610 HFONT hfont, old_hfont;
1611 TEXTMETRIC tm;
1612 INT ret, i;
1614 hdc = CreateCompatibleDC(0);
1615 assert(hdc);
1617 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1619 if (!is_truetype_font_installed(fd[i].face_name))
1621 skip("%s is not installed\n", fd[i].face_name);
1622 continue;
1625 memset(&lf, 0, sizeof(lf));
1626 lf.lfHeight = fd[i].requested_height;
1627 lf.lfWeight = fd[i].weight;
1628 strcpy(lf.lfFaceName, fd[i].face_name);
1630 hfont = CreateFontIndirect(&lf);
1631 assert(hfont);
1633 old_hfont = SelectObject(hdc, hfont);
1634 ret = GetTextMetrics(hdc, &tm);
1635 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1636 if(fd[i].dpi == tm.tmDigitizedAspectX)
1638 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1639 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);
1640 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);
1641 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);
1642 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);
1643 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1644 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);
1645 #endif
1646 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);
1649 SelectObject(hdc, old_hfont);
1650 DeleteObject(hfont);
1653 DeleteDC(hdc);
1656 static void test_GetOutlineTextMetrics(void)
1658 OUTLINETEXTMETRIC *otm;
1659 LOGFONT lf;
1660 HFONT hfont, hfont_old;
1661 HDC hdc;
1662 DWORD ret, otm_size;
1663 LPSTR unset_ptr;
1665 if (!is_font_installed("Arial"))
1667 skip("Arial is not installed\n");
1668 return;
1671 hdc = GetDC(0);
1673 memset(&lf, 0, sizeof(lf));
1674 strcpy(lf.lfFaceName, "Arial");
1675 lf.lfHeight = -13;
1676 lf.lfWeight = FW_NORMAL;
1677 lf.lfPitchAndFamily = DEFAULT_PITCH;
1678 lf.lfQuality = PROOF_QUALITY;
1679 hfont = CreateFontIndirect(&lf);
1680 assert(hfont != 0);
1682 hfont_old = SelectObject(hdc, hfont);
1683 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1684 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1686 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1688 memset(otm, 0xAA, otm_size);
1689 SetLastError(0xdeadbeef);
1690 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1691 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1692 ok(ret == 1 /* Win9x */ ||
1693 ret == otm->otmSize /* XP*/,
1694 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1695 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1697 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1698 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1699 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1700 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1703 memset(otm, 0xAA, otm_size);
1704 SetLastError(0xdeadbeef);
1705 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1706 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1707 ok(ret == 1 /* Win9x */ ||
1708 ret == otm->otmSize /* XP*/,
1709 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1710 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1712 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1713 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1714 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1715 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1718 /* ask about truncated data */
1719 memset(otm, 0xAA, otm_size);
1720 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1721 SetLastError(0xdeadbeef);
1722 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1723 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1724 ok(ret == 1 /* Win9x */ ||
1725 ret == otm->otmSize /* XP*/,
1726 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1727 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1729 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1730 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1731 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1733 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1735 HeapFree(GetProcessHeap(), 0, otm);
1737 SelectObject(hdc, hfont_old);
1738 DeleteObject(hfont);
1740 ReleaseDC(0, hdc);
1743 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1745 INT y,
1746 breakCount,
1747 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1748 areaWidth = clientArea->right - clientArea->left,
1749 nErrors = 0, e;
1750 BOOL lastExtent = FALSE;
1751 PSTR pFirstChar, pLastChar;
1752 SIZE size;
1753 TEXTMETRICA tm;
1754 struct err
1756 char extent[100];
1757 int GetTextExtentExPointWWidth;
1758 } error[10];
1760 GetTextMetricsA(hdc, &tm);
1761 y = clientArea->top;
1762 do {
1763 breakCount = 0;
1764 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1765 pFirstChar = str;
1767 do {
1768 pLastChar = str;
1770 /* if not at the end of the string, ... */
1771 if (*str == '\0') break;
1772 /* ... add the next word to the current extent */
1773 while (*str != '\0' && *str++ != tm.tmBreakChar);
1774 breakCount++;
1775 SetTextJustification(hdc, 0, 0);
1776 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1777 } while ((int) size.cx < areaWidth);
1779 /* ignore trailing break chars */
1780 breakCount--;
1781 while (*(pLastChar - 1) == tm.tmBreakChar)
1783 pLastChar--;
1784 breakCount--;
1787 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1789 SetTextJustification(hdc, 0, 0);
1790 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1792 /* do not justify the last extent */
1793 if (*str != '\0' && breakCount > 0)
1795 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1796 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1797 justifiedWidth = size.cx;
1799 else lastExtent = TRUE;
1801 /* catch errors and report them */
1802 if (!lastExtent && (justifiedWidth != areaWidth))
1804 memset(error[nErrors].extent, 0, 100);
1805 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1806 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1807 nErrors++;
1810 y += size.cy;
1811 str = pLastChar;
1812 } while (*str && y < clientArea->bottom);
1814 for (e = 0; e < nErrors; e++)
1816 /* The width returned by GetTextExtentPoint32() is exactly the same
1817 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1818 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1819 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1820 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1824 static void test_SetTextJustification(void)
1826 HDC hdc;
1827 RECT clientArea;
1828 LOGFONTA lf;
1829 HFONT hfont;
1830 HWND hwnd;
1831 static char testText[] =
1832 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1833 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1834 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1835 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1836 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1837 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1838 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1840 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1841 GetClientRect( hwnd, &clientArea );
1842 hdc = GetDC( hwnd );
1844 memset(&lf, 0, sizeof lf);
1845 lf.lfCharSet = ANSI_CHARSET;
1846 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1847 lf.lfWeight = FW_DONTCARE;
1848 lf.lfHeight = 20;
1849 lf.lfQuality = DEFAULT_QUALITY;
1850 lstrcpyA(lf.lfFaceName, "Times New Roman");
1851 hfont = create_font("Times New Roman", &lf);
1852 SelectObject(hdc, hfont);
1854 testJustification(hdc, testText, &clientArea);
1856 DeleteObject(hfont);
1857 ReleaseDC(hwnd, hdc);
1858 DestroyWindow(hwnd);
1861 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1863 HDC hdc;
1864 LOGFONTA lf;
1865 HFONT hfont, hfont_old;
1866 CHARSETINFO csi;
1867 FONTSIGNATURE fs;
1868 INT cs;
1869 DWORD i, ret;
1870 char name[64];
1872 assert(count <= 128);
1874 memset(&lf, 0, sizeof(lf));
1876 lf.lfCharSet = charset;
1877 lf.lfHeight = 10;
1878 lstrcpyA(lf.lfFaceName, "Arial");
1879 SetLastError(0xdeadbeef);
1880 hfont = CreateFontIndirectA(&lf);
1881 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1883 hdc = GetDC(0);
1884 hfont_old = SelectObject(hdc, hfont);
1886 cs = GetTextCharsetInfo(hdc, &fs, 0);
1887 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1889 SetLastError(0xdeadbeef);
1890 ret = GetTextFaceA(hdc, sizeof(name), name);
1891 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1893 if (charset == SYMBOL_CHARSET)
1895 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1896 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1898 else
1900 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1901 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1904 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1906 trace("Can't find codepage for charset %d\n", cs);
1907 ReleaseDC(0, hdc);
1908 return FALSE;
1910 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1912 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1914 skip("Font code page %d, looking for code page %d\n",
1915 pGdiGetCodePage(hdc), code_page);
1916 ReleaseDC(0, hdc);
1917 return FALSE;
1920 if (unicode)
1922 char ansi_buf[128];
1923 WCHAR unicode_buf[128];
1925 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1927 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1929 SetLastError(0xdeadbeef);
1930 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1931 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1932 count, ret, GetLastError());
1934 else
1936 char ansi_buf[128];
1938 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1940 SetLastError(0xdeadbeef);
1941 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1942 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1943 count, ret, GetLastError());
1946 SelectObject(hdc, hfont_old);
1947 DeleteObject(hfont);
1949 ReleaseDC(0, hdc);
1951 return TRUE;
1954 static void test_font_charset(void)
1956 static struct charset_data
1958 INT charset;
1959 UINT code_page;
1960 WORD font_idxA[128], font_idxW[128];
1961 } cd[] =
1963 { ANSI_CHARSET, 1252 },
1964 { RUSSIAN_CHARSET, 1251 },
1965 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1967 int i;
1969 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1971 win_skip("Skipping the font charset test on a Win9x platform\n");
1972 return;
1975 if (!is_font_installed("Arial"))
1977 skip("Arial is not installed\n");
1978 return;
1981 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1983 if (cd[i].charset == SYMBOL_CHARSET)
1985 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1987 skip("Symbol or Wingdings is not installed\n");
1988 break;
1991 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1992 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1993 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1996 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1997 if (i > 2)
1999 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2000 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2002 else
2003 skip("Symbol or Wingdings is not installed\n");
2006 static void test_GetFontUnicodeRanges(void)
2008 LOGFONTA lf;
2009 HDC hdc;
2010 HFONT hfont, hfont_old;
2011 DWORD size;
2012 GLYPHSET *gs;
2013 DWORD i;
2015 if (!pGetFontUnicodeRanges)
2017 win_skip("GetFontUnicodeRanges not available before W2K\n");
2018 return;
2021 memset(&lf, 0, sizeof(lf));
2022 lstrcpyA(lf.lfFaceName, "Arial");
2023 hfont = create_font("Arial", &lf);
2025 hdc = GetDC(0);
2026 hfont_old = SelectObject(hdc, hfont);
2028 size = pGetFontUnicodeRanges(NULL, NULL);
2029 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2031 size = pGetFontUnicodeRanges(hdc, NULL);
2032 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2034 gs = HeapAlloc(GetProcessHeap(), 0, size);
2036 size = pGetFontUnicodeRanges(hdc, gs);
2037 ok(size, "GetFontUnicodeRanges failed\n");
2039 if (0) /* Disabled to limit console spam */
2040 for (i = 0; i < gs->cRanges; i++)
2041 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2042 trace("found %u ranges\n", gs->cRanges);
2044 HeapFree(GetProcessHeap(), 0, gs);
2046 SelectObject(hdc, hfont_old);
2047 DeleteObject(hfont);
2048 ReleaseDC(NULL, hdc);
2051 #define MAX_ENUM_FONTS 4096
2053 struct enum_font_data
2055 int total;
2056 LOGFONT lf[MAX_ENUM_FONTS];
2059 struct enum_font_dataW
2061 int total;
2062 LOGFONTW lf[MAX_ENUM_FONTS];
2065 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2067 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2068 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2070 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2071 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2073 if (type != TRUETYPE_FONTTYPE) return 1;
2075 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2077 if (0) /* Disabled to limit console spam */
2078 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2079 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2080 if (efd->total < MAX_ENUM_FONTS)
2081 efd->lf[efd->total++] = *lf;
2082 else
2083 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2085 return 1;
2088 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2090 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2091 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2093 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2094 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2096 if (type != TRUETYPE_FONTTYPE) return 1;
2098 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2100 if (0) /* Disabled to limit console spam */
2101 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2102 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2103 if (efd->total < MAX_ENUM_FONTS)
2104 efd->lf[efd->total++] = *lf;
2105 else
2106 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2108 return 1;
2111 static void get_charset_stats(struct enum_font_data *efd,
2112 int *ansi_charset, int *symbol_charset,
2113 int *russian_charset)
2115 int i;
2117 *ansi_charset = 0;
2118 *symbol_charset = 0;
2119 *russian_charset = 0;
2121 for (i = 0; i < efd->total; i++)
2123 switch (efd->lf[i].lfCharSet)
2125 case ANSI_CHARSET:
2126 (*ansi_charset)++;
2127 break;
2128 case SYMBOL_CHARSET:
2129 (*symbol_charset)++;
2130 break;
2131 case RUSSIAN_CHARSET:
2132 (*russian_charset)++;
2133 break;
2138 static void get_charset_statsW(struct enum_font_dataW *efd,
2139 int *ansi_charset, int *symbol_charset,
2140 int *russian_charset)
2142 int i;
2144 *ansi_charset = 0;
2145 *symbol_charset = 0;
2146 *russian_charset = 0;
2148 for (i = 0; i < efd->total; i++)
2150 switch (efd->lf[i].lfCharSet)
2152 case ANSI_CHARSET:
2153 (*ansi_charset)++;
2154 break;
2155 case SYMBOL_CHARSET:
2156 (*symbol_charset)++;
2157 break;
2158 case RUSSIAN_CHARSET:
2159 (*russian_charset)++;
2160 break;
2165 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2167 struct enum_font_data efd;
2168 struct enum_font_dataW efdw;
2169 LOGFONT lf;
2170 HDC hdc;
2171 int i, ret, ansi_charset, symbol_charset, russian_charset;
2173 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2175 if (*font_name && !is_truetype_font_installed(font_name))
2177 skip("%s is not installed\n", font_name);
2178 return;
2181 hdc = GetDC(0);
2183 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2184 * while EnumFontFamiliesEx doesn't.
2186 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2189 * Use EnumFontFamiliesW since win98 crashes when the
2190 * second parameter is NULL using EnumFontFamilies
2192 efdw.total = 0;
2193 SetLastError(0xdeadbeef);
2194 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2195 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2196 if(ret)
2198 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2199 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2200 ansi_charset, symbol_charset, russian_charset);
2201 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2202 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2203 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2204 ok(russian_charset > 0 ||
2205 broken(russian_charset == 0), /* NT4 */
2206 "NULL family should enumerate RUSSIAN_CHARSET\n");
2209 efdw.total = 0;
2210 SetLastError(0xdeadbeef);
2211 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2212 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2213 if(ret)
2215 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2216 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2217 ansi_charset, symbol_charset, russian_charset);
2218 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2219 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2220 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2221 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2225 efd.total = 0;
2226 SetLastError(0xdeadbeef);
2227 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2228 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2229 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2230 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2231 ansi_charset, symbol_charset, russian_charset,
2232 *font_name ? font_name : "<empty>");
2233 if (*font_name)
2234 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2235 else
2236 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2237 for (i = 0; i < efd.total; i++)
2239 /* FIXME: remove completely once Wine is fixed */
2240 if (efd.lf[i].lfCharSet != font_charset)
2242 todo_wine
2243 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2245 else
2246 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2247 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2248 font_name, efd.lf[i].lfFaceName);
2251 memset(&lf, 0, sizeof(lf));
2252 lf.lfCharSet = ANSI_CHARSET;
2253 lstrcpy(lf.lfFaceName, font_name);
2254 efd.total = 0;
2255 SetLastError(0xdeadbeef);
2256 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2257 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2258 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2259 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2260 ansi_charset, symbol_charset, russian_charset,
2261 *font_name ? font_name : "<empty>");
2262 if (font_charset == SYMBOL_CHARSET)
2264 if (*font_name)
2265 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2266 else
2267 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2269 else
2271 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2272 for (i = 0; i < efd.total; i++)
2274 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2275 if (*font_name)
2276 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2277 font_name, efd.lf[i].lfFaceName);
2281 /* DEFAULT_CHARSET should enumerate all available charsets */
2282 memset(&lf, 0, sizeof(lf));
2283 lf.lfCharSet = DEFAULT_CHARSET;
2284 lstrcpy(lf.lfFaceName, font_name);
2285 efd.total = 0;
2286 SetLastError(0xdeadbeef);
2287 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2288 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2289 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2290 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2291 ansi_charset, symbol_charset, russian_charset,
2292 *font_name ? font_name : "<empty>");
2293 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2294 for (i = 0; i < efd.total; i++)
2296 if (*font_name)
2297 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2298 font_name, efd.lf[i].lfFaceName);
2300 if (*font_name)
2302 switch (font_charset)
2304 case ANSI_CHARSET:
2305 ok(ansi_charset > 0,
2306 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2307 ok(!symbol_charset,
2308 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2309 ok(russian_charset > 0,
2310 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2311 break;
2312 case SYMBOL_CHARSET:
2313 ok(!ansi_charset,
2314 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2315 ok(symbol_charset,
2316 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2317 ok(!russian_charset,
2318 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2319 break;
2320 case DEFAULT_CHARSET:
2321 ok(ansi_charset > 0,
2322 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2323 ok(symbol_charset > 0,
2324 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2325 ok(russian_charset > 0,
2326 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2327 break;
2330 else
2332 ok(ansi_charset > 0,
2333 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2334 ok(symbol_charset > 0,
2335 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2336 ok(russian_charset > 0,
2337 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2340 memset(&lf, 0, sizeof(lf));
2341 lf.lfCharSet = SYMBOL_CHARSET;
2342 lstrcpy(lf.lfFaceName, font_name);
2343 efd.total = 0;
2344 SetLastError(0xdeadbeef);
2345 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2346 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2347 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2348 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2349 ansi_charset, symbol_charset, russian_charset,
2350 *font_name ? font_name : "<empty>");
2351 if (*font_name && font_charset == ANSI_CHARSET)
2352 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2353 else
2355 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2356 for (i = 0; i < efd.total; i++)
2358 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2359 if (*font_name)
2360 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2361 font_name, efd.lf[i].lfFaceName);
2364 ok(!ansi_charset,
2365 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2366 ok(symbol_charset > 0,
2367 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2368 ok(!russian_charset,
2369 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2372 ReleaseDC(0, hdc);
2375 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2377 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2379 if (type != TRUETYPE_FONTTYPE) return 1;
2381 if (efd->total < MAX_ENUM_FONTS)
2382 efd->lf[efd->total++] = *lf;
2383 else
2384 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2386 return 1;
2389 static void test_EnumFontFamiliesEx_default_charset(void)
2391 struct enum_font_data efd;
2392 LOGFONT gui_font, enum_font;
2393 DWORD ret;
2394 HDC hdc;
2396 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2397 ok(ret, "GetObject failed.\n");
2398 if (!ret)
2399 return;
2401 efd.total = 0;
2403 hdc = GetDC(0);
2404 memset(&enum_font, 0, sizeof(enum_font));
2405 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2406 enum_font.lfCharSet = DEFAULT_CHARSET;
2407 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2408 ReleaseDC(0, hdc);
2410 if (efd.total == 0) {
2411 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2412 return;
2414 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2416 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2417 "(%s) got charset %d expected %d\n",
2418 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2420 return;
2423 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2425 HFONT hfont, hfont_prev;
2426 DWORD ret;
2427 GLYPHMETRICS gm1, gm2;
2428 LOGFONTA lf2 = *lf;
2429 WORD idx;
2431 if(!pGetGlyphIndicesA)
2432 return;
2434 /* negative widths are handled just as positive ones */
2435 lf2.lfWidth = -lf->lfWidth;
2437 SetLastError(0xdeadbeef);
2438 hfont = CreateFontIndirectA(lf);
2439 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2440 check_font("original", lf, hfont);
2442 hfont_prev = SelectObject(hdc, hfont);
2444 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2445 if (ret == GDI_ERROR || idx == 0xffff)
2447 SelectObject(hdc, hfont_prev);
2448 DeleteObject(hfont);
2449 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2450 return;
2453 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2454 memset(&gm1, 0xab, sizeof(gm1));
2455 SetLastError(0xdeadbeef);
2456 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2457 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2459 SelectObject(hdc, hfont_prev);
2460 DeleteObject(hfont);
2462 SetLastError(0xdeadbeef);
2463 hfont = CreateFontIndirectA(&lf2);
2464 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2465 check_font("negative width", &lf2, hfont);
2467 hfont_prev = SelectObject(hdc, hfont);
2469 memset(&gm2, 0xbb, sizeof(gm2));
2470 SetLastError(0xdeadbeef);
2471 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2472 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2474 SelectObject(hdc, hfont_prev);
2475 DeleteObject(hfont);
2477 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2478 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2479 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2480 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2481 gm1.gmCellIncX == gm2.gmCellIncX &&
2482 gm1.gmCellIncY == gm2.gmCellIncY,
2483 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2484 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2485 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2486 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2487 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2490 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2491 #include "pshpack2.h"
2492 typedef struct
2494 USHORT version;
2495 SHORT xAvgCharWidth;
2496 USHORT usWeightClass;
2497 USHORT usWidthClass;
2498 SHORT fsType;
2499 SHORT ySubscriptXSize;
2500 SHORT ySubscriptYSize;
2501 SHORT ySubscriptXOffset;
2502 SHORT ySubscriptYOffset;
2503 SHORT ySuperscriptXSize;
2504 SHORT ySuperscriptYSize;
2505 SHORT ySuperscriptXOffset;
2506 SHORT ySuperscriptYOffset;
2507 SHORT yStrikeoutSize;
2508 SHORT yStrikeoutPosition;
2509 SHORT sFamilyClass;
2510 PANOSE panose;
2511 ULONG ulUnicodeRange1;
2512 ULONG ulUnicodeRange2;
2513 ULONG ulUnicodeRange3;
2514 ULONG ulUnicodeRange4;
2515 CHAR achVendID[4];
2516 USHORT fsSelection;
2517 USHORT usFirstCharIndex;
2518 USHORT usLastCharIndex;
2519 /* According to the Apple spec, original version didn't have the below fields,
2520 * version numbers were taken from the OpenType spec.
2522 /* version 0 (TrueType 1.5) */
2523 USHORT sTypoAscender;
2524 USHORT sTypoDescender;
2525 USHORT sTypoLineGap;
2526 USHORT usWinAscent;
2527 USHORT usWinDescent;
2528 /* version 1 (TrueType 1.66) */
2529 ULONG ulCodePageRange1;
2530 ULONG ulCodePageRange2;
2531 /* version 2 (OpenType 1.2) */
2532 SHORT sxHeight;
2533 SHORT sCapHeight;
2534 USHORT usDefaultChar;
2535 USHORT usBreakChar;
2536 USHORT usMaxContext;
2537 } TT_OS2_V2;
2538 #include "poppack.h"
2540 #ifdef WORDS_BIGENDIAN
2541 #define GET_BE_WORD(x) (x)
2542 #define GET_BE_DWORD(x) (x)
2543 #else
2544 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2545 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2546 #endif
2548 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2549 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2550 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2551 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2552 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2553 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2555 typedef struct
2557 USHORT version;
2558 USHORT num_tables;
2559 } cmap_header;
2561 typedef struct
2563 USHORT plat_id;
2564 USHORT enc_id;
2565 ULONG offset;
2566 } cmap_encoding_record;
2568 typedef struct
2570 USHORT format;
2571 USHORT length;
2572 USHORT language;
2574 BYTE glyph_ids[256];
2575 } cmap_format_0;
2577 typedef struct
2579 USHORT format;
2580 USHORT length;
2581 USHORT language;
2583 USHORT seg_countx2;
2584 USHORT search_range;
2585 USHORT entry_selector;
2586 USHORT range_shift;
2588 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2589 /* Then follows:
2590 USHORT pad;
2591 USHORT start_count[seg_countx2 / 2];
2592 USHORT id_delta[seg_countx2 / 2];
2593 USHORT id_range_offset[seg_countx2 / 2];
2594 USHORT glyph_ids[];
2596 } cmap_format_4;
2598 typedef struct
2600 USHORT end_count;
2601 USHORT start_count;
2602 USHORT id_delta;
2603 USHORT id_range_offset;
2604 } cmap_format_4_seg;
2606 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2608 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2609 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2610 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2611 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2612 os2->panose.bWeight, os2->panose.bProportion);
2615 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2617 int i;
2618 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2620 *first = 256;
2622 for(i = 0; i < 256; i++)
2624 if(cmap->glyph_ids[i] == 0) continue;
2625 *last = i;
2626 if(*first == 256) *first = i;
2628 if(*first == 256) return FALSE;
2629 return TRUE;
2632 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2634 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2635 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2636 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2637 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2638 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2641 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2643 int i;
2644 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2645 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2646 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2648 *first = 0x10000;
2650 for(i = 0; i < seg_count; i++)
2652 DWORD code, index;
2653 cmap_format_4_seg seg;
2655 get_seg4(cmap, i, &seg);
2656 for(code = seg.start_count; code <= seg.end_count; code++)
2658 if(seg.id_range_offset == 0)
2659 index = (seg.id_delta + code) & 0xffff;
2660 else
2662 index = seg.id_range_offset / 2
2663 + code - seg.start_count
2664 + i - seg_count;
2666 /* some fonts have broken last segment */
2667 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2668 index = GET_BE_WORD(glyph_ids[index]);
2669 else
2671 trace("segment %04x/%04x index %04x points to nowhere\n",
2672 seg.start_count, seg.end_count, index);
2673 index = 0;
2675 if(index) index += seg.id_delta;
2677 if(*first == 0x10000)
2678 *last = *first = code;
2679 else if(index)
2680 *last = code;
2684 if(*first == 0x10000) return FALSE;
2685 return TRUE;
2688 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2690 USHORT i;
2691 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2693 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2695 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2696 return (BYTE *)header + GET_BE_DWORD(record->offset);
2697 record++;
2699 return NULL;
2702 typedef enum
2704 cmap_none,
2705 cmap_ms_unicode,
2706 cmap_ms_symbol
2707 } cmap_type;
2709 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2711 LONG size, ret;
2712 cmap_header *header;
2713 void *cmap;
2714 BOOL r = FALSE;
2715 WORD format;
2717 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2718 ok(size != GDI_ERROR, "no cmap table found\n");
2719 if(size == GDI_ERROR) return FALSE;
2721 header = HeapAlloc(GetProcessHeap(), 0, size);
2722 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2723 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2724 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2726 cmap = get_cmap(header, 3, 1);
2727 if(cmap)
2728 *cmap_type = cmap_ms_unicode;
2729 else
2731 cmap = get_cmap(header, 3, 0);
2732 if(cmap) *cmap_type = cmap_ms_symbol;
2734 if(!cmap)
2736 *cmap_type = cmap_none;
2737 goto end;
2740 format = GET_BE_WORD(*(WORD *)cmap);
2741 switch(format)
2743 case 0:
2744 r = get_first_last_from_cmap0(cmap, first, last);
2745 break;
2746 case 4:
2747 r = get_first_last_from_cmap4(cmap, first, last, size);
2748 break;
2749 default:
2750 trace("unhandled cmap format %d\n", format);
2751 break;
2754 end:
2755 HeapFree(GetProcessHeap(), 0, header);
2756 return r;
2759 #define TT_PLATFORM_MICROSOFT 3
2760 #define TT_MS_ID_UNICODE_CS 1
2761 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2762 #define TT_NAME_ID_FULL_NAME 4
2764 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2766 struct sfnt_name_header
2768 USHORT format;
2769 USHORT number_of_record;
2770 USHORT storage_offset;
2771 } *header;
2772 struct sfnt_name
2774 USHORT platform_id;
2775 USHORT encoding_id;
2776 USHORT language_id;
2777 USHORT name_id;
2778 USHORT length;
2779 USHORT offset;
2780 } *entry;
2781 BOOL r = FALSE;
2782 LONG size, offset, length;
2783 LONG c, ret;
2784 WCHAR *name;
2785 BYTE *data;
2786 USHORT i;
2788 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2789 ok(size != GDI_ERROR, "no name table found\n");
2790 if(size == GDI_ERROR) return FALSE;
2792 data = HeapAlloc(GetProcessHeap(), 0, size);
2793 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2794 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2796 header = (void *)data;
2797 header->format = GET_BE_WORD(header->format);
2798 header->number_of_record = GET_BE_WORD(header->number_of_record);
2799 header->storage_offset = GET_BE_WORD(header->storage_offset);
2800 if (header->format != 0)
2802 trace("got format %u\n", header->format);
2803 goto out;
2805 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2807 trace("number records out of range: %d\n", header->number_of_record);
2808 goto out;
2810 if (header->storage_offset >= size)
2812 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2813 goto out;
2816 entry = (void *)&header[1];
2817 for (i = 0; i < header->number_of_record; i++)
2819 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2820 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2821 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2822 GET_BE_WORD(entry[i].name_id) != name_id)
2824 continue;
2827 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2828 length = GET_BE_WORD(entry[i].length);
2829 if (offset + length > size)
2831 trace("entry %d is out of range\n", i);
2832 break;
2834 if (length >= out_size)
2836 trace("buffer too small for entry %d\n", i);
2837 break;
2840 name = (WCHAR *)(data + offset);
2841 for (c = 0; c < length / 2; c++)
2842 out_buf[c] = GET_BE_WORD(name[c]);
2843 out_buf[c] = 0;
2845 r = TRUE;
2846 break;
2849 out:
2850 HeapFree(GetProcessHeap(), 0, data);
2851 return r;
2854 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2856 HDC hdc;
2857 HFONT hfont, hfont_old;
2858 TEXTMETRICA tmA;
2859 TT_OS2_V2 tt_os2;
2860 LONG size, ret;
2861 const char *font_name = lf->lfFaceName;
2862 DWORD cmap_first = 0, cmap_last = 0;
2863 UINT ascent, descent, cell_height;
2864 cmap_type cmap_type;
2865 BOOL sys_lang_non_english;
2867 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2868 hdc = GetDC(0);
2870 SetLastError(0xdeadbeef);
2871 hfont = CreateFontIndirectA(lf);
2872 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2874 hfont_old = SelectObject(hdc, hfont);
2876 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2877 if (size == GDI_ERROR)
2879 trace("OS/2 chunk was not found\n");
2880 goto end_of_test;
2882 if (size > sizeof(tt_os2))
2884 trace("got too large OS/2 chunk of size %u\n", size);
2885 size = sizeof(tt_os2);
2888 memset(&tt_os2, 0, sizeof(tt_os2));
2889 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2890 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2892 ascent = GET_BE_WORD(tt_os2.usWinAscent);
2893 descent = GET_BE_WORD(tt_os2.usWinDescent);
2894 cell_height = ascent + descent;
2895 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
2896 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
2898 SetLastError(0xdeadbeef);
2899 ret = GetTextMetricsA(hdc, &tmA);
2900 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2902 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2904 skip("Unable to retrieve first and last glyphs from cmap\n");
2906 else
2908 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2909 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2910 UINT os2_first_char, os2_last_char, default_char, break_char;
2911 USHORT version;
2912 TEXTMETRICW tmW;
2914 version = GET_BE_WORD(tt_os2.version);
2916 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2917 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2918 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2919 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2921 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2922 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2923 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2925 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2927 expect_first_W = 0;
2928 switch(GetACP())
2930 case 1257: /* Baltic */
2931 expect_last_W = 0xf8fd;
2932 break;
2933 default:
2934 expect_last_W = 0xf0ff;
2936 expect_break_W = 0x20;
2937 expect_default_W = expect_break_W - 1;
2938 expect_first_A = 0x1e;
2939 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2941 else
2943 expect_first_W = cmap_first;
2944 expect_last_W = min(cmap_last, os2_last_char);
2945 if(os2_first_char <= 1)
2946 expect_break_W = os2_first_char + 2;
2947 else if(os2_first_char > 0xff)
2948 expect_break_W = 0x20;
2949 else
2950 expect_break_W = os2_first_char;
2951 expect_default_W = expect_break_W - 1;
2952 expect_first_A = expect_default_W - 1;
2953 expect_last_A = min(expect_last_W, 0xff);
2955 expect_break_A = expect_break_W;
2956 expect_default_A = expect_default_W;
2958 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2959 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2960 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2961 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2962 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2963 else
2964 ok(tmA.tmFirstChar == expect_first_A ||
2965 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2966 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2967 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2968 ok(tmA.tmLastChar == expect_last_A ||
2969 tmA.tmLastChar == 0xff /* win9x */,
2970 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2971 else
2972 skip("tmLastChar is DBCS lead byte\n");
2973 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2974 font_name, tmA.tmBreakChar, expect_break_A);
2975 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2976 "A: tmDefaultChar for %s got %02x expected %02x\n",
2977 font_name, tmA.tmDefaultChar, expect_default_A);
2980 SetLastError(0xdeadbeef);
2981 ret = GetTextMetricsW(hdc, &tmW);
2982 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2983 "GetTextMetricsW error %u\n", GetLastError());
2984 if (ret)
2986 /* Wine uses the os2 first char */
2987 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2988 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2989 font_name, tmW.tmFirstChar, expect_first_W);
2990 else
2991 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2992 font_name, tmW.tmFirstChar, expect_first_W);
2994 /* Wine uses the os2 last char */
2995 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2996 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2997 font_name, tmW.tmLastChar, expect_last_W);
2998 else
2999 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3000 font_name, tmW.tmLastChar, expect_last_W);
3001 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3002 font_name, tmW.tmBreakChar, expect_break_W);
3003 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3004 "W: tmDefaultChar for %s got %02x expected %02x\n",
3005 font_name, tmW.tmDefaultChar, expect_default_W);
3007 /* Test the aspect ratio while we have tmW */
3008 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3009 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3010 tmW.tmDigitizedAspectX, ret);
3011 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3012 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3013 tmW.tmDigitizedAspectX, ret);
3017 /* test FF_ values */
3018 switch(tt_os2.panose.bFamilyType)
3020 case PAN_ANY:
3021 case PAN_NO_FIT:
3022 case PAN_FAMILY_TEXT_DISPLAY:
3023 case PAN_FAMILY_PICTORIAL:
3024 default:
3025 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3026 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3028 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3029 break;
3031 switch(tt_os2.panose.bSerifStyle)
3033 case PAN_ANY:
3034 case PAN_NO_FIT:
3035 default:
3036 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3037 break;
3039 case PAN_SERIF_COVE:
3040 case PAN_SERIF_OBTUSE_COVE:
3041 case PAN_SERIF_SQUARE_COVE:
3042 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3043 case PAN_SERIF_SQUARE:
3044 case PAN_SERIF_THIN:
3045 case PAN_SERIF_BONE:
3046 case PAN_SERIF_EXAGGERATED:
3047 case PAN_SERIF_TRIANGLE:
3048 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3049 break;
3051 case PAN_SERIF_NORMAL_SANS:
3052 case PAN_SERIF_OBTUSE_SANS:
3053 case PAN_SERIF_PERP_SANS:
3054 case PAN_SERIF_FLARED:
3055 case PAN_SERIF_ROUNDED:
3056 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3057 break;
3059 break;
3061 case PAN_FAMILY_SCRIPT:
3062 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3063 break;
3065 case PAN_FAMILY_DECORATIVE:
3066 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3067 break;
3070 test_negative_width(hdc, lf);
3072 end_of_test:
3073 SelectObject(hdc, hfont_old);
3074 DeleteObject(hfont);
3076 ReleaseDC(0, hdc);
3079 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3081 INT *enumed = (INT *)lParam;
3083 if (type == TRUETYPE_FONTTYPE)
3085 (*enumed)++;
3086 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3088 return 1;
3091 static void test_GetTextMetrics(void)
3093 LOGFONTA lf;
3094 HDC hdc;
3095 INT enumed;
3097 /* Report only once */
3098 if(!pGetGlyphIndicesA)
3099 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3101 hdc = GetDC(0);
3103 memset(&lf, 0, sizeof(lf));
3104 lf.lfCharSet = DEFAULT_CHARSET;
3105 enumed = 0;
3106 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3107 trace("Tested metrics of %d truetype fonts\n", enumed);
3109 ReleaseDC(0, hdc);
3112 static void test_nonexistent_font(void)
3114 static const struct
3116 const char *name;
3117 int charset;
3118 } font_subst[] =
3120 { "Times New Roman Baltic", 186 },
3121 { "Times New Roman CE", 238 },
3122 { "Times New Roman CYR", 204 },
3123 { "Times New Roman Greek", 161 },
3124 { "Times New Roman TUR", 162 }
3126 LOGFONTA lf;
3127 HDC hdc;
3128 HFONT hfont;
3129 CHARSETINFO csi;
3130 INT cs, expected_cs, i;
3131 char buf[LF_FACESIZE];
3133 if (!is_truetype_font_installed("Arial") ||
3134 !is_truetype_font_installed("Times New Roman"))
3136 skip("Arial or Times New Roman not installed\n");
3137 return;
3140 expected_cs = GetACP();
3141 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3143 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3144 return;
3146 expected_cs = csi.ciCharset;
3147 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3149 hdc = GetDC(0);
3151 memset(&lf, 0, sizeof(lf));
3152 lf.lfHeight = 100;
3153 lf.lfWeight = FW_REGULAR;
3154 lf.lfCharSet = ANSI_CHARSET;
3155 lf.lfPitchAndFamily = FF_SWISS;
3156 strcpy(lf.lfFaceName, "Nonexistent font");
3157 hfont = CreateFontIndirectA(&lf);
3158 hfont = SelectObject(hdc, hfont);
3159 GetTextFaceA(hdc, sizeof(buf), buf);
3160 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3161 cs = GetTextCharset(hdc);
3162 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3163 DeleteObject(SelectObject(hdc, hfont));
3165 memset(&lf, 0, sizeof(lf));
3166 lf.lfHeight = -13;
3167 lf.lfWeight = FW_DONTCARE;
3168 strcpy(lf.lfFaceName, "Nonexistent font");
3169 hfont = CreateFontIndirectA(&lf);
3170 hfont = SelectObject(hdc, hfont);
3171 GetTextFaceA(hdc, sizeof(buf), buf);
3172 todo_wine /* Wine uses Arial for all substitutions */
3173 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3174 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3175 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3176 "Got %s\n", buf);
3177 cs = GetTextCharset(hdc);
3178 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3179 DeleteObject(SelectObject(hdc, hfont));
3181 memset(&lf, 0, sizeof(lf));
3182 lf.lfHeight = -13;
3183 lf.lfWeight = FW_REGULAR;
3184 strcpy(lf.lfFaceName, "Nonexistent font");
3185 hfont = CreateFontIndirectA(&lf);
3186 hfont = SelectObject(hdc, hfont);
3187 GetTextFaceA(hdc, sizeof(buf), buf);
3188 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3189 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3190 cs = GetTextCharset(hdc);
3191 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3192 DeleteObject(SelectObject(hdc, hfont));
3194 memset(&lf, 0, sizeof(lf));
3195 lf.lfHeight = -13;
3196 lf.lfWeight = FW_DONTCARE;
3197 strcpy(lf.lfFaceName, "Times New Roman");
3198 hfont = CreateFontIndirectA(&lf);
3199 hfont = SelectObject(hdc, hfont);
3200 GetTextFaceA(hdc, sizeof(buf), buf);
3201 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3202 cs = GetTextCharset(hdc);
3203 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3204 DeleteObject(SelectObject(hdc, hfont));
3206 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3208 memset(&lf, 0, sizeof(lf));
3209 lf.lfHeight = -13;
3210 lf.lfWeight = FW_REGULAR;
3211 strcpy(lf.lfFaceName, font_subst[i].name);
3212 hfont = CreateFontIndirectA(&lf);
3213 hfont = SelectObject(hdc, hfont);
3214 cs = GetTextCharset(hdc);
3215 if (font_subst[i].charset == expected_cs)
3217 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3218 GetTextFaceA(hdc, sizeof(buf), buf);
3219 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3221 else
3223 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3224 GetTextFaceA(hdc, sizeof(buf), buf);
3225 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3226 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3228 DeleteObject(SelectObject(hdc, hfont));
3230 memset(&lf, 0, sizeof(lf));
3231 lf.lfHeight = -13;
3232 lf.lfWeight = FW_DONTCARE;
3233 strcpy(lf.lfFaceName, font_subst[i].name);
3234 hfont = CreateFontIndirectA(&lf);
3235 hfont = SelectObject(hdc, hfont);
3236 GetTextFaceA(hdc, sizeof(buf), buf);
3237 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3238 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3239 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3240 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3241 "got %s for font %s\n", buf, font_subst[i].name);
3242 cs = GetTextCharset(hdc);
3243 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3244 DeleteObject(SelectObject(hdc, hfont));
3247 ReleaseDC(0, hdc);
3250 static void test_GdiRealizationInfo(void)
3252 HDC hdc;
3253 DWORD info[4];
3254 BOOL r;
3255 HFONT hfont, hfont_old;
3256 LOGFONTA lf;
3258 if(!pGdiRealizationInfo)
3260 win_skip("GdiRealizationInfo not available\n");
3261 return;
3264 hdc = GetDC(0);
3266 memset(info, 0xcc, sizeof(info));
3267 r = pGdiRealizationInfo(hdc, info);
3268 ok(r != 0, "ret 0\n");
3269 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3270 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3272 if (!is_truetype_font_installed("Arial"))
3274 skip("skipping GdiRealizationInfo with truetype font\n");
3275 goto end;
3278 memset(&lf, 0, sizeof(lf));
3279 strcpy(lf.lfFaceName, "Arial");
3280 lf.lfHeight = 20;
3281 lf.lfWeight = FW_NORMAL;
3282 hfont = CreateFontIndirectA(&lf);
3283 hfont_old = SelectObject(hdc, hfont);
3285 memset(info, 0xcc, sizeof(info));
3286 r = pGdiRealizationInfo(hdc, info);
3287 ok(r != 0, "ret 0\n");
3288 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3289 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3291 DeleteObject(SelectObject(hdc, hfont_old));
3293 end:
3294 ReleaseDC(0, hdc);
3297 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3298 the nul in the count of characters copied when the face name buffer is not
3299 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3300 always includes it. */
3301 static void test_GetTextFace(void)
3303 static const char faceA[] = "Tahoma";
3304 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3305 LOGFONTA fA = {0};
3306 LOGFONTW fW = {0};
3307 char bufA[LF_FACESIZE];
3308 WCHAR bufW[LF_FACESIZE];
3309 HFONT f, g;
3310 HDC dc;
3311 int n;
3313 if(!is_font_installed("Tahoma"))
3315 skip("Tahoma is not installed so skipping this test\n");
3316 return;
3319 /* 'A' case. */
3320 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3321 f = CreateFontIndirectA(&fA);
3322 ok(f != NULL, "CreateFontIndirectA failed\n");
3324 dc = GetDC(NULL);
3325 g = SelectObject(dc, f);
3326 n = GetTextFaceA(dc, sizeof bufA, bufA);
3327 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3328 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3330 /* Play with the count arg. */
3331 bufA[0] = 'x';
3332 n = GetTextFaceA(dc, 0, bufA);
3333 ok(n == 0, "GetTextFaceA returned %d\n", n);
3334 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3336 bufA[0] = 'x';
3337 n = GetTextFaceA(dc, 1, bufA);
3338 ok(n == 0, "GetTextFaceA returned %d\n", n);
3339 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3341 bufA[0] = 'x'; bufA[1] = 'y';
3342 n = GetTextFaceA(dc, 2, bufA);
3343 ok(n == 1, "GetTextFaceA returned %d\n", n);
3344 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3346 n = GetTextFaceA(dc, 0, NULL);
3347 ok(n == sizeof faceA ||
3348 broken(n == 0), /* win98, winMe */
3349 "GetTextFaceA returned %d\n", n);
3351 DeleteObject(SelectObject(dc, g));
3352 ReleaseDC(NULL, dc);
3354 /* 'W' case. */
3355 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3356 SetLastError(0xdeadbeef);
3357 f = CreateFontIndirectW(&fW);
3358 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3360 win_skip("CreateFontIndirectW is not implemented\n");
3361 return;
3363 ok(f != NULL, "CreateFontIndirectW failed\n");
3365 dc = GetDC(NULL);
3366 g = SelectObject(dc, f);
3367 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3368 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3369 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3371 /* Play with the count arg. */
3372 bufW[0] = 'x';
3373 n = GetTextFaceW(dc, 0, bufW);
3374 ok(n == 0, "GetTextFaceW returned %d\n", n);
3375 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3377 bufW[0] = 'x';
3378 n = GetTextFaceW(dc, 1, bufW);
3379 ok(n == 1, "GetTextFaceW returned %d\n", n);
3380 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3382 bufW[0] = 'x'; bufW[1] = 'y';
3383 n = GetTextFaceW(dc, 2, bufW);
3384 ok(n == 2, "GetTextFaceW returned %d\n", n);
3385 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3387 n = GetTextFaceW(dc, 0, NULL);
3388 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3390 DeleteObject(SelectObject(dc, g));
3391 ReleaseDC(NULL, dc);
3394 static void test_orientation(void)
3396 static const char test_str[11] = "Test String";
3397 HDC hdc;
3398 LOGFONTA lf;
3399 HFONT hfont, old_hfont;
3400 SIZE size;
3402 if (!is_truetype_font_installed("Arial"))
3404 skip("Arial is not installed\n");
3405 return;
3408 hdc = CreateCompatibleDC(0);
3409 memset(&lf, 0, sizeof(lf));
3410 lstrcpyA(lf.lfFaceName, "Arial");
3411 lf.lfHeight = 72;
3412 lf.lfOrientation = lf.lfEscapement = 900;
3413 hfont = create_font("orientation", &lf);
3414 old_hfont = SelectObject(hdc, hfont);
3415 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3416 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3417 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3418 SelectObject(hdc, old_hfont);
3419 DeleteObject(hfont);
3420 DeleteDC(hdc);
3423 static void test_oemcharset(void)
3425 HDC hdc;
3426 LOGFONTA lf, clf;
3427 HFONT hfont, old_hfont;
3428 int charset;
3430 hdc = CreateCompatibleDC(0);
3431 ZeroMemory(&lf, sizeof(lf));
3432 lf.lfHeight = 12;
3433 lf.lfCharSet = OEM_CHARSET;
3434 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3435 lstrcpyA(lf.lfFaceName, "Terminal");
3436 hfont = CreateFontIndirectA(&lf);
3437 old_hfont = SelectObject(hdc, hfont);
3438 charset = GetTextCharset(hdc);
3439 todo_wine
3440 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3441 hfont = SelectObject(hdc, old_hfont);
3442 GetObjectA(hfont, sizeof(clf), &clf);
3443 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3444 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3445 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3446 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3447 DeleteObject(hfont);
3448 DeleteDC(hdc);
3451 static void test_GetGlyphOutline(void)
3453 HDC hdc;
3454 GLYPHMETRICS gm, gm2;
3455 LOGFONTA lf;
3456 HFONT hfont, old_hfont;
3457 INT ret, ret2;
3458 static const struct
3460 UINT cs;
3461 UINT a;
3462 UINT w;
3463 } c[] =
3465 {ANSI_CHARSET, 0x30, 0x30},
3466 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3467 {HANGEUL_CHARSET, 0x8141, 0xac02},
3468 {JOHAB_CHARSET, 0x8446, 0x3135},
3469 {GB2312_CHARSET, 0x8141, 0x4e04},
3470 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3472 UINT i;
3474 if (!is_truetype_font_installed("Tahoma"))
3476 skip("Tahoma is not installed\n");
3477 return;
3480 hdc = CreateCompatibleDC(0);
3481 memset(&lf, 0, sizeof(lf));
3482 lf.lfHeight = 72;
3483 lstrcpyA(lf.lfFaceName, "Tahoma");
3484 SetLastError(0xdeadbeef);
3485 hfont = CreateFontIndirectA(&lf);
3486 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3487 old_hfont = SelectObject(hdc, hfont);
3489 memset(&gm, 0, sizeof(gm));
3490 SetLastError(0xdeadbeef);
3491 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3492 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3494 memset(&gm, 0, sizeof(gm));
3495 SetLastError(0xdeadbeef);
3496 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3497 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3498 ok(GetLastError() == 0xdeadbeef ||
3499 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3500 "expected 0xdeadbeef, got %u\n", GetLastError());
3502 memset(&gm, 0, sizeof(gm));
3503 SetLastError(0xdeadbeef);
3504 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3505 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3506 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3508 memset(&gm, 0, sizeof(gm));
3509 SetLastError(0xdeadbeef);
3510 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3511 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3513 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3514 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3517 /* test for needed buffer size request on space char */
3518 memset(&gm, 0, sizeof(gm));
3519 SetLastError(0xdeadbeef);
3520 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3521 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3522 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3524 /* requesting buffer size for space char + error */
3525 memset(&gm, 0, sizeof(gm));
3526 SetLastError(0xdeadbeef);
3527 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3528 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3530 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3531 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3534 SelectObject(hdc, old_hfont);
3535 DeleteObject(hfont);
3537 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3539 lf.lfFaceName[0] = '\0';
3540 lf.lfCharSet = c[i].cs;
3541 lf.lfPitchAndFamily = 0;
3542 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3544 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3545 continue;
3548 old_hfont = SelectObject(hdc, hfont);
3550 /* expected to ignore superfluous bytes (sigle-byte character) */
3551 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3552 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3553 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3555 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3556 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3557 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3559 /* expected to ignore superfluous bytes (double-byte character) */
3560 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3561 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3562 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3563 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3565 /* expected to match wide-char version results */
3566 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3567 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3569 hfont = SelectObject(hdc, old_hfont);
3570 DeleteObject(hfont);
3573 DeleteDC(hdc);
3576 /* bug #9995: there is a limit to the character width that can be specified */
3577 static void test_GetTextMetrics2(const char *fontname, int font_height)
3579 HFONT of, hf;
3580 HDC hdc;
3581 TEXTMETRICA tm;
3582 BOOL ret;
3583 int ave_width, height, width, ratio, scale;
3585 if (!is_truetype_font_installed( fontname)) {
3586 skip("%s is not installed\n", fontname);
3587 return;
3589 hdc = CreateCompatibleDC(0);
3590 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3591 /* select width = 0 */
3592 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3593 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3594 DEFAULT_QUALITY, VARIABLE_PITCH,
3595 fontname);
3596 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3597 of = SelectObject( hdc, hf);
3598 ret = GetTextMetricsA( hdc, &tm);
3599 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3600 height = tm.tmHeight;
3601 ave_width = tm.tmAveCharWidth;
3602 SelectObject( hdc, of);
3603 DeleteObject( hf);
3605 trace("height %d, ave width %d\n", height, ave_width);
3607 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3609 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3610 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3611 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3612 ok(hf != 0, "CreateFont failed\n");
3613 of = SelectObject(hdc, hf);
3614 ret = GetTextMetrics(hdc, &tm);
3615 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3616 SelectObject(hdc, of);
3617 DeleteObject(hf);
3619 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3620 break;
3623 DeleteDC(hdc);
3625 ratio = width / height;
3626 scale = width / ave_width;
3628 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3629 width, height, ratio, width, ave_width, scale);
3631 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3634 static void test_CreateFontIndirect(void)
3636 LOGFONTA lf, getobj_lf;
3637 int ret, i;
3638 HFONT hfont;
3639 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3641 memset(&lf, 0, sizeof(lf));
3642 lf.lfCharSet = ANSI_CHARSET;
3643 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3644 lf.lfHeight = 16;
3645 lf.lfWidth = 16;
3646 lf.lfQuality = DEFAULT_QUALITY;
3647 lf.lfItalic = FALSE;
3648 lf.lfWeight = FW_DONTCARE;
3650 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3652 lstrcpyA(lf.lfFaceName, TestName[i]);
3653 hfont = CreateFontIndirectA(&lf);
3654 ok(hfont != 0, "CreateFontIndirectA failed\n");
3655 SetLastError(0xdeadbeef);
3656 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3657 ok(ret, "GetObject failed: %d\n", GetLastError());
3658 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3659 ok(lf.lfWeight == getobj_lf.lfWeight ||
3660 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3661 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3662 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3663 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3664 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3665 DeleteObject(hfont);
3669 static void test_CreateFontIndirectEx(void)
3671 ENUMLOGFONTEXDVA lfex;
3672 HFONT hfont;
3674 if (!pCreateFontIndirectExA)
3676 win_skip("CreateFontIndirectExA is not available\n");
3677 return;
3680 if (!is_truetype_font_installed("Arial"))
3682 skip("Arial is not installed\n");
3683 return;
3686 SetLastError(0xdeadbeef);
3687 hfont = pCreateFontIndirectExA(NULL);
3688 ok(hfont == NULL, "got %p\n", hfont);
3689 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3691 memset(&lfex, 0, sizeof(lfex));
3692 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3693 hfont = pCreateFontIndirectExA(&lfex);
3694 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3695 if (hfont)
3696 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3697 DeleteObject(hfont);
3700 static void free_font(void *font)
3702 UnmapViewOfFile(font);
3705 static void *load_font(const char *font_name, DWORD *font_size)
3707 char file_name[MAX_PATH];
3708 HANDLE file, mapping;
3709 void *font;
3711 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3712 strcat(file_name, "\\fonts\\");
3713 strcat(file_name, font_name);
3715 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3716 if (file == INVALID_HANDLE_VALUE) return NULL;
3718 *font_size = GetFileSize(file, NULL);
3720 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3721 if (!mapping)
3723 CloseHandle(file);
3724 return NULL;
3727 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3729 CloseHandle(file);
3730 CloseHandle(mapping);
3731 return font;
3734 static void test_AddFontMemResource(void)
3736 void *font;
3737 DWORD font_size, num_fonts;
3738 HANDLE ret;
3739 BOOL bRet;
3741 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3743 win_skip("AddFontMemResourceEx is not available on this platform\n");
3744 return;
3747 font = load_font("sserife.fon", &font_size);
3748 if (!font)
3750 skip("Unable to locate and load font sserife.fon\n");
3751 return;
3754 SetLastError(0xdeadbeef);
3755 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3756 ok(!ret, "AddFontMemResourceEx should fail\n");
3757 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3758 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3759 GetLastError());
3761 SetLastError(0xdeadbeef);
3762 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3763 ok(!ret, "AddFontMemResourceEx should fail\n");
3764 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3765 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3766 GetLastError());
3768 SetLastError(0xdeadbeef);
3769 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3770 ok(!ret, "AddFontMemResourceEx should fail\n");
3771 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3772 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3773 GetLastError());
3775 SetLastError(0xdeadbeef);
3776 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3777 ok(!ret, "AddFontMemResourceEx should fail\n");
3778 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3779 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3780 GetLastError());
3782 SetLastError(0xdeadbeef);
3783 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3784 ok(!ret, "AddFontMemResourceEx should fail\n");
3785 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3786 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3787 GetLastError());
3789 SetLastError(0xdeadbeef);
3790 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3791 ok(!ret, "AddFontMemResourceEx should fail\n");
3792 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3793 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3794 GetLastError());
3796 num_fonts = 0xdeadbeef;
3797 SetLastError(0xdeadbeef);
3798 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3799 ok(!ret, "AddFontMemResourceEx should fail\n");
3800 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3801 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3802 GetLastError());
3803 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3805 if (0) /* hangs under windows 2000 */
3807 num_fonts = 0xdeadbeef;
3808 SetLastError(0xdeadbeef);
3809 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3810 ok(!ret, "AddFontMemResourceEx should fail\n");
3811 ok(GetLastError() == 0xdeadbeef,
3812 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3813 GetLastError());
3814 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3817 num_fonts = 0xdeadbeef;
3818 SetLastError(0xdeadbeef);
3819 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3820 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3821 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3822 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3824 free_font(font);
3826 SetLastError(0xdeadbeef);
3827 bRet = pRemoveFontMemResourceEx(ret);
3828 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3830 /* test invalid pointer to number of loaded fonts */
3831 font = load_font("sserife.fon", &font_size);
3832 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3834 SetLastError(0xdeadbeef);
3835 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3836 ok(!ret, "AddFontMemResourceEx should fail\n");
3837 ok(GetLastError() == 0xdeadbeef,
3838 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3839 GetLastError());
3841 SetLastError(0xdeadbeef);
3842 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3843 ok(!ret, "AddFontMemResourceEx should fail\n");
3844 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3845 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3846 GetLastError());
3848 free_font(font);
3851 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3853 LOGFONT *lf;
3855 if (type != TRUETYPE_FONTTYPE) return 1;
3857 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3859 lf = (LOGFONT *)lparam;
3860 *lf = *elf;
3861 return 0;
3864 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3866 int ret;
3867 LOGFONT *lf;
3869 if (type != TRUETYPE_FONTTYPE) return 1;
3871 lf = (LOGFONT *)lparam;
3872 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3873 if(ret == 0)
3875 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3876 *lf = *elf;
3877 return 0;
3879 return 1;
3882 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3884 return lparam;
3887 static void test_EnumFonts(void)
3889 int ret;
3890 LOGFONT lf;
3891 HDC hdc;
3893 if (!is_truetype_font_installed("Arial"))
3895 skip("Arial is not installed\n");
3896 return;
3899 /* Windows uses localized font face names, so Arial Bold won't be found */
3900 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3902 skip("User locale is not English, skipping the test\n");
3903 return;
3906 hdc = CreateCompatibleDC(0);
3908 /* check that the enumproc's retval is returned */
3909 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
3910 ok(ret == 0xcafe, "got %08x\n", ret);
3912 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3913 ok(!ret, "font Arial is not enumerated\n");
3914 ret = strcmp(lf.lfFaceName, "Arial");
3915 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3916 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3918 lstrcpy(lf.lfFaceName, "Arial");
3919 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3920 ok(!ret, "font Arial is not enumerated\n");
3921 ret = strcmp(lf.lfFaceName, "Arial");
3922 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3923 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3925 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3926 ok(!ret, "font Arial Bold is not enumerated\n");
3927 ret = strcmp(lf.lfFaceName, "Arial");
3928 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3929 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3931 lstrcpy(lf.lfFaceName, "Arial Bold");
3932 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3933 ok(ret, "font Arial Bold should not be enumerated\n");
3935 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3936 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3937 ret = strcmp(lf.lfFaceName, "Arial");
3938 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3939 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3941 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3942 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3943 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3945 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3946 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3948 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3949 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3950 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3952 DeleteDC(hdc);
3955 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3957 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3958 const char *fullname = (const char *)lParam;
3960 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3962 return 1;
3965 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3967 HDC hdc = GetDC(0);
3968 BOOL ret = FALSE;
3970 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3971 ret = TRUE;
3973 ReleaseDC(0, hdc);
3974 return ret;
3977 static void test_fullname(void)
3979 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3980 char buf[LF_FULLFACESIZE];
3981 HFONT hfont, of;
3982 LOGFONTA lf;
3983 HDC hdc;
3984 int i;
3986 hdc = CreateCompatibleDC(0);
3987 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3989 memset(&lf, 0, sizeof(lf));
3990 lf.lfCharSet = ANSI_CHARSET;
3991 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3992 lf.lfHeight = 16;
3993 lf.lfWidth = 16;
3994 lf.lfQuality = DEFAULT_QUALITY;
3995 lf.lfItalic = FALSE;
3996 lf.lfWeight = FW_DONTCARE;
3998 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4000 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4002 skip("%s is not installed\n", TestName[i]);
4003 continue;
4006 lstrcpyA(lf.lfFaceName, TestName[i]);
4007 hfont = CreateFontIndirectA(&lf);
4008 ok(hfont != 0, "CreateFontIndirectA failed\n");
4010 of = SelectObject(hdc, hfont);
4011 buf[0] = 0;
4012 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
4013 "face full name could not be read\n");
4014 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
4015 SelectObject(hdc, of);
4016 DeleteObject(hfont);
4018 DeleteDC(hdc);
4021 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4023 char tmp_path[MAX_PATH];
4024 HRSRC rsrc;
4025 void *rsrc_data;
4026 DWORD rsrc_size;
4027 HANDLE hfile;
4028 BOOL ret;
4030 SetLastError(0xdeadbeef);
4031 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4032 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4033 if (!rsrc) return FALSE;
4034 SetLastError(0xdeadbeef);
4035 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4036 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4037 if (!rsrc_data) return FALSE;
4038 SetLastError(0xdeadbeef);
4039 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4040 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4041 if (!rsrc_size) return FALSE;
4043 SetLastError(0xdeadbeef);
4044 ret = GetTempPath(MAX_PATH, tmp_path);
4045 ok(ret, "GetTempPath() error %d\n", GetLastError());
4046 SetLastError(0xdeadbeef);
4047 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4048 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4050 SetLastError(0xdeadbeef);
4051 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4052 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4053 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4055 SetLastError(0xdeadbeef);
4056 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4057 ok(ret, "WriteFile() error %d\n", GetLastError());
4059 CloseHandle(hfile);
4060 return ret;
4063 static void test_CreateScalableFontResource(void)
4065 char ttf_name[MAX_PATH];
4066 char tmp_path[MAX_PATH];
4067 char fot_name[MAX_PATH];
4068 char *file_part;
4069 DWORD ret;
4071 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4073 win_skip("AddFontResourceExA is not available on this platform\n");
4074 return;
4077 if (!write_ttf_file("wine_test.ttf", ttf_name))
4079 skip("Failed to create ttf file for testing\n");
4080 return;
4083 trace("created %s\n", ttf_name);
4085 ret = is_truetype_font_installed("wine_test");
4086 ok(!ret, "font wine_test should not be enumerated\n");
4088 ret = GetTempPath(MAX_PATH, tmp_path);
4089 ok(ret, "GetTempPath() error %d\n", GetLastError());
4090 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4091 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4093 ret = GetFileAttributes(fot_name);
4094 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4096 SetLastError(0xdeadbeef);
4097 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4098 ok(!ret, "CreateScalableFontResource() should fail\n");
4099 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4101 SetLastError(0xdeadbeef);
4102 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4103 ok(!ret, "CreateScalableFontResource() should fail\n");
4104 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4106 file_part = strrchr(ttf_name, '\\');
4107 SetLastError(0xdeadbeef);
4108 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4109 ok(!ret, "CreateScalableFontResource() should fail\n");
4110 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4112 SetLastError(0xdeadbeef);
4113 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4114 ok(!ret, "CreateScalableFontResource() should fail\n");
4115 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4117 SetLastError(0xdeadbeef);
4118 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4119 ok(!ret, "CreateScalableFontResource() should fail\n");
4120 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4122 ret = DeleteFile(fot_name);
4123 ok(ret, "DeleteFile() error %d\n", GetLastError());
4125 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4126 todo_wine
4127 ok(!ret, "RemoveFontResourceEx() should fail\n");
4129 /* test public font resource */
4130 SetLastError(0xdeadbeef);
4131 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4132 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4134 ret = is_truetype_font_installed("wine_test");
4135 ok(!ret, "font wine_test should not be enumerated\n");
4137 SetLastError(0xdeadbeef);
4138 ret = pAddFontResourceExA(fot_name, 0, 0);
4139 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4141 ret = is_truetype_font_installed("wine_test");
4142 ok(ret, "font wine_test should be enumerated\n");
4144 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4145 todo_wine
4146 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4148 SetLastError(0xdeadbeef);
4149 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4150 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4152 ret = is_truetype_font_installed("wine_test");
4153 todo_wine
4154 ok(!ret, "font wine_test should not be enumerated\n");
4156 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4157 if (ret)
4159 /* remove once RemoveFontResource is implemented */
4160 DeleteFile(fot_name);
4161 DeleteFile(ttf_name);
4162 return;
4165 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4166 ok(!ret, "RemoveFontResourceEx() should fail\n");
4168 DeleteFile(fot_name);
4170 /* test hidden font resource */
4171 SetLastError(0xdeadbeef);
4172 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4173 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4175 ret = is_truetype_font_installed("wine_test");
4176 ok(!ret, "font wine_test should not be enumerated\n");
4178 SetLastError(0xdeadbeef);
4179 ret = pAddFontResourceExA(fot_name, 0, 0);
4180 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4182 ret = is_truetype_font_installed("wine_test");
4183 ok(!ret, "font wine_test should not be enumerated\n");
4185 /* XP allows removing a private font added with 0 flags */
4186 SetLastError(0xdeadbeef);
4187 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4188 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4190 ret = is_truetype_font_installed("wine_test");
4191 ok(!ret, "font wine_test should not be enumerated\n");
4193 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4194 ok(!ret, "RemoveFontResourceEx() should fail\n");
4196 DeleteFile(fot_name);
4197 DeleteFile(ttf_name);
4200 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4202 LOGFONTA lf;
4203 HFONT hfont, hfont_prev;
4204 HDC hdc;
4205 char facename[100];
4206 DWORD ret;
4207 static const WCHAR str[] = { 0x2025 };
4209 *installed = is_truetype_font_installed(name);
4211 lf.lfHeight = -18;
4212 lf.lfWidth = 0;
4213 lf.lfEscapement = 0;
4214 lf.lfOrientation = 0;
4215 lf.lfWeight = FW_DONTCARE;
4216 lf.lfItalic = 0;
4217 lf.lfUnderline = 0;
4218 lf.lfStrikeOut = 0;
4219 lf.lfCharSet = DEFAULT_CHARSET;
4220 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4221 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4222 lf.lfQuality = DEFAULT_QUALITY;
4223 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4224 strcpy(lf.lfFaceName, name);
4226 hfont = CreateFontIndirectA(&lf);
4227 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4229 hdc = GetDC(NULL);
4231 hfont_prev = SelectObject(hdc, hfont);
4232 ok(hfont_prev != NULL, "SelectObject failed\n");
4234 ret = GetTextFaceA(hdc, sizeof facename, facename);
4235 ok(ret, "GetTextFaceA failed\n");
4236 *selected = !strcmp(facename, name);
4238 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4239 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4240 if (!*selected)
4241 memset(gm, 0, sizeof *gm);
4243 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4244 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4246 SelectObject(hdc, hfont_prev);
4247 DeleteObject(hfont);
4248 ReleaseDC(NULL, hdc);
4251 static void test_vertical_font(void)
4253 char ttf_name[MAX_PATH];
4254 int num;
4255 BOOL ret, installed, selected;
4256 GLYPHMETRICS gm;
4257 WORD hgi, vgi;
4259 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4261 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4262 return;
4265 if (!write_ttf_file("vertical.ttf", ttf_name))
4267 skip("Failed to create ttf file for testing\n");
4268 return;
4271 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4272 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4274 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4275 ok(installed, "@WineTestVertical is not installed\n");
4276 ok(selected, "@WineTestVertical is not selected\n");
4277 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4278 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4279 gm.gmBlackBoxX, gm.gmBlackBoxY);
4281 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4282 ok(installed, "@@WineTestVertical is not installed\n");
4283 ok(selected, "@@WineTestVertical is not selected\n");
4284 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4285 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4286 gm.gmBlackBoxX, gm.gmBlackBoxY);
4288 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4290 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4291 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4293 DeleteFile(ttf_name);
4296 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4297 DWORD type, LPARAM lParam)
4299 if (lf->lfFaceName[0] == '@') {
4300 return 0;
4302 return 1;
4305 static void test_east_asian_font_selection(void)
4307 HDC hdc;
4308 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4309 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4310 size_t i;
4312 hdc = GetDC(NULL);
4314 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4316 LOGFONTA lf;
4317 HFONT hfont;
4318 char face_name[LF_FACESIZE];
4319 int ret;
4321 memset(&lf, 0, sizeof lf);
4322 lf.lfFaceName[0] = '\0';
4323 lf.lfCharSet = charset[i];
4325 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4327 skip("Vertical font for charset %u is not installed\n", charset[i]);
4328 continue;
4331 hfont = CreateFontIndirectA(&lf);
4332 hfont = SelectObject(hdc, hfont);
4333 memset(face_name, 0, sizeof face_name);
4334 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4335 ok(ret && face_name[0] != '@',
4336 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4337 DeleteObject(SelectObject(hdc, hfont));
4339 memset(&lf, 0, sizeof lf);
4340 strcpy(lf.lfFaceName, "@");
4341 lf.lfCharSet = charset[i];
4342 hfont = CreateFontIndirectA(&lf);
4343 hfont = SelectObject(hdc, hfont);
4344 memset(face_name, 0, sizeof face_name);
4345 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4346 ok(ret && face_name[0] == '@',
4347 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4348 DeleteObject(SelectObject(hdc, hfont));
4350 ReleaseDC(NULL, hdc);
4353 static int get_font_dpi(const LOGFONT *lf)
4355 HDC hdc = CreateCompatibleDC(0);
4356 HFONT hfont;
4357 TEXTMETRIC tm;
4358 int ret;
4360 hfont = CreateFontIndirect(lf);
4361 ok(hfont != 0, "CreateFontIndirect failed\n");
4363 SelectObject(hdc, hfont);
4364 ret = GetTextMetrics(hdc, &tm);
4365 ok(ret, "GetTextMetrics failed\n");
4366 ret = tm.tmDigitizedAspectX;
4368 DeleteDC(hdc);
4369 DeleteObject(hfont);
4371 return ret;
4374 static void test_stock_fonts(void)
4376 static const int font[] =
4378 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4379 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4381 static const struct test_data
4383 int charset, weight, height, dpi;
4384 const char face_name[LF_FACESIZE];
4385 } td[][11] =
4387 { /* ANSI_FIXED_FONT */
4388 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4389 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4390 { 0 }
4392 { /* ANSI_VAR_FONT */
4393 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4394 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4395 { 0 }
4397 { /* SYSTEM_FONT */
4398 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4399 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4400 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4401 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4402 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4403 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4404 { 0 }
4406 { /* DEVICE_DEFAULT_FONT */
4407 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4408 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4409 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4410 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4411 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4412 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4413 { 0 }
4415 { /* DEFAULT_GUI_FONT */
4416 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4417 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4418 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4419 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4420 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4421 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4422 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4423 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4424 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4425 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4426 { 0 }
4429 int i, j;
4431 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4433 HFONT hfont;
4434 LOGFONT lf;
4435 int ret;
4437 hfont = GetStockObject(font[i]);
4438 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4440 ret = GetObject(hfont, sizeof(lf), &lf);
4441 if (ret != sizeof(lf))
4443 /* NT4 */
4444 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4445 continue;
4448 for (j = 0; td[i][j].face_name[0] != 0; j++)
4450 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4452 continue;
4455 ret = get_font_dpi(&lf);
4456 if (ret != td[i][j].dpi)
4458 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4459 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4460 continue;
4463 if ((font[i] == DEVICE_DEFAULT_FONT || font[i] == SYSTEM_FONT) && td[i][j].charset != DEFAULT_CHARSET)
4464 todo_wine ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4465 else
4466 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4467 if ((font[i] == DEFAULT_GUI_FONT && td[i][j].charset != DEFAULT_CHARSET) ||
4468 ((font[i] == DEVICE_DEFAULT_FONT || font[i] == SYSTEM_FONT) && td[i][j].charset == SHIFTJIS_CHARSET))
4469 todo_wine ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4470 else
4471 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4472 if (td[i][j].face_name[0] == '?')
4474 /* Wine doesn't have this font, skip this case for now.
4475 Actually, the face name is localized on Windows and varies
4476 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4477 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4479 else
4481 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);
4483 break;
4488 START_TEST(font)
4490 init();
4492 test_stock_fonts();
4493 test_logfont();
4494 test_bitmap_font();
4495 test_outline_font();
4496 test_bitmap_font_metrics();
4497 test_GdiGetCharDimensions();
4498 test_GetCharABCWidths();
4499 test_text_extents();
4500 test_GetGlyphIndices();
4501 test_GetKerningPairs();
4502 test_GetOutlineTextMetrics();
4503 test_SetTextJustification();
4504 test_font_charset();
4505 test_GetFontUnicodeRanges();
4506 test_nonexistent_font();
4507 test_orientation();
4508 test_height_selection();
4509 test_AddFontMemResource();
4510 test_EnumFonts();
4512 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4513 * I'd like to avoid them in this test.
4515 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4516 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4517 if (is_truetype_font_installed("Arial Black") &&
4518 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4520 test_EnumFontFamilies("", ANSI_CHARSET);
4521 test_EnumFontFamilies("", SYMBOL_CHARSET);
4522 test_EnumFontFamilies("", DEFAULT_CHARSET);
4524 else
4525 skip("Arial Black or Symbol/Wingdings is not installed\n");
4526 test_EnumFontFamiliesEx_default_charset();
4527 test_GetTextMetrics();
4528 test_GdiRealizationInfo();
4529 test_GetTextFace();
4530 test_GetGlyphOutline();
4531 test_GetTextMetrics2("Tahoma", -11);
4532 test_GetTextMetrics2("Tahoma", -55);
4533 test_GetTextMetrics2("Tahoma", -110);
4534 test_GetTextMetrics2("Arial", -11);
4535 test_GetTextMetrics2("Arial", -55);
4536 test_GetTextMetrics2("Arial", -110);
4537 test_CreateFontIndirect();
4538 test_CreateFontIndirectEx();
4539 test_oemcharset();
4540 test_fullname();
4541 test_east_asian_font_selection();
4543 /* These tests should be last test until RemoveFontResource
4544 * is properly implemented.
4546 test_vertical_font();
4547 test_CreateScalableFontResource();