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
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
46 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
48 static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext,
49 LPINT nfit, LPINT dxs, LPSIZE size );
50 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
51 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
52 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
53 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
54 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
55 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
57 static HMODULE hgdi32 = 0;
58 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
59 static WORD system_lang_id;
61 static void init(void)
63 hgdi32 = GetModuleHandleA("gdi32.dll");
65 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
66 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
67 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
68 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
69 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
70 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
71 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
72 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
73 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
74 pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI");
75 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
76 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
77 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
78 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
79 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
80 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
82 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
85 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
87 if (type != TRUETYPE_FONTTYPE) return 1;
92 static BOOL is_truetype_font_installed(const char *name)
97 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
104 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
109 static BOOL is_font_installed(const char *name)
114 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
121 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
129 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
130 /* NT4 tries to be clever and only returns the minimum length */
131 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
133 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
134 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
135 ok(lf->lfHeight == getobj_lf.lfHeight ||
136 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
137 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
138 ok(lf->lfWidth == getobj_lf.lfWidth ||
139 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
140 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
141 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
142 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
143 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
144 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
145 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
146 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
147 ok(lf->lfWeight == getobj_lf.lfWeight ||
148 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
149 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
150 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
151 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
152 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
153 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
154 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
155 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
156 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
157 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
158 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
159 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
160 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
163 static HFONT create_font(const char* test, const LOGFONTA* lf)
165 HFONT hfont = CreateFontIndirectA(lf);
166 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
168 check_font(test, lf, hfont);
172 static void test_logfont(void)
177 memset(&lf, 0, sizeof lf);
179 lf.lfCharSet = ANSI_CHARSET;
180 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
181 lf.lfWeight = FW_DONTCARE;
184 lf.lfQuality = DEFAULT_QUALITY;
186 lstrcpyA(lf.lfFaceName, "Arial");
187 hfont = create_font("Arial", &lf);
190 memset(&lf, 'A', sizeof(lf));
191 hfont = CreateFontIndirectA(&lf);
192 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
194 lf.lfFaceName[LF_FACESIZE - 1] = 0;
195 check_font("AAA...", &lf, hfont);
199 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
201 if (type & RASTER_FONTTYPE)
203 LOGFONT *lf = (LOGFONT *)lParam;
205 return 0; /* stop enumeration */
208 return 1; /* continue enumeration */
211 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
213 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
214 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
215 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
216 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
217 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
218 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
219 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
220 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
221 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
222 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
223 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
224 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
225 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
226 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
227 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
228 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
229 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
230 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
231 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
232 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
235 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
236 LONG lfWidth, const char *test_str,
237 INT test_str_len, const TEXTMETRICA *tm_orig,
238 const SIZE *size_orig, INT width_of_A_orig,
239 INT scale_x, INT scale_y)
242 OUTLINETEXTMETRIC otm;
245 INT width_of_A, cx, cy;
251 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
253 GetObjectA(hfont, sizeof(lf), &lf);
255 if (GetOutlineTextMetricsA(hdc, 0, NULL))
257 otm.otmSize = sizeof(otm) / 2;
258 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259 ok(ret == sizeof(otm)/2 /* XP */ ||
260 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
262 memset(&otm, 0x1, sizeof(otm));
263 otm.otmSize = sizeof(otm);
264 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
265 ok(ret == sizeof(otm) /* XP */ ||
266 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
268 memset(&tm, 0x2, sizeof(tm));
269 ret = GetTextMetricsA(hdc, &tm);
270 ok(ret, "GetTextMetricsA failed\n");
271 /* the structure size is aligned */
272 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
274 ok(0, "tm != otm\n");
275 compare_tm(&tm, &otm.otmTextMetrics);
278 tm = otm.otmTextMetrics;
279 if (0) /* these metrics are scaled too, but with rounding errors */
281 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
282 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
284 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
285 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
286 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
287 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
288 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
289 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
293 ret = GetTextMetricsA(hdc, &tm);
294 ok(ret, "GetTextMetricsA failed\n");
297 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
298 cy = tm.tmHeight / tm_orig->tmHeight;
299 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
300 lfHeight, scale_x, scale_y, cx, cy);
301 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
302 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
303 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
304 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
305 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
307 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
311 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
314 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
316 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
318 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
319 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
321 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
323 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
326 /* Test how GDI scales bitmap font metrics */
327 static void test_bitmap_font(void)
329 static const char test_str[11] = "Test String";
332 HFONT hfont, old_hfont;
335 INT ret, i, width_orig, height_orig, scale, lfWidth;
337 hdc = CreateCompatibleDC(0);
339 /* "System" has only 1 pixel size defined, otherwise the test breaks */
340 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
344 trace("no bitmap fonts were found, skipping the test\n");
348 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
350 height_orig = bitmap_lf.lfHeight;
351 lfWidth = bitmap_lf.lfWidth;
353 hfont = create_font("bitmap", &bitmap_lf);
354 old_hfont = SelectObject(hdc, hfont);
355 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
356 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
357 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
358 SelectObject(hdc, old_hfont);
361 bitmap_lf.lfHeight = 0;
362 bitmap_lf.lfWidth = 4;
363 hfont = create_font("bitmap", &bitmap_lf);
364 old_hfont = SelectObject(hdc, hfont);
365 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
366 SelectObject(hdc, old_hfont);
369 bitmap_lf.lfHeight = height_orig;
370 bitmap_lf.lfWidth = lfWidth;
372 /* test fractional scaling */
373 for (i = 1; i <= height_orig * 6; i++)
377 bitmap_lf.lfHeight = i;
378 hfont = create_font("fractional", &bitmap_lf);
379 scale = (i + height_orig - 1) / height_orig;
380 nearest_height = scale * height_orig;
381 /* Only jump to the next height if the difference <= 25% original height */
382 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
383 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
384 so we'll not test this particular height. */
385 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
386 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
387 old_hfont = SelectObject(hdc, hfont);
388 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
389 SelectObject(hdc, old_hfont);
393 /* test integer scaling 3x2 */
394 bitmap_lf.lfHeight = height_orig * 2;
395 bitmap_lf.lfWidth *= 3;
396 hfont = create_font("3x2", &bitmap_lf);
397 old_hfont = SelectObject(hdc, hfont);
398 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
399 SelectObject(hdc, old_hfont);
402 /* test integer scaling 3x3 */
403 bitmap_lf.lfHeight = height_orig * 3;
404 bitmap_lf.lfWidth = 0;
405 hfont = create_font("3x3", &bitmap_lf);
406 old_hfont = SelectObject(hdc, hfont);
407 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
408 SelectObject(hdc, old_hfont);
414 /* Test how GDI scales outline font metrics */
415 static void test_outline_font(void)
417 static const char test_str[11] = "Test String";
420 HFONT hfont, old_hfont, old_hfont_2;
421 OUTLINETEXTMETRICA otm;
423 INT width_orig, height_orig, lfWidth;
426 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
430 if (!is_truetype_font_installed("Arial"))
432 skip("Arial is not installed\n");
436 hdc = CreateCompatibleDC(0);
438 memset(&lf, 0, sizeof(lf));
439 strcpy(lf.lfFaceName, "Arial");
441 hfont = create_font("outline", &lf);
442 old_hfont = SelectObject(hdc, hfont);
443 otm.otmSize = sizeof(otm);
444 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
445 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
446 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
448 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
449 SelectObject(hdc, old_hfont);
452 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
453 lf.lfHeight = otm.otmEMSquare;
454 lf.lfHeight = -lf.lfHeight;
455 hfont = create_font("outline", &lf);
456 old_hfont = SelectObject(hdc, hfont);
457 otm.otmSize = sizeof(otm);
458 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
459 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
460 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
461 SelectObject(hdc, old_hfont);
464 height_orig = otm.otmTextMetrics.tmHeight;
465 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
467 /* test integer scaling 3x2 */
468 lf.lfHeight = height_orig * 2;
469 lf.lfWidth = lfWidth * 3;
470 hfont = create_font("3x2", &lf);
471 old_hfont = SelectObject(hdc, hfont);
472 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
473 SelectObject(hdc, old_hfont);
476 /* test integer scaling 3x3 */
477 lf.lfHeight = height_orig * 3;
478 lf.lfWidth = lfWidth * 3;
479 hfont = create_font("3x3", &lf);
480 old_hfont = SelectObject(hdc, hfont);
481 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
482 SelectObject(hdc, old_hfont);
485 /* test integer scaling 1x1 */
486 lf.lfHeight = height_orig * 1;
487 lf.lfWidth = lfWidth * 1;
488 hfont = create_font("1x1", &lf);
489 old_hfont = SelectObject(hdc, hfont);
490 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
491 SelectObject(hdc, old_hfont);
494 /* test integer scaling 1x1 */
495 lf.lfHeight = height_orig;
497 hfont = create_font("1x1", &lf);
498 old_hfont = SelectObject(hdc, hfont);
499 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
501 /* with an identity matrix */
502 memset(&gm, 0, sizeof(gm));
503 SetLastError(0xdeadbeef);
504 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
505 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
506 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
507 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
508 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
509 /* with a custom matrix */
510 memset(&gm, 0, sizeof(gm));
511 SetLastError(0xdeadbeef);
512 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
513 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
514 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
515 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
516 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
518 /* Test that changing the DC transformation affects only the font
519 * selected on this DC and doesn't affect the same font selected on
522 hdc_2 = CreateCompatibleDC(0);
523 old_hfont_2 = SelectObject(hdc_2, hfont);
524 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
526 SetMapMode(hdc, MM_ANISOTROPIC);
528 /* font metrics on another DC should be unchanged */
529 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
531 /* test restrictions of compatibility mode GM_COMPATIBLE */
532 /* part 1: rescaling only X should not change font scaling on screen.
533 So compressing the X axis by 2 is not done, and this
534 appears as X scaling of 2 that no one requested. */
535 SetWindowExtEx(hdc, 100, 100, NULL);
536 SetViewportExtEx(hdc, 50, 100, NULL);
537 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
538 /* font metrics on another DC should be unchanged */
539 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
541 /* part 2: rescaling only Y should change font scaling.
542 As also X is scaled by a factor of 2, but this is not
543 requested by the DC transformation, we get a scaling factor
544 of 2 in the X coordinate. */
545 SetViewportExtEx(hdc, 100, 200, NULL);
546 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
550 /* restore scaling */
551 SetMapMode(hdc, MM_TEXT);
553 /* font metrics on another DC should be unchanged */
554 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 SelectObject(hdc_2, old_hfont_2);
559 if (!SetGraphicsMode(hdc, GM_ADVANCED))
561 SelectObject(hdc, old_hfont);
564 skip("GM_ADVANCED is not supported on this platform\n");
575 SetLastError(0xdeadbeef);
576 ret = SetWorldTransform(hdc, &xform);
577 ok(ret, "SetWorldTransform error %u\n", GetLastError());
579 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
581 /* with an identity matrix */
582 memset(&gm, 0, sizeof(gm));
583 SetLastError(0xdeadbeef);
584 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
585 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
586 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
587 pt.x = width_orig; pt.y = 0;
589 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
590 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
591 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
592 /* with a custom matrix */
593 memset(&gm, 0, sizeof(gm));
594 SetLastError(0xdeadbeef);
595 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
596 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
597 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
598 pt.x = width_orig; pt.y = 0;
600 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
601 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
602 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
604 SetLastError(0xdeadbeef);
605 ret = SetMapMode(hdc, MM_LOMETRIC);
606 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
608 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
610 /* with an identity matrix */
611 memset(&gm, 0, sizeof(gm));
612 SetLastError(0xdeadbeef);
613 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
614 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
615 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
616 pt.x = width_orig; pt.y = 0;
618 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
619 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
620 /* with a custom matrix */
621 memset(&gm, 0, sizeof(gm));
622 SetLastError(0xdeadbeef);
623 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
624 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
625 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
626 pt.x = width_orig; pt.y = 0;
628 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
629 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
631 SetLastError(0xdeadbeef);
632 ret = SetMapMode(hdc, MM_TEXT);
633 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
635 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
637 /* with an identity matrix */
638 memset(&gm, 0, sizeof(gm));
639 SetLastError(0xdeadbeef);
640 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
641 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
642 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
643 pt.x = width_orig; pt.y = 0;
645 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
646 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
647 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
648 /* with a custom matrix */
649 memset(&gm, 0, sizeof(gm));
650 SetLastError(0xdeadbeef);
651 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
652 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
653 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
654 pt.x = width_orig; pt.y = 0;
656 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
657 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
658 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
660 SelectObject(hdc, old_hfont);
665 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
667 LOGFONT *lf = (LOGFONT *)lParam;
669 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
672 return 0; /* stop enumeration */
674 return 1; /* continue enumeration */
677 static BOOL is_CJK(void)
679 return (system_lang_id == LANG_CHINESE || system_lang_id == LANG_JAPANESE || system_lang_id == LANG_KOREAN);
682 #define FH_SCALE 0x80000000
683 static void test_bitmap_font_metrics(void)
685 static const struct font_data
687 const char face_name[LF_FACESIZE];
688 int weight, height, ascent, descent, int_leading, ext_leading;
689 int ave_char_width, max_char_width, dpi;
690 BYTE first_char, last_char, def_char, break_char;
696 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
697 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
698 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
699 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
700 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
701 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
702 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 13 },
703 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
704 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC, 16 },
705 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
707 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
708 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
709 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
710 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
711 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
712 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
713 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
714 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
715 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
716 { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
718 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
719 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
720 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
721 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
722 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
723 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
724 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
725 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
726 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
727 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
728 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
729 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
730 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
731 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
732 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
733 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
735 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
736 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
737 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
739 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
740 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
741 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
742 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
743 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
744 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
745 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
746 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
748 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
749 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
750 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
751 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
752 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
753 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
754 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
755 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
756 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
757 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
758 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
759 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
760 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
761 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
762 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
763 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
764 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
766 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
767 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
768 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
769 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
770 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
771 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
772 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
773 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
774 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
775 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
776 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
778 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
779 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
780 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
782 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
783 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
784 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
786 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
787 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
788 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
790 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
791 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
793 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
794 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
795 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
796 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
797 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
798 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
799 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
800 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
801 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
802 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
803 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
804 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
805 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
806 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
807 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
808 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
809 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
810 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
811 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
812 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC },
813 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN },
815 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
816 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
817 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
818 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
819 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
820 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
821 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
822 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
823 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
824 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
825 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
826 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
828 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
829 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
830 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN },
832 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
834 /* FIXME: add "Terminal" */
836 static const int font_log_pixels[] = { 96, 120 };
839 HFONT hfont, old_hfont;
841 INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
842 char face_name[LF_FACESIZE];
845 trace("system language id %04x\n", system_lang_id);
847 expected_cs = GetACP();
848 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
850 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
853 expected_cs = csi.ciCharset;
854 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
856 hdc = CreateCompatibleDC(0);
859 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
860 GetDeviceCaps(hdc, LOGPIXELSY));
862 screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
865 for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
867 int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
871 font_res = font_log_pixels[i];
874 trace("best font resolution is %d\n", font_res);
876 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
880 memset(&lf, 0, sizeof(lf));
882 height = fd[i].height & ~FH_SCALE;
883 lf.lfHeight = height;
884 strcpy(lf.lfFaceName, fd[i].face_name);
886 for(bit = 0; bit < 32; bit++)
894 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
895 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
897 lf.lfCharSet = csi.ciCharset;
898 trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
899 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
900 if (fd[i].height & FH_SCALE)
901 ok(ret, "scaled font height %d should not be enumerated\n", height);
904 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
906 if (ret) /* FIXME: Remove once Wine is fixed */
907 todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
909 ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
912 if (ret && !(fd[i].height & FH_SCALE))
915 hfont = create_font(lf.lfFaceName, &lf);
916 old_hfont = SelectObject(hdc, hfont);
918 SetLastError(0xdeadbeef);
919 ret = GetTextFace(hdc, sizeof(face_name), face_name);
920 ok(ret, "GetTextFace error %u\n", GetLastError());
922 if (lstrcmp(face_name, fd[i].face_name) != 0)
924 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
925 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
926 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
927 SelectObject(hdc, old_hfont);
932 memset(&gm, 0, sizeof(gm));
933 SetLastError(0xdeadbeef);
934 ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
936 ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
937 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
940 bRet = GetTextMetrics(hdc, &tm);
941 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
943 SetLastError(0xdeadbeef);
944 ret = GetTextCharset(hdc);
945 if (is_CJK() && lf.lfCharSet == ANSI_CHARSET)
946 ok(ret == ANSI_CHARSET, "got charset %d, expected ANSI_CHARSETd\n", ret);
948 ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
950 trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
951 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
953 if(fd[i].dpi == tm.tmDigitizedAspectX)
955 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
956 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
958 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
959 if (fd[i].height & FH_SCALE)
960 ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
962 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
963 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
964 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
965 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
966 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
967 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
968 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
969 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
970 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
971 make default char test fail */
972 if (tm.tmCharSet == lf.lfCharSet)
973 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
974 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
975 ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
977 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
978 that make the max width bigger */
979 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
980 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
983 skip("Skipping font metrics test for system langid 0x%x\n",
986 SelectObject(hdc, old_hfont);
994 static void test_GdiGetCharDimensions(void)
1000 LONG avgwidth, height;
1001 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1003 if (!pGdiGetCharDimensions)
1005 win_skip("GdiGetCharDimensions not available on this platform\n");
1009 hdc = CreateCompatibleDC(NULL);
1011 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1012 avgwidth = ((size.cx / 26) + 1) / 2;
1014 ret = pGdiGetCharDimensions(hdc, &tm, &height);
1015 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1016 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1018 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1019 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1021 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1022 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1025 ret = pGdiGetCharDimensions(hdc, NULL, &height);
1026 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1027 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1032 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1033 const TEXTMETRIC *lpntme,
1034 DWORD FontType, LPARAM lParam)
1036 if (FontType & TRUETYPE_FONTTYPE)
1040 hfont = CreateFontIndirect(lpelfe);
1043 *(HFONT *)lParam = hfont;
1051 static void test_GetCharABCWidths(void)
1053 static const WCHAR str[] = {'a',0};
1075 {0xffffff, 0xffffff},
1076 {0x1000000, 0x1000000},
1077 {0xffffff, 0x1000000},
1078 {0xffffffff, 0xffffffff},
1086 BOOL r[sizeof range / sizeof range[0]];
1089 {ANSI_CHARSET, 0x30, 0x30,
1090 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1091 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1092 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1093 {HANGEUL_CHARSET, 0x8141, 0xac02,
1094 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1095 {JOHAB_CHARSET, 0x8446, 0x3135,
1096 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1097 {GB2312_CHARSET, 0x8141, 0x4e04,
1098 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1099 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1100 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1104 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1106 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1110 memset(&lf, 0, sizeof(lf));
1111 strcpy(lf.lfFaceName, "System");
1114 hfont = CreateFontIndirectA(&lf);
1116 hfont = SelectObject(hdc, hfont);
1118 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1119 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1121 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1122 ok(!ret, "GetCharABCWidthsI should have failed\n");
1124 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1125 ok(!ret, "GetCharABCWidthsI should have failed\n");
1127 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1128 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1130 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1131 ok(!ret, "GetCharABCWidthsW should have failed\n");
1133 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1134 ok(!ret, "GetCharABCWidthsW should have failed\n");
1136 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1137 ok(!ret, "GetCharABCWidthsW should have failed\n");
1139 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1140 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1142 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1143 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1145 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1146 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1148 hfont = SelectObject(hdc, hfont);
1149 DeleteObject(hfont);
1151 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1155 UINT code = 0x41, j;
1157 lf.lfFaceName[0] = '\0';
1158 lf.lfCharSet = c[i].cs;
1159 lf.lfPitchAndFamily = 0;
1160 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1162 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1166 memset(a, 0, sizeof a);
1167 memset(w, 0, sizeof w);
1168 hfont = SelectObject(hdc, hfont);
1169 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1170 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1171 memcmp(a, w, sizeof a) == 0,
1172 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1174 memset(a, 0xbb, sizeof a);
1175 ret = pGetCharABCWidthsA(hdc, code, code, a);
1176 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1177 memset(full, 0xcc, sizeof full);
1178 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1179 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1180 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1181 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1183 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1185 memset(full, 0xdd, sizeof full);
1186 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1187 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1188 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1191 UINT last = range[j].last - range[j].first;
1192 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1193 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1194 "GetCharABCWidthsA %x should match. codepage = %u\n",
1195 range[j].last, c[i].cs);
1199 hfont = SelectObject(hdc, hfont);
1200 DeleteObject(hfont);
1203 ReleaseDC(NULL, hdc);
1206 static void test_text_extents(void)
1208 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1210 INT i, len, fit1, fit2;
1219 memset(&lf, 0, sizeof(lf));
1220 strcpy(lf.lfFaceName, "Arial");
1223 hfont = CreateFontIndirectA(&lf);
1225 hfont = SelectObject(hdc, hfont);
1226 GetTextMetricsA(hdc, &tm);
1227 GetTextExtentPointA(hdc, "o", 1, &sz);
1228 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1230 SetLastError(0xdeadbeef);
1231 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1232 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1234 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1235 hfont = SelectObject(hdc, hfont);
1236 DeleteObject(hfont);
1242 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1243 extents[0] = 1; /* So that the increasing sequence test will fail
1244 if the extents array is untouched. */
1245 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1246 GetTextExtentPointW(hdc, wt, len, &sz2);
1247 ok(sz1.cy == sz2.cy,
1248 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1249 /* Because of the '\n' in the string GetTextExtentExPoint and
1250 GetTextExtentPoint return different widths under Win2k, but
1251 under WinXP they return the same width. So we don't test that
1254 for (i = 1; i < len; ++i)
1255 ok(extents[i-1] <= extents[i],
1256 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1258 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1259 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1260 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1261 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1262 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1263 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1264 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1265 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1266 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1267 ok(extents[0] == extents[2] && extents[1] == extents[3],
1268 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1269 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1270 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1271 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1272 HeapFree(GetProcessHeap(), 0, extents);
1274 /* extents functions fail with -ve counts (the interesting case being -1) */
1275 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1276 ok(ret == FALSE, "got %d\n", ret);
1277 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1278 ok(ret == FALSE, "got %d\n", ret);
1279 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1280 ok(ret == FALSE, "got %d\n", ret);
1282 /* max_extent = 0 succeeds and returns zero */
1284 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1286 broken(ret == FALSE), /* NT4, 2k */
1289 broken(fit1 == -215), /* NT4, 2k */
1290 "fit = %d\n", fit1);
1291 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1292 ok(ret == TRUE, "got %d\n", ret);
1293 ok(fit2 == 0, "fit = %d\n", fit2);
1295 /* max_extent = -1 is interpreted as a very large width that will
1296 * definitely fit our three characters */
1298 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1299 ok(ret == TRUE, "got %d\n", ret);
1300 ok(fit1 == 3, "fit = %d\n", fit1);
1301 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1302 ok(ret == TRUE, "got %d\n", ret);
1303 ok(fit2 == 3, "fit = %d\n", fit2);
1305 /* max_extent = -2 is interpreted similarly, but the Ansi version
1306 * rejects it while the Unicode one accepts it */
1308 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1309 ok(ret == FALSE, "got %d\n", ret);
1310 ok(fit1 == -215, "fit = %d\n", fit1);
1311 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1312 ok(ret == TRUE, "got %d\n", ret);
1313 ok(fit2 == 3, "fit = %d\n", fit2);
1315 hfont = SelectObject(hdc, hfont);
1316 DeleteObject(hfont);
1317 ReleaseDC(NULL, hdc);
1320 static void test_GetGlyphIndices(void)
1327 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1328 WORD glyphs[(sizeof(testtext)/2)-1];
1332 if (!pGetGlyphIndicesW) {
1333 win_skip("GetGlyphIndicesW not available on platform\n");
1339 memset(&lf, 0, sizeof(lf));
1340 strcpy(lf.lfFaceName, "System");
1342 lf.lfCharSet = ANSI_CHARSET;
1344 hfont = CreateFontIndirectA(&lf);
1345 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1346 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1347 if (textm.tmCharSet == ANSI_CHARSET)
1349 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1350 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1351 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1352 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1354 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1355 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1356 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1357 textm.tmDefaultChar, glyphs[4]);
1360 /* FIXME: Write tests for non-ANSI charsets. */
1361 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1363 if(!is_font_installed("Tahoma"))
1365 skip("Tahoma is not installed so skipping this test\n");
1368 memset(&lf, 0, sizeof(lf));
1369 strcpy(lf.lfFaceName, "Tahoma");
1372 hfont = CreateFontIndirectA(&lf);
1373 hOldFont = SelectObject(hdc, hfont);
1374 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1375 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1376 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1377 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1378 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1380 testtext[0] = textm.tmDefaultChar;
1381 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1382 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1383 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1384 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1385 DeleteObject(SelectObject(hdc, hOldFont));
1388 static void test_GetKerningPairs(void)
1390 static const struct kerning_data
1392 const char face_name[LF_FACESIZE];
1394 /* some interesting fields from OUTLINETEXTMETRIC */
1395 LONG tmHeight, tmAscent, tmDescent;
1400 UINT otmsCapEmHeight;
1405 UINT otmusMinimumPPEM;
1406 /* small subset of kerning pairs to test */
1407 DWORD total_kern_pairs;
1408 const KERNINGPAIR kern_pair[26];
1411 {"Arial", 12, 12, 9, 3,
1412 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1415 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1416 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1417 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1418 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1419 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1420 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1421 {933,970,+1},{933,972,-1}
1424 {"Arial", -34, 39, 32, 7,
1425 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1428 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1429 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1430 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1431 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1432 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1433 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1434 {933,970,+2},{933,972,-3}
1437 { "Arial", 120, 120, 97, 23,
1438 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1441 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1442 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1443 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1444 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1445 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1446 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1447 {933,970,+6},{933,972,-10}
1450 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1451 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1452 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1455 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1456 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1457 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1458 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1459 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1460 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1461 {933,970,+54},{933,972,-83}
1467 HFONT hfont, hfont_old;
1468 KERNINGPAIR *kern_pair;
1470 DWORD total_kern_pairs, ret, i, n, matches;
1474 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1475 * which may render this test unusable, so we're trying to avoid that.
1477 SetLastError(0xdeadbeef);
1478 GetKerningPairsW(hdc, 0, NULL);
1479 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1481 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1486 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1488 OUTLINETEXTMETRICW otm;
1491 if (!is_font_installed(kd[i].face_name))
1493 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1497 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1499 memset(&lf, 0, sizeof(lf));
1500 strcpy(lf.lfFaceName, kd[i].face_name);
1501 lf.lfHeight = kd[i].height;
1502 hfont = CreateFontIndirect(&lf);
1505 hfont_old = SelectObject(hdc, hfont);
1507 SetLastError(0xdeadbeef);
1508 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1509 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1510 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1512 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1513 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1514 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1515 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1516 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1517 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1519 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1520 kd[i].otmEMSquare, otm.otmEMSquare);
1521 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1522 kd[i].otmAscent, otm.otmAscent);
1523 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1524 kd[i].otmDescent, otm.otmDescent);
1525 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1526 kd[i].otmLineGap, otm.otmLineGap);
1527 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1528 kd[i].otmMacDescent, otm.otmMacDescent);
1529 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1530 kd[i].otmMacAscent, otm.otmMacAscent);
1532 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1533 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1534 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1535 kd[i].otmsXHeight, otm.otmsXHeight);
1536 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1537 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1538 kd[i].otmMacLineGap, otm.otmMacLineGap);
1539 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1540 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1543 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1544 trace("total_kern_pairs %u\n", total_kern_pairs);
1545 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1547 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1550 SetLastError(0xdeadbeef);
1551 ret = GetKerningPairsW(hdc, 0, kern_pair);
1552 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1553 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1554 ok(ret == 0, "got %u, expected 0\n", ret);
1556 ret = GetKerningPairsW(hdc, 100, NULL);
1557 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1559 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1560 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1562 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1563 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1567 for (n = 0; n < ret; n++)
1570 /* Disabled to limit console spam */
1571 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1572 trace("{'%c','%c',%d},\n",
1573 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1574 for (j = 0; j < kd[i].total_kern_pairs; j++)
1576 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1577 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1579 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1580 "pair %d:%d got %d, expected %d\n",
1581 kern_pair[n].wFirst, kern_pair[n].wSecond,
1582 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1588 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1589 matches, kd[i].total_kern_pairs);
1591 HeapFree(GetProcessHeap(), 0, kern_pair);
1593 SelectObject(hdc, hfont_old);
1594 DeleteObject(hfont);
1600 static void test_height_selection(void)
1602 static const struct font_data
1604 const char face_name[LF_FACESIZE];
1605 int requested_height;
1606 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1609 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1610 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1611 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1612 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1613 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1614 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1615 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1616 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1617 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1618 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1622 HFONT hfont, old_hfont;
1626 hdc = CreateCompatibleDC(0);
1629 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1631 if (!is_truetype_font_installed(fd[i].face_name))
1633 skip("%s is not installed\n", fd[i].face_name);
1637 memset(&lf, 0, sizeof(lf));
1638 lf.lfHeight = fd[i].requested_height;
1639 lf.lfWeight = fd[i].weight;
1640 strcpy(lf.lfFaceName, fd[i].face_name);
1642 hfont = CreateFontIndirect(&lf);
1645 old_hfont = SelectObject(hdc, hfont);
1646 ret = GetTextMetrics(hdc, &tm);
1647 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1648 if(fd[i].dpi == tm.tmDigitizedAspectX)
1650 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1651 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1652 ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1653 ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1654 ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1655 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1656 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1658 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1661 SelectObject(hdc, old_hfont);
1662 DeleteObject(hfont);
1668 static void test_GetOutlineTextMetrics(void)
1670 OUTLINETEXTMETRIC *otm;
1672 HFONT hfont, hfont_old;
1674 DWORD ret, otm_size;
1677 if (!is_font_installed("Arial"))
1679 skip("Arial is not installed\n");
1685 memset(&lf, 0, sizeof(lf));
1686 strcpy(lf.lfFaceName, "Arial");
1688 lf.lfWeight = FW_NORMAL;
1689 lf.lfPitchAndFamily = DEFAULT_PITCH;
1690 lf.lfQuality = PROOF_QUALITY;
1691 hfont = CreateFontIndirect(&lf);
1694 hfont_old = SelectObject(hdc, hfont);
1695 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1696 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1698 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1700 memset(otm, 0xAA, otm_size);
1701 SetLastError(0xdeadbeef);
1702 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1703 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1704 ok(ret == 1 /* Win9x */ ||
1705 ret == otm->otmSize /* XP*/,
1706 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1707 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1709 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1710 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1711 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1712 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1715 memset(otm, 0xAA, otm_size);
1716 SetLastError(0xdeadbeef);
1717 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1718 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1719 ok(ret == 1 /* Win9x */ ||
1720 ret == otm->otmSize /* XP*/,
1721 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1722 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1724 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1725 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1726 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1727 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1730 /* ask about truncated data */
1731 memset(otm, 0xAA, otm_size);
1732 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1733 SetLastError(0xdeadbeef);
1734 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1735 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1736 ok(ret == 1 /* Win9x */ ||
1737 ret == otm->otmSize /* XP*/,
1738 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1739 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1741 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1742 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1743 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1745 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1747 HeapFree(GetProcessHeap(), 0, otm);
1749 SelectObject(hdc, hfont_old);
1750 DeleteObject(hfont);
1755 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1759 areaWidth = clientArea->right - clientArea->left,
1761 PSTR pFirstChar, pLastChar;
1768 int GetTextExtentExPointWWidth;
1771 GetTextMetricsA(hdc, &tm);
1772 y = clientArea->top;
1775 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1781 /* if not at the end of the string, ... */
1782 if (*str == '\0') break;
1783 /* ... add the next word to the current extent */
1784 while (*str != '\0' && *str++ != tm.tmBreakChar);
1786 SetTextJustification(hdc, 0, 0);
1787 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1788 } while ((int) size.cx < areaWidth);
1790 /* ignore trailing break chars */
1792 while (*(pLastChar - 1) == tm.tmBreakChar)
1798 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1800 SetTextJustification(hdc, 0, 0);
1801 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1803 /* do not justify the last extent */
1804 if (*str != '\0' && breakCount > 0)
1806 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1807 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1808 if (size.cx != areaWidth && nErrors < sizeof(error)/sizeof(error[0]) - 1)
1810 error[nErrors].start = pFirstChar;
1811 error[nErrors].len = pLastChar - pFirstChar;
1812 error[nErrors].GetTextExtentExPointWWidth = size.cx;
1817 trace( "%u %.*s\n", size.cx, (int)(pLastChar - pFirstChar), pFirstChar);
1821 } while (*str && y < clientArea->bottom);
1823 for (e = 0; e < nErrors; e++)
1825 /* The width returned by GetTextExtentPoint32() is exactly the same
1826 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1827 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1828 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
1829 error[e].len, error[e].start, areaWidth, error[e].GetTextExtentExPointWWidth);
1833 static void test_SetTextJustification(void)
1843 static char testText[] =
1844 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1845 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1846 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1847 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1848 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1849 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1850 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1852 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1853 GetClientRect( hwnd, &clientArea );
1854 hdc = GetDC( hwnd );
1856 memset(&lf, 0, sizeof lf);
1857 lf.lfCharSet = ANSI_CHARSET;
1858 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1859 lf.lfWeight = FW_DONTCARE;
1861 lf.lfQuality = DEFAULT_QUALITY;
1862 lstrcpyA(lf.lfFaceName, "Times New Roman");
1863 hfont = create_font("Times New Roman", &lf);
1864 SelectObject(hdc, hfont);
1866 testJustification(hdc, testText, &clientArea);
1868 if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done;
1869 pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 );
1871 SetTextJustification(hdc, 0, 0);
1872 GetTextExtentPoint32(hdc, " ", 1, &expect);
1873 GetTextExtentPoint32(hdc, " ", 3, &size);
1874 ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx );
1875 SetTextJustification(hdc, 4, 1);
1876 GetTextExtentPoint32(hdc, " ", 1, &size);
1877 ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx );
1878 SetTextJustification(hdc, 9, 2);
1879 GetTextExtentPoint32(hdc, " ", 2, &size);
1880 ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx );
1881 SetTextJustification(hdc, 7, 3);
1882 GetTextExtentPoint32(hdc, " ", 3, &size);
1883 ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx );
1884 SetTextJustification(hdc, 7, 3);
1885 SetTextCharacterExtra(hdc, 2 );
1886 GetTextExtentPoint32(hdc, " ", 3, &size);
1887 ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx );
1888 SetTextJustification(hdc, 0, 0);
1889 SetTextCharacterExtra(hdc, 0);
1890 size.cx = size.cy = 1234;
1891 GetTextExtentPoint32(hdc, " ", 0, &size);
1892 ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy );
1893 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect);
1894 SetTextJustification(hdc, 5, 1);
1895 pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size);
1896 ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx );
1897 SetTextJustification(hdc, 0, 0);
1899 SetMapMode( hdc, MM_ANISOTROPIC );
1900 SetWindowExtEx( hdc, 2, 2, NULL );
1901 GetClientRect( hwnd, &clientArea );
1902 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1903 testJustification(hdc, testText, &clientArea);
1905 GetTextExtentPoint32(hdc, "A", 1, &expect);
1906 for (i = 0; i < 10; i++)
1908 SetTextCharacterExtra(hdc, i);
1909 GetTextExtentPoint32(hdc, "A", 1, &size);
1910 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1912 SetTextCharacterExtra(hdc, 0);
1913 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect);
1914 for (i = 0; i < 10; i++)
1916 SetTextCharacterExtra(hdc, i);
1917 pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size);
1918 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1920 SetTextCharacterExtra(hdc, 0);
1922 SetViewportExtEx( hdc, 3, 3, NULL );
1923 GetClientRect( hwnd, &clientArea );
1924 DPtoLP( hdc, (POINT *)&clientArea, 2 );
1925 testJustification(hdc, testText, &clientArea);
1927 GetTextExtentPoint32(hdc, "A", 1, &expect);
1928 for (i = 0; i < 10; i++)
1930 SetTextCharacterExtra(hdc, i);
1931 GetTextExtentPoint32(hdc, "A", 1, &size);
1932 ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i );
1936 DeleteObject(hfont);
1937 ReleaseDC(hwnd, hdc);
1938 DestroyWindow(hwnd);
1941 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1945 HFONT hfont, hfont_old;
1952 assert(count <= 128);
1954 memset(&lf, 0, sizeof(lf));
1956 lf.lfCharSet = charset;
1958 lstrcpyA(lf.lfFaceName, "Arial");
1959 SetLastError(0xdeadbeef);
1960 hfont = CreateFontIndirectA(&lf);
1961 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1964 hfont_old = SelectObject(hdc, hfont);
1966 cs = GetTextCharsetInfo(hdc, &fs, 0);
1967 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1969 SetLastError(0xdeadbeef);
1970 ret = GetTextFaceA(hdc, sizeof(name), name);
1971 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1973 if (charset == SYMBOL_CHARSET)
1975 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1976 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1980 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1981 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1984 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1986 trace("Can't find codepage for charset %d\n", cs);
1990 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1992 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1994 skip("Font code page %d, looking for code page %d\n",
1995 pGdiGetCodePage(hdc), code_page);
2003 WCHAR unicode_buf[128];
2005 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2007 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
2009 SetLastError(0xdeadbeef);
2010 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
2011 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
2012 count, ret, GetLastError());
2018 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
2020 SetLastError(0xdeadbeef);
2021 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
2022 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
2023 count, ret, GetLastError());
2026 SelectObject(hdc, hfont_old);
2027 DeleteObject(hfont);
2034 static void test_font_charset(void)
2036 static struct charset_data
2040 WORD font_idxA[128], font_idxW[128];
2043 { ANSI_CHARSET, 1252 },
2044 { RUSSIAN_CHARSET, 1251 },
2045 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
2049 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
2051 win_skip("Skipping the font charset test on a Win9x platform\n");
2055 if (!is_font_installed("Arial"))
2057 skip("Arial is not installed\n");
2061 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
2063 if (cd[i].charset == SYMBOL_CHARSET)
2065 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2067 skip("Symbol or Wingdings is not installed\n");
2071 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
2072 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
2073 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
2076 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
2079 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2080 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2083 skip("Symbol or Wingdings is not installed\n");
2086 static void test_GdiGetCodePage(void)
2088 static const struct _matching_data
2090 UINT current_codepage;
2093 UINT expected_codepage;
2094 } matching_data[] = {
2095 {1251, "Arial", ANSI_CHARSET, 1252},
2096 {1251, "Tahoma", ANSI_CHARSET, 1252},
2098 {1252, "Arial", ANSI_CHARSET, 1252},
2099 {1252, "Tahoma", ANSI_CHARSET, 1252},
2101 {1253, "Arial", ANSI_CHARSET, 1252},
2102 {1253, "Tahoma", ANSI_CHARSET, 1252},
2104 { 932, "Arial", ANSI_CHARSET, 1252}, /* Japanese Windows returns 1252, not 932 */
2105 { 932, "Tahoma", ANSI_CHARSET, 1252},
2106 { 932, "MS UI Gothic", ANSI_CHARSET, 1252},
2108 { 936, "Arial", ANSI_CHARSET, 936},
2109 { 936, "Tahoma", ANSI_CHARSET, 936},
2110 { 936, "Simsun", ANSI_CHARSET, 936},
2112 { 949, "Arial", ANSI_CHARSET, 949},
2113 { 949, "Tahoma", ANSI_CHARSET, 949},
2114 { 949, "Gulim", ANSI_CHARSET, 949},
2116 { 950, "Arial", ANSI_CHARSET, 950},
2117 { 950, "Tahoma", ANSI_CHARSET, 950},
2118 { 950, "PMingLiU", ANSI_CHARSET, 950},
2127 if (!pGdiGetCodePage)
2129 skip("GdiGetCodePage not available on this platform\n");
2135 for (i = 0; i < sizeof(matching_data) / sizeof(struct _matching_data); i++)
2137 /* only test data matched current locale codepage */
2138 if (matching_data[i].current_codepage != acp)
2141 if (!is_font_installed(matching_data[i].lfFaceName))
2143 skip("%s is not installed\n", matching_data[i].lfFaceName);
2149 memset(&lf, 0, sizeof(lf));
2151 lf.lfCharSet = matching_data[i].lfCharSet;
2152 lstrcpyA(lf.lfFaceName, matching_data[i].lfFaceName);
2153 hfont = CreateFontIndirectA(&lf);
2154 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2156 hfont = SelectObject(hdc, hfont);
2157 charset = GetTextCharset(hdc);
2158 codepage = pGdiGetCodePage(hdc);
2159 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2160 acp, lf.lfFaceName, lf.lfCharSet, charset, codepage, matching_data[i].expected_codepage);
2161 ok(codepage == matching_data[i].expected_codepage,
2162 "GdiGetCodePage should have returned %d, got %d\n", matching_data[i].expected_codepage, codepage);
2164 hfont = SelectObject(hdc, hfont);
2165 DeleteObject(hfont);
2166 ReleaseDC(NULL, hdc);
2170 static void test_GetFontUnicodeRanges(void)
2174 HFONT hfont, hfont_old;
2179 if (!pGetFontUnicodeRanges)
2181 win_skip("GetFontUnicodeRanges not available before W2K\n");
2185 memset(&lf, 0, sizeof(lf));
2186 lstrcpyA(lf.lfFaceName, "Arial");
2187 hfont = create_font("Arial", &lf);
2190 hfont_old = SelectObject(hdc, hfont);
2192 size = pGetFontUnicodeRanges(NULL, NULL);
2193 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2195 size = pGetFontUnicodeRanges(hdc, NULL);
2196 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2198 gs = HeapAlloc(GetProcessHeap(), 0, size);
2200 size = pGetFontUnicodeRanges(hdc, gs);
2201 ok(size, "GetFontUnicodeRanges failed\n");
2203 if (0) /* Disabled to limit console spam */
2204 for (i = 0; i < gs->cRanges; i++)
2205 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2206 trace("found %u ranges\n", gs->cRanges);
2208 HeapFree(GetProcessHeap(), 0, gs);
2210 SelectObject(hdc, hfont_old);
2211 DeleteObject(hfont);
2212 ReleaseDC(NULL, hdc);
2215 #define MAX_ENUM_FONTS 4096
2217 struct enum_font_data
2220 LOGFONT lf[MAX_ENUM_FONTS];
2223 struct enum_fullname_data
2226 ENUMLOGFONT elf[MAX_ENUM_FONTS];
2229 struct enum_font_dataW
2232 LOGFONTW lf[MAX_ENUM_FONTS];
2235 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2237 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2238 const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2240 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2241 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2243 if (type != TRUETYPE_FONTTYPE) return 1;
2245 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2247 if (0) /* Disabled to limit console spam */
2248 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2249 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2250 if (efd->total < MAX_ENUM_FONTS)
2251 efd->lf[efd->total++] = *lf;
2253 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2258 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2260 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2261 const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2263 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2264 ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2266 if (type != TRUETYPE_FONTTYPE) return 1;
2268 ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2270 if (0) /* Disabled to limit console spam */
2271 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2272 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2273 if (efd->total < MAX_ENUM_FONTS)
2274 efd->lf[efd->total++] = *lf;
2276 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2281 static void get_charset_stats(struct enum_font_data *efd,
2282 int *ansi_charset, int *symbol_charset,
2283 int *russian_charset)
2288 *symbol_charset = 0;
2289 *russian_charset = 0;
2291 for (i = 0; i < efd->total; i++)
2293 switch (efd->lf[i].lfCharSet)
2298 case SYMBOL_CHARSET:
2299 (*symbol_charset)++;
2301 case RUSSIAN_CHARSET:
2302 (*russian_charset)++;
2308 static void get_charset_statsW(struct enum_font_dataW *efd,
2309 int *ansi_charset, int *symbol_charset,
2310 int *russian_charset)
2315 *symbol_charset = 0;
2316 *russian_charset = 0;
2318 for (i = 0; i < efd->total; i++)
2320 switch (efd->lf[i].lfCharSet)
2325 case SYMBOL_CHARSET:
2326 (*symbol_charset)++;
2328 case RUSSIAN_CHARSET:
2329 (*russian_charset)++;
2335 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2337 struct enum_font_data efd;
2338 struct enum_font_dataW efdw;
2341 int i, ret, ansi_charset, symbol_charset, russian_charset;
2343 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2345 if (*font_name && !is_truetype_font_installed(font_name))
2347 skip("%s is not installed\n", font_name);
2353 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2354 * while EnumFontFamiliesEx doesn't.
2356 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2359 * Use EnumFontFamiliesW since win98 crashes when the
2360 * second parameter is NULL using EnumFontFamilies
2363 SetLastError(0xdeadbeef);
2364 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2365 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2368 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2369 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2370 ansi_charset, symbol_charset, russian_charset);
2371 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2372 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2373 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2374 ok(russian_charset > 0 ||
2375 broken(russian_charset == 0), /* NT4 */
2376 "NULL family should enumerate RUSSIAN_CHARSET\n");
2380 SetLastError(0xdeadbeef);
2381 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2382 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2385 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2386 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2387 ansi_charset, symbol_charset, russian_charset);
2388 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2389 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2390 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2391 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2396 SetLastError(0xdeadbeef);
2397 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2398 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2399 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2400 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2401 ansi_charset, symbol_charset, russian_charset,
2402 *font_name ? font_name : "<empty>");
2404 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2406 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2407 for (i = 0; i < efd.total; i++)
2409 /* FIXME: remove completely once Wine is fixed */
2410 if (efd.lf[i].lfCharSet != font_charset)
2413 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2416 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2417 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2418 font_name, efd.lf[i].lfFaceName);
2421 memset(&lf, 0, sizeof(lf));
2422 lf.lfCharSet = ANSI_CHARSET;
2423 lstrcpy(lf.lfFaceName, font_name);
2425 SetLastError(0xdeadbeef);
2426 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2427 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2428 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2429 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2430 ansi_charset, symbol_charset, russian_charset,
2431 *font_name ? font_name : "<empty>");
2432 if (font_charset == SYMBOL_CHARSET)
2435 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2437 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2441 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2442 for (i = 0; i < efd.total; i++)
2444 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2446 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2447 font_name, efd.lf[i].lfFaceName);
2451 /* DEFAULT_CHARSET should enumerate all available charsets */
2452 memset(&lf, 0, sizeof(lf));
2453 lf.lfCharSet = DEFAULT_CHARSET;
2454 lstrcpy(lf.lfFaceName, font_name);
2456 SetLastError(0xdeadbeef);
2457 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2458 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2459 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2460 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2461 ansi_charset, symbol_charset, russian_charset,
2462 *font_name ? font_name : "<empty>");
2463 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2464 for (i = 0; i < efd.total; i++)
2467 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2468 font_name, efd.lf[i].lfFaceName);
2472 switch (font_charset)
2475 ok(ansi_charset > 0,
2476 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2478 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2479 ok(russian_charset > 0,
2480 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2482 case SYMBOL_CHARSET:
2484 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2486 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2487 ok(!russian_charset,
2488 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2490 case DEFAULT_CHARSET:
2491 ok(ansi_charset > 0,
2492 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2493 ok(symbol_charset > 0,
2494 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2495 ok(russian_charset > 0,
2496 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2502 ok(ansi_charset > 0,
2503 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2504 ok(symbol_charset > 0,
2505 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2506 ok(russian_charset > 0,
2507 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2510 memset(&lf, 0, sizeof(lf));
2511 lf.lfCharSet = SYMBOL_CHARSET;
2512 lstrcpy(lf.lfFaceName, font_name);
2514 SetLastError(0xdeadbeef);
2515 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2516 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2517 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2518 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2519 ansi_charset, symbol_charset, russian_charset,
2520 *font_name ? font_name : "<empty>");
2521 if (*font_name && font_charset == ANSI_CHARSET)
2522 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2525 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2526 for (i = 0; i < efd.total; i++)
2528 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2530 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2531 font_name, efd.lf[i].lfFaceName);
2535 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2536 ok(symbol_charset > 0,
2537 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2538 ok(!russian_charset,
2539 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2545 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2547 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2549 if (type != TRUETYPE_FONTTYPE) return 1;
2551 if (efd->total < MAX_ENUM_FONTS)
2552 efd->lf[efd->total++] = *lf;
2554 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2559 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2561 struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2563 if (type != TRUETYPE_FONTTYPE) return 1;
2565 if (efnd->total < MAX_ENUM_FONTS)
2566 efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2568 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2573 static void test_EnumFontFamiliesEx_default_charset(void)
2575 struct enum_font_data efd;
2576 LOGFONT gui_font, enum_font;
2580 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2581 ok(ret, "GetObject failed.\n");
2588 memset(&enum_font, 0, sizeof(enum_font));
2589 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2590 enum_font.lfCharSet = DEFAULT_CHARSET;
2591 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2594 if (efd.total == 0) {
2595 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2598 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2600 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet || broken(system_lang_id == LANG_ARABIC),
2601 "(%s) got charset %d expected %d\n",
2602 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2607 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2609 HFONT hfont, hfont_prev;
2611 GLYPHMETRICS gm1, gm2;
2615 if(!pGetGlyphIndicesA)
2618 /* negative widths are handled just as positive ones */
2619 lf2.lfWidth = -lf->lfWidth;
2621 SetLastError(0xdeadbeef);
2622 hfont = CreateFontIndirectA(lf);
2623 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2624 check_font("original", lf, hfont);
2626 hfont_prev = SelectObject(hdc, hfont);
2628 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2629 if (ret == GDI_ERROR || idx == 0xffff)
2631 SelectObject(hdc, hfont_prev);
2632 DeleteObject(hfont);
2633 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2637 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2638 memset(&gm1, 0xab, sizeof(gm1));
2639 SetLastError(0xdeadbeef);
2640 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2641 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2643 SelectObject(hdc, hfont_prev);
2644 DeleteObject(hfont);
2646 SetLastError(0xdeadbeef);
2647 hfont = CreateFontIndirectA(&lf2);
2648 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2649 check_font("negative width", &lf2, hfont);
2651 hfont_prev = SelectObject(hdc, hfont);
2653 memset(&gm2, 0xbb, sizeof(gm2));
2654 SetLastError(0xdeadbeef);
2655 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2656 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2658 SelectObject(hdc, hfont_prev);
2659 DeleteObject(hfont);
2661 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2662 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2663 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2664 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2665 gm1.gmCellIncX == gm2.gmCellIncX &&
2666 gm1.gmCellIncY == gm2.gmCellIncY,
2667 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2668 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2669 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2670 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2671 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2674 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2675 #include "pshpack2.h"
2679 SHORT xAvgCharWidth;
2680 USHORT usWeightClass;
2681 USHORT usWidthClass;
2683 SHORT ySubscriptXSize;
2684 SHORT ySubscriptYSize;
2685 SHORT ySubscriptXOffset;
2686 SHORT ySubscriptYOffset;
2687 SHORT ySuperscriptXSize;
2688 SHORT ySuperscriptYSize;
2689 SHORT ySuperscriptXOffset;
2690 SHORT ySuperscriptYOffset;
2691 SHORT yStrikeoutSize;
2692 SHORT yStrikeoutPosition;
2695 ULONG ulUnicodeRange1;
2696 ULONG ulUnicodeRange2;
2697 ULONG ulUnicodeRange3;
2698 ULONG ulUnicodeRange4;
2701 USHORT usFirstCharIndex;
2702 USHORT usLastCharIndex;
2703 /* According to the Apple spec, original version didn't have the below fields,
2704 * version numbers were taken from the OpenType spec.
2706 /* version 0 (TrueType 1.5) */
2707 USHORT sTypoAscender;
2708 USHORT sTypoDescender;
2709 USHORT sTypoLineGap;
2711 USHORT usWinDescent;
2712 /* version 1 (TrueType 1.66) */
2713 ULONG ulCodePageRange1;
2714 ULONG ulCodePageRange2;
2715 /* version 2 (OpenType 1.2) */
2718 USHORT usDefaultChar;
2720 USHORT usMaxContext;
2722 #include "poppack.h"
2724 #ifdef WORDS_BIGENDIAN
2725 #define GET_BE_WORD(x) (x)
2726 #define GET_BE_DWORD(x) (x)
2728 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2729 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2732 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2733 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2734 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2735 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2736 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2737 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2750 } cmap_encoding_record;
2758 BYTE glyph_ids[256];
2768 USHORT search_range;
2769 USHORT entry_selector;
2772 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2775 USHORT start_count[seg_countx2 / 2];
2776 USHORT id_delta[seg_countx2 / 2];
2777 USHORT id_range_offset[seg_countx2 / 2];
2787 USHORT id_range_offset;
2788 } cmap_format_4_seg;
2790 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2792 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2793 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2794 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2795 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2796 os2->panose.bWeight, os2->panose.bProportion);
2799 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2802 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2806 for(i = 0; i < 256; i++)
2808 if(cmap->glyph_ids[i] == 0) continue;
2810 if(*first == 256) *first = i;
2812 if(*first == 256) return FALSE;
2816 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2818 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2819 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2820 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2821 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2822 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2825 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2828 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2829 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2830 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2834 for(i = 0; i < seg_count; i++)
2837 cmap_format_4_seg seg;
2839 get_seg4(cmap, i, &seg);
2840 for(code = seg.start_count; code <= seg.end_count; code++)
2842 if(seg.id_range_offset == 0)
2843 index = (seg.id_delta + code) & 0xffff;
2846 index = seg.id_range_offset / 2
2847 + code - seg.start_count
2850 /* some fonts have broken last segment */
2851 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2852 index = GET_BE_WORD(glyph_ids[index]);
2855 trace("segment %04x/%04x index %04x points to nowhere\n",
2856 seg.start_count, seg.end_count, index);
2859 if(index) index += seg.id_delta;
2861 if(*first == 0x10000)
2862 *last = *first = code;
2868 if(*first == 0x10000) return FALSE;
2872 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2875 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2877 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2879 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2880 return (BYTE *)header + GET_BE_DWORD(record->offset);
2893 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2896 cmap_header *header;
2901 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2902 ok(size != GDI_ERROR, "no cmap table found\n");
2903 if(size == GDI_ERROR) return FALSE;
2905 header = HeapAlloc(GetProcessHeap(), 0, size);
2906 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2907 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2908 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2910 cmap = get_cmap(header, 3, 1);
2912 *cmap_type = cmap_ms_unicode;
2915 cmap = get_cmap(header, 3, 0);
2916 if(cmap) *cmap_type = cmap_ms_symbol;
2920 *cmap_type = cmap_none;
2924 format = GET_BE_WORD(*(WORD *)cmap);
2928 r = get_first_last_from_cmap0(cmap, first, last);
2931 r = get_first_last_from_cmap4(cmap, first, last, size);
2934 trace("unhandled cmap format %d\n", format);
2939 HeapFree(GetProcessHeap(), 0, header);
2943 #define TT_PLATFORM_MICROSOFT 3
2944 #define TT_MS_ID_SYMBOL_CS 0
2945 #define TT_MS_ID_UNICODE_CS 1
2946 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2947 #define TT_NAME_ID_FONT_FAMILY 1
2948 #define TT_NAME_ID_FONT_SUBFAMILY 2
2949 #define TT_NAME_ID_UNIQUE_ID 3
2950 #define TT_NAME_ID_FULL_NAME 4
2952 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2954 struct sfnt_name_header
2957 USHORT number_of_record;
2958 USHORT storage_offset;
2970 LONG size, offset, length;
2976 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2977 ok(size != GDI_ERROR, "no name table found\n");
2978 if(size == GDI_ERROR) return FALSE;
2980 data = HeapAlloc(GetProcessHeap(), 0, size);
2981 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2982 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2984 header = (void *)data;
2985 header->format = GET_BE_WORD(header->format);
2986 header->number_of_record = GET_BE_WORD(header->number_of_record);
2987 header->storage_offset = GET_BE_WORD(header->storage_offset);
2988 if (header->format != 0)
2990 trace("got format %u\n", header->format);
2993 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2995 trace("number records out of range: %d\n", header->number_of_record);
2998 if (header->storage_offset >= size)
3000 trace("storage_offset %u > size %u\n", header->storage_offset, size);
3004 entry = (void *)&header[1];
3005 for (i = 0; i < header->number_of_record; i++)
3007 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
3008 (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
3009 GET_BE_WORD(entry[i].language_id) != language_id ||
3010 GET_BE_WORD(entry[i].name_id) != name_id)
3015 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
3016 length = GET_BE_WORD(entry[i].length);
3017 if (offset + length > size)
3019 trace("entry %d is out of range\n", i);
3022 if (length >= out_size)
3024 trace("buffer too small for entry %d\n", i);
3028 name = (WCHAR *)(data + offset);
3029 for (c = 0; c < length / 2; c++)
3030 out_buf[c] = GET_BE_WORD(name[c]);
3038 HeapFree(GetProcessHeap(), 0, data);
3042 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
3045 HFONT hfont, hfont_old;
3049 const char *font_name = lf->lfFaceName;
3050 DWORD cmap_first = 0, cmap_last = 0;
3051 UINT ascent, descent, cell_height;
3052 cmap_type cmap_type;
3053 BOOL sys_lang_non_english;
3055 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
3058 SetLastError(0xdeadbeef);
3059 hfont = CreateFontIndirectA(lf);
3060 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
3062 hfont_old = SelectObject(hdc, hfont);
3064 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
3065 if (size == GDI_ERROR)
3067 trace("OS/2 chunk was not found\n");
3070 if (size > sizeof(tt_os2))
3072 trace("got too large OS/2 chunk of size %u\n", size);
3073 size = sizeof(tt_os2);
3076 memset(&tt_os2, 0, sizeof(tt_os2));
3077 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
3078 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
3080 ascent = GET_BE_WORD(tt_os2.usWinAscent);
3081 descent = GET_BE_WORD(tt_os2.usWinDescent);
3082 cell_height = ascent + descent;
3083 ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3084 font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
3086 SetLastError(0xdeadbeef);
3087 ret = GetTextMetricsA(hdc, &tmA);
3088 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3090 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
3092 skip("Unable to retrieve first and last glyphs from cmap\n");
3096 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
3097 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
3098 UINT os2_first_char, os2_last_char, default_char, break_char;
3102 version = GET_BE_WORD(tt_os2.version);
3104 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
3105 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
3106 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
3107 break_char = GET_BE_WORD(tt_os2.usBreakChar);
3109 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3110 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
3111 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
3113 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
3118 case 1257: /* Baltic */
3119 expect_last_W = 0xf8fd;
3122 expect_last_W = 0xf0ff;
3124 expect_break_W = 0x20;
3125 expect_default_W = expect_break_W - 1;
3126 expect_first_A = 0x1e;
3127 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
3131 expect_first_W = cmap_first;
3132 expect_last_W = min(cmap_last, os2_last_char);
3133 if(os2_first_char <= 1)
3134 expect_break_W = os2_first_char + 2;
3135 else if(os2_first_char > 0xff)
3136 expect_break_W = 0x20;
3138 expect_break_W = os2_first_char;
3139 expect_default_W = expect_break_W - 1;
3140 expect_first_A = expect_default_W - 1;
3141 expect_last_A = min(expect_last_W, 0xff);
3143 expect_break_A = expect_break_W;
3144 expect_default_A = expect_default_W;
3146 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3147 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
3148 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
3149 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3150 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3152 ok(tmA.tmFirstChar == expect_first_A ||
3153 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
3154 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
3155 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
3156 ok(tmA.tmLastChar == expect_last_A ||
3157 tmA.tmLastChar == 0xff /* win9x */,
3158 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
3160 skip("tmLastChar is DBCS lead byte\n");
3161 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
3162 font_name, tmA.tmBreakChar, expect_break_A);
3163 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3164 "A: tmDefaultChar for %s got %02x expected %02x\n",
3165 font_name, tmA.tmDefaultChar, expect_default_A);
3168 SetLastError(0xdeadbeef);
3169 ret = GetTextMetricsW(hdc, &tmW);
3170 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3171 "GetTextMetricsW error %u\n", GetLastError());
3174 /* Wine uses the os2 first char */
3175 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3176 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3177 font_name, tmW.tmFirstChar, expect_first_W);
3179 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3180 font_name, tmW.tmFirstChar, expect_first_W);
3182 /* Wine uses the os2 last char */
3183 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3184 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3185 font_name, tmW.tmLastChar, expect_last_W);
3187 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3188 font_name, tmW.tmLastChar, expect_last_W);
3189 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3190 font_name, tmW.tmBreakChar, expect_break_W);
3191 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3192 "W: tmDefaultChar for %s got %02x expected %02x\n",
3193 font_name, tmW.tmDefaultChar, expect_default_W);
3195 /* Test the aspect ratio while we have tmW */
3196 ret = GetDeviceCaps(hdc, LOGPIXELSX);
3197 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3198 tmW.tmDigitizedAspectX, ret);
3199 ret = GetDeviceCaps(hdc, LOGPIXELSY);
3200 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3201 tmW.tmDigitizedAspectX, ret);
3205 /* test FF_ values */
3206 switch(tt_os2.panose.bFamilyType)
3210 case PAN_FAMILY_TEXT_DISPLAY:
3211 case PAN_FAMILY_PICTORIAL:
3213 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3214 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3216 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3219 switch(tt_os2.panose.bSerifStyle)
3224 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3227 case PAN_SERIF_COVE:
3228 case PAN_SERIF_OBTUSE_COVE:
3229 case PAN_SERIF_SQUARE_COVE:
3230 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3231 case PAN_SERIF_SQUARE:
3232 case PAN_SERIF_THIN:
3233 case PAN_SERIF_BONE:
3234 case PAN_SERIF_EXAGGERATED:
3235 case PAN_SERIF_TRIANGLE:
3236 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3239 case PAN_SERIF_NORMAL_SANS:
3240 case PAN_SERIF_OBTUSE_SANS:
3241 case PAN_SERIF_PERP_SANS:
3242 case PAN_SERIF_FLARED:
3243 case PAN_SERIF_ROUNDED:
3244 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3249 case PAN_FAMILY_SCRIPT:
3250 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3253 case PAN_FAMILY_DECORATIVE:
3254 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3258 test_negative_width(hdc, lf);
3261 SelectObject(hdc, hfont_old);
3262 DeleteObject(hfont);
3267 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3269 INT *enumed = (INT *)lParam;
3271 if (type == TRUETYPE_FONTTYPE)
3274 test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3279 static void test_GetTextMetrics(void)
3285 /* Report only once */
3286 if(!pGetGlyphIndicesA)
3287 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3291 memset(&lf, 0, sizeof(lf));
3292 lf.lfCharSet = DEFAULT_CHARSET;
3294 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3295 trace("Tested metrics of %d truetype fonts\n", enumed);
3300 static void test_nonexistent_font(void)
3308 { "Times New Roman Baltic", 186 },
3309 { "Times New Roman CE", 238 },
3310 { "Times New Roman CYR", 204 },
3311 { "Times New Roman Greek", 161 },
3312 { "Times New Roman TUR", 162 }
3318 INT cs, expected_cs, i;
3319 char buf[LF_FACESIZE];
3321 if (!is_truetype_font_installed("Arial") ||
3322 !is_truetype_font_installed("Times New Roman"))
3324 skip("Arial or Times New Roman not installed\n");
3328 expected_cs = GetACP();
3329 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3331 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3334 expected_cs = csi.ciCharset;
3335 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3339 memset(&lf, 0, sizeof(lf));
3341 lf.lfWeight = FW_REGULAR;
3342 lf.lfCharSet = ANSI_CHARSET;
3343 lf.lfPitchAndFamily = FF_SWISS;
3344 strcpy(lf.lfFaceName, "Nonexistent font");
3345 hfont = CreateFontIndirectA(&lf);
3346 hfont = SelectObject(hdc, hfont);
3347 GetTextFaceA(hdc, sizeof(buf), buf);
3348 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3349 cs = GetTextCharset(hdc);
3350 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3351 DeleteObject(SelectObject(hdc, hfont));
3353 memset(&lf, 0, sizeof(lf));
3355 lf.lfWeight = FW_DONTCARE;
3356 strcpy(lf.lfFaceName, "Nonexistent font");
3357 hfont = CreateFontIndirectA(&lf);
3358 hfont = SelectObject(hdc, hfont);
3359 GetTextFaceA(hdc, sizeof(buf), buf);
3360 todo_wine /* Wine uses Arial for all substitutions */
3361 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3362 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3363 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3365 cs = GetTextCharset(hdc);
3366 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3367 DeleteObject(SelectObject(hdc, hfont));
3369 memset(&lf, 0, sizeof(lf));
3371 lf.lfWeight = FW_REGULAR;
3372 strcpy(lf.lfFaceName, "Nonexistent font");
3373 hfont = CreateFontIndirectA(&lf);
3374 hfont = SelectObject(hdc, hfont);
3375 GetTextFaceA(hdc, sizeof(buf), buf);
3376 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3377 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3378 cs = GetTextCharset(hdc);
3379 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3380 DeleteObject(SelectObject(hdc, hfont));
3382 memset(&lf, 0, sizeof(lf));
3384 lf.lfWeight = FW_DONTCARE;
3385 strcpy(lf.lfFaceName, "Times New Roman");
3386 hfont = CreateFontIndirectA(&lf);
3387 hfont = SelectObject(hdc, hfont);
3388 GetTextFaceA(hdc, sizeof(buf), buf);
3389 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3390 cs = GetTextCharset(hdc);
3391 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3392 DeleteObject(SelectObject(hdc, hfont));
3394 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3396 memset(&lf, 0, sizeof(lf));
3398 lf.lfWeight = FW_REGULAR;
3399 strcpy(lf.lfFaceName, font_subst[i].name);
3400 hfont = CreateFontIndirectA(&lf);
3401 hfont = SelectObject(hdc, hfont);
3402 cs = GetTextCharset(hdc);
3403 if (font_subst[i].charset == expected_cs)
3405 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3406 GetTextFaceA(hdc, sizeof(buf), buf);
3407 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3411 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3412 GetTextFaceA(hdc, sizeof(buf), buf);
3413 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3414 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3416 DeleteObject(SelectObject(hdc, hfont));
3418 memset(&lf, 0, sizeof(lf));
3420 lf.lfWeight = FW_DONTCARE;
3421 strcpy(lf.lfFaceName, font_subst[i].name);
3422 hfont = CreateFontIndirectA(&lf);
3423 hfont = SelectObject(hdc, hfont);
3424 GetTextFaceA(hdc, sizeof(buf), buf);
3425 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3426 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3427 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3428 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3429 "got %s for font %s\n", buf, font_subst[i].name);
3430 cs = GetTextCharset(hdc);
3431 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3432 DeleteObject(SelectObject(hdc, hfont));
3438 static void test_GdiRealizationInfo(void)
3443 HFONT hfont, hfont_old;
3446 if(!pGdiRealizationInfo)
3448 win_skip("GdiRealizationInfo not available\n");
3454 memset(info, 0xcc, sizeof(info));
3455 r = pGdiRealizationInfo(hdc, info);
3456 ok(r != 0, "ret 0\n");
3457 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3458 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3460 if (!is_truetype_font_installed("Arial"))
3462 skip("skipping GdiRealizationInfo with truetype font\n");
3466 memset(&lf, 0, sizeof(lf));
3467 strcpy(lf.lfFaceName, "Arial");
3469 lf.lfWeight = FW_NORMAL;
3470 hfont = CreateFontIndirectA(&lf);
3471 hfont_old = SelectObject(hdc, hfont);
3473 memset(info, 0xcc, sizeof(info));
3474 r = pGdiRealizationInfo(hdc, info);
3475 ok(r != 0, "ret 0\n");
3476 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3477 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3479 DeleteObject(SelectObject(hdc, hfont_old));
3485 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3486 the nul in the count of characters copied when the face name buffer is not
3487 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3488 always includes it. */
3489 static void test_GetTextFace(void)
3491 static const char faceA[] = "Tahoma";
3492 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3495 char bufA[LF_FACESIZE];
3496 WCHAR bufW[LF_FACESIZE];
3501 if(!is_font_installed("Tahoma"))
3503 skip("Tahoma is not installed so skipping this test\n");
3508 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3509 f = CreateFontIndirectA(&fA);
3510 ok(f != NULL, "CreateFontIndirectA failed\n");
3513 g = SelectObject(dc, f);
3514 n = GetTextFaceA(dc, sizeof bufA, bufA);
3515 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3516 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3518 /* Play with the count arg. */
3520 n = GetTextFaceA(dc, 0, bufA);
3521 ok(n == 0, "GetTextFaceA returned %d\n", n);
3522 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3525 n = GetTextFaceA(dc, 1, bufA);
3526 ok(n == 0, "GetTextFaceA returned %d\n", n);
3527 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3529 bufA[0] = 'x'; bufA[1] = 'y';
3530 n = GetTextFaceA(dc, 2, bufA);
3531 ok(n == 1, "GetTextFaceA returned %d\n", n);
3532 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3534 n = GetTextFaceA(dc, 0, NULL);
3535 ok(n == sizeof faceA ||
3536 broken(n == 0), /* win98, winMe */
3537 "GetTextFaceA returned %d\n", n);
3539 DeleteObject(SelectObject(dc, g));
3540 ReleaseDC(NULL, dc);
3543 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3544 SetLastError(0xdeadbeef);
3545 f = CreateFontIndirectW(&fW);
3546 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3548 win_skip("CreateFontIndirectW is not implemented\n");
3551 ok(f != NULL, "CreateFontIndirectW failed\n");
3554 g = SelectObject(dc, f);
3555 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3556 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3557 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3559 /* Play with the count arg. */
3561 n = GetTextFaceW(dc, 0, bufW);
3562 ok(n == 0, "GetTextFaceW returned %d\n", n);
3563 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3566 n = GetTextFaceW(dc, 1, bufW);
3567 ok(n == 1, "GetTextFaceW returned %d\n", n);
3568 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3570 bufW[0] = 'x'; bufW[1] = 'y';
3571 n = GetTextFaceW(dc, 2, bufW);
3572 ok(n == 2, "GetTextFaceW returned %d\n", n);
3573 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3575 n = GetTextFaceW(dc, 0, NULL);
3576 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3578 DeleteObject(SelectObject(dc, g));
3579 ReleaseDC(NULL, dc);
3582 static void test_orientation(void)
3584 static const char test_str[11] = "Test String";
3587 HFONT hfont, old_hfont;
3590 if (!is_truetype_font_installed("Arial"))
3592 skip("Arial is not installed\n");
3596 hdc = CreateCompatibleDC(0);
3597 memset(&lf, 0, sizeof(lf));
3598 lstrcpyA(lf.lfFaceName, "Arial");
3600 lf.lfOrientation = lf.lfEscapement = 900;
3601 hfont = create_font("orientation", &lf);
3602 old_hfont = SelectObject(hdc, hfont);
3603 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3604 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3605 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3606 SelectObject(hdc, old_hfont);
3607 DeleteObject(hfont);
3611 static void test_oemcharset(void)
3615 HFONT hfont, old_hfont;
3618 hdc = CreateCompatibleDC(0);
3619 ZeroMemory(&lf, sizeof(lf));
3621 lf.lfCharSet = OEM_CHARSET;
3622 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3623 lstrcpyA(lf.lfFaceName, "Terminal");
3624 hfont = CreateFontIndirectA(&lf);
3625 old_hfont = SelectObject(hdc, hfont);
3626 charset = GetTextCharset(hdc);
3628 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3629 hfont = SelectObject(hdc, old_hfont);
3630 GetObjectA(hfont, sizeof(clf), &clf);
3631 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3632 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3633 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3634 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3635 DeleteObject(hfont);
3639 static int CALLBACK create_fixed_pitch_font_proc(const LOGFONT *lpelfe,
3640 const TEXTMETRIC *lpntme,
3641 DWORD FontType, LPARAM lParam)
3643 const NEWTEXTMETRICEX *lpntmex = (const NEWTEXTMETRICEX *)lpntme;
3645 LOGFONT lf = *lpelfe;
3648 /* skip bitmap, proportional or vertical font */
3649 if ((FontType & TRUETYPE_FONTTYPE) == 0 ||
3650 (lf.lfPitchAndFamily & 0xf) != FIXED_PITCH ||
3651 lf.lfFaceName[0] == '@')
3654 /* skip linked font */
3655 if (!TranslateCharsetInfo((DWORD*)(INT_PTR)lpelfe->lfCharSet, &csi, TCI_SRCCHARSET) ||
3656 (lpntmex->ntmFontSig.fsCsb[0] & csi.fs.fsCsb[0]) == 0)
3659 /* test with an odd height */
3662 hfont = CreateFontIndirect(&lf);
3665 *(HFONT *)lParam = hfont;
3671 static void test_GetGlyphOutline(void)
3674 GLYPHMETRICS gm, gm2;
3676 HFONT hfont, old_hfont;
3685 {ANSI_CHARSET, 0x30, 0x30},
3686 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3687 {HANGEUL_CHARSET, 0x8141, 0xac02},
3688 {JOHAB_CHARSET, 0x8446, 0x3135},
3689 {GB2312_CHARSET, 0x8141, 0x4e04},
3690 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3694 if (!is_truetype_font_installed("Tahoma"))
3696 skip("Tahoma is not installed\n");
3700 hdc = CreateCompatibleDC(0);
3701 memset(&lf, 0, sizeof(lf));
3703 lstrcpyA(lf.lfFaceName, "Tahoma");
3704 SetLastError(0xdeadbeef);
3705 hfont = CreateFontIndirectA(&lf);
3706 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3707 old_hfont = SelectObject(hdc, hfont);
3709 memset(&gm, 0, sizeof(gm));
3710 SetLastError(0xdeadbeef);
3711 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3712 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3714 memset(&gm, 0, sizeof(gm));
3715 SetLastError(0xdeadbeef);
3716 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3717 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3718 ok(GetLastError() == 0xdeadbeef ||
3719 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3720 "expected 0xdeadbeef, got %u\n", GetLastError());
3722 memset(&gm, 0, sizeof(gm));
3723 SetLastError(0xdeadbeef);
3724 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3725 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3726 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3728 memset(&gm, 0, sizeof(gm));
3729 SetLastError(0xdeadbeef);
3730 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3731 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3733 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3734 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3737 /* test for needed buffer size request on space char */
3738 memset(&gm, 0, sizeof(gm));
3739 SetLastError(0xdeadbeef);
3740 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3741 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3742 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3744 /* requesting buffer size for space char + error */
3745 memset(&gm, 0, sizeof(gm));
3746 SetLastError(0xdeadbeef);
3747 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3748 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3750 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3751 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3754 SelectObject(hdc, old_hfont);
3755 DeleteObject(hfont);
3757 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3759 static const MAT2 rotate_mat = {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
3761 lf.lfFaceName[0] = '\0';
3762 lf.lfCharSet = c[i].cs;
3763 lf.lfPitchAndFamily = 0;
3764 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3766 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3770 old_hfont = SelectObject(hdc, hfont);
3772 /* expected to ignore superfluous bytes (sigle-byte character) */
3773 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3774 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3775 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3777 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3778 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3779 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3781 /* expected to ignore superfluous bytes (double-byte character) */
3782 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3783 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3784 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3785 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3787 /* expected to match wide-char version results */
3788 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3789 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3791 if (EnumFontFamiliesEx(hdc, &lf, create_fixed_pitch_font_proc, (LPARAM)&hfont, 0))
3793 skip("Fixed-pitch TrueType font for charset %u is not available\n", c[i].cs);
3796 DeleteObject(SelectObject(hdc, hfont));
3799 DeleteObject(SelectObject(hdc, old_hfont));
3803 ret = GetObject(hfont, sizeof lf, &lf);
3804 ok(ret > 0, "GetObject error %u\n", GetLastError());
3806 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3807 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3808 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
3809 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3810 trace("Tests with height=%d,half=%d,full=%d,face=%s,charset=%d\n",
3811 -lf.lfHeight, gm.gmCellIncX, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
3812 ok(gm2.gmCellIncX == gm.gmCellIncX * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
3813 "expected %d, got %d (%s:%d)\n",
3814 gm.gmCellIncX * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
3816 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &rotate_mat);
3817 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3818 ok(gm2.gmCellIncY == -lf.lfHeight,
3819 "expected %d, got %d (%s:%d)\n",
3820 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
3823 hfont = CreateFontIndirect(&lf);
3824 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
3825 DeleteObject(SelectObject(hdc, hfont));
3826 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3827 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3828 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
3829 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3830 ok(gm2.gmCellIncX == gm.gmCellIncX * 2 || broken(gm2.gmCellIncX == -lf.lfHeight),
3831 "expected %d, got %d (%s:%d)\n",
3832 gm.gmCellIncX * 2, gm2.gmCellIncX, lf.lfFaceName, lf.lfCharSet);
3834 lf.lfItalic = FALSE;
3835 lf.lfEscapement = lf.lfOrientation = 2700;
3836 hfont = CreateFontIndirect(&lf);
3837 ok(hfont != NULL, "CreateFontIndirect error %u\n", GetLastError());
3838 DeleteObject(SelectObject(hdc, hfont));
3839 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_METRICS, &gm2, 0, NULL, &mat);
3840 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3841 ok(gm2.gmCellIncY == -lf.lfHeight,
3842 "expected %d, got %d (%s:%d)\n",
3843 -lf.lfHeight, gm2.gmCellIncY, lf.lfFaceName, lf.lfCharSet);
3845 hfont = SelectObject(hdc, old_hfont);
3846 DeleteObject(hfont);
3852 /* bug #9995: there is a limit to the character width that can be specified */
3853 static void test_GetTextMetrics2(const char *fontname, int font_height)
3859 int ave_width, height, width, ratio, scale;
3861 if (!is_truetype_font_installed( fontname)) {
3862 skip("%s is not installed\n", fontname);
3865 hdc = CreateCompatibleDC(0);
3866 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3867 /* select width = 0 */
3868 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3869 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3870 DEFAULT_QUALITY, VARIABLE_PITCH,
3872 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3873 of = SelectObject( hdc, hf);
3874 ret = GetTextMetricsA( hdc, &tm);
3875 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3876 height = tm.tmHeight;
3877 ave_width = tm.tmAveCharWidth;
3878 SelectObject( hdc, of);
3881 trace("height %d, ave width %d\n", height, ave_width);
3883 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3885 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3886 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3887 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3888 ok(hf != 0, "CreateFont failed\n");
3889 of = SelectObject(hdc, hf);
3890 ret = GetTextMetrics(hdc, &tm);
3891 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3892 SelectObject(hdc, of);
3895 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3901 ratio = width / height;
3902 scale = width / ave_width;
3904 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3905 width, height, ratio, width, ave_width, scale);
3907 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3910 static void test_CreateFontIndirect(void)
3912 LOGFONTA lf, getobj_lf;
3915 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3917 memset(&lf, 0, sizeof(lf));
3918 lf.lfCharSet = ANSI_CHARSET;
3919 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3922 lf.lfQuality = DEFAULT_QUALITY;
3923 lf.lfItalic = FALSE;
3924 lf.lfWeight = FW_DONTCARE;
3926 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3928 lstrcpyA(lf.lfFaceName, TestName[i]);
3929 hfont = CreateFontIndirectA(&lf);
3930 ok(hfont != 0, "CreateFontIndirectA failed\n");
3931 SetLastError(0xdeadbeef);
3932 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3933 ok(ret, "GetObject failed: %d\n", GetLastError());
3934 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3935 ok(lf.lfWeight == getobj_lf.lfWeight ||
3936 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3937 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3938 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3939 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3940 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3941 DeleteObject(hfont);
3945 static void test_CreateFontIndirectEx(void)
3947 ENUMLOGFONTEXDVA lfex;
3950 if (!pCreateFontIndirectExA)
3952 win_skip("CreateFontIndirectExA is not available\n");
3956 if (!is_truetype_font_installed("Arial"))
3958 skip("Arial is not installed\n");
3962 SetLastError(0xdeadbeef);
3963 hfont = pCreateFontIndirectExA(NULL);
3964 ok(hfont == NULL, "got %p\n", hfont);
3965 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3967 memset(&lfex, 0, sizeof(lfex));
3968 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3969 hfont = pCreateFontIndirectExA(&lfex);
3970 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3972 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3973 DeleteObject(hfont);
3976 static void free_font(void *font)
3978 UnmapViewOfFile(font);
3981 static void *load_font(const char *font_name, DWORD *font_size)
3983 char file_name[MAX_PATH];
3984 HANDLE file, mapping;
3987 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3988 strcat(file_name, "\\fonts\\");
3989 strcat(file_name, font_name);
3991 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3992 if (file == INVALID_HANDLE_VALUE) return NULL;
3994 *font_size = GetFileSize(file, NULL);
3996 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
4003 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4006 CloseHandle(mapping);
4010 static void test_AddFontMemResource(void)
4013 DWORD font_size, num_fonts;
4017 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
4019 win_skip("AddFontMemResourceEx is not available on this platform\n");
4023 font = load_font("sserife.fon", &font_size);
4026 skip("Unable to locate and load font sserife.fon\n");
4030 SetLastError(0xdeadbeef);
4031 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
4032 ok(!ret, "AddFontMemResourceEx should fail\n");
4033 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4034 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4037 SetLastError(0xdeadbeef);
4038 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
4039 ok(!ret, "AddFontMemResourceEx should fail\n");
4040 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4041 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4044 SetLastError(0xdeadbeef);
4045 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
4046 ok(!ret, "AddFontMemResourceEx should fail\n");
4047 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4048 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4051 SetLastError(0xdeadbeef);
4052 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
4053 ok(!ret, "AddFontMemResourceEx should fail\n");
4054 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4055 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4058 SetLastError(0xdeadbeef);
4059 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
4060 ok(!ret, "AddFontMemResourceEx should fail\n");
4061 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4062 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4065 SetLastError(0xdeadbeef);
4066 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
4067 ok(!ret, "AddFontMemResourceEx should fail\n");
4068 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4069 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4072 num_fonts = 0xdeadbeef;
4073 SetLastError(0xdeadbeef);
4074 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
4075 ok(!ret, "AddFontMemResourceEx should fail\n");
4076 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4077 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4079 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4081 if (0) /* hangs under windows 2000 */
4083 num_fonts = 0xdeadbeef;
4084 SetLastError(0xdeadbeef);
4085 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
4086 ok(!ret, "AddFontMemResourceEx should fail\n");
4087 ok(GetLastError() == 0xdeadbeef,
4088 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4090 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4093 num_fonts = 0xdeadbeef;
4094 SetLastError(0xdeadbeef);
4095 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
4096 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
4097 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4098 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
4102 SetLastError(0xdeadbeef);
4103 bRet = pRemoveFontMemResourceEx(ret);
4104 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
4106 /* test invalid pointer to number of loaded fonts */
4107 font = load_font("sserife.fon", &font_size);
4108 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
4110 SetLastError(0xdeadbeef);
4111 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
4112 ok(!ret, "AddFontMemResourceEx should fail\n");
4113 ok(GetLastError() == 0xdeadbeef,
4114 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4117 SetLastError(0xdeadbeef);
4118 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
4119 ok(!ret, "AddFontMemResourceEx should fail\n");
4120 ok(GetLastError() == ERROR_INVALID_PARAMETER,
4121 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4127 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
4131 if (type != TRUETYPE_FONTTYPE) return 1;
4133 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4135 lf = (LOGFONT *)lparam;
4140 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
4145 if (type != TRUETYPE_FONTTYPE) return 1;
4147 lf = (LOGFONT *)lparam;
4148 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
4151 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
4158 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
4163 static void test_EnumFonts(void)
4169 if (!is_truetype_font_installed("Arial"))
4171 skip("Arial is not installed\n");
4175 /* Windows uses localized font face names, so Arial Bold won't be found */
4176 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
4178 skip("User locale is not English, skipping the test\n");
4182 hdc = CreateCompatibleDC(0);
4184 /* check that the enumproc's retval is returned */
4185 ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
4186 ok(ret == 0xcafe, "got %08x\n", ret);
4188 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
4189 ok(!ret, "font Arial is not enumerated\n");
4190 ret = strcmp(lf.lfFaceName, "Arial");
4191 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4192 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4194 lstrcpy(lf.lfFaceName, "Arial");
4195 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4196 ok(!ret, "font Arial is not enumerated\n");
4197 ret = strcmp(lf.lfFaceName, "Arial");
4198 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4199 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
4201 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
4202 ok(!ret, "font Arial Bold is not enumerated\n");
4203 ret = strcmp(lf.lfFaceName, "Arial");
4204 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4205 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4207 lstrcpy(lf.lfFaceName, "Arial Bold");
4208 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4209 ok(ret, "font Arial Bold should not be enumerated\n");
4211 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
4212 ok(!ret, "font Arial Bold Italic is not enumerated\n");
4213 ret = strcmp(lf.lfFaceName, "Arial");
4214 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
4215 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
4217 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
4218 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4219 ok(ret, "font Arial Bold Italic should not be enumerated\n");
4221 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
4222 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4224 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
4225 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
4226 ok(ret, "font Arial Italic Bold should not be enumerated\n");
4231 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
4233 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
4234 const char *fullname = (const char *)lParam;
4236 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
4241 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
4246 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
4253 static void test_fullname(void)
4255 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4256 WCHAR bufW[LF_FULLFACESIZE];
4257 char bufA[LF_FULLFACESIZE];
4264 hdc = CreateCompatibleDC(0);
4265 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4267 memset(&lf, 0, sizeof(lf));
4268 lf.lfCharSet = ANSI_CHARSET;
4269 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4272 lf.lfQuality = DEFAULT_QUALITY;
4273 lf.lfItalic = FALSE;
4274 lf.lfWeight = FW_DONTCARE;
4276 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4278 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4280 skip("%s is not installed\n", TestName[i]);
4284 lstrcpyA(lf.lfFaceName, TestName[i]);
4285 hfont = CreateFontIndirectA(&lf);
4286 ok(hfont != 0, "CreateFontIndirectA failed\n");
4288 of = SelectObject(hdc, hfont);
4291 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4292 ok(ret, "face full name could not be read\n");
4293 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4294 ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4295 SelectObject(hdc, of);
4296 DeleteObject(hfont);
4301 static WCHAR *prepend_at(WCHAR *family)
4306 memmove(family + 1, family, (lstrlenW(family) + 1) * sizeof(WCHAR));
4311 static void test_fullname2_helper(const char *Family)
4313 char *FamilyName, *FaceName, *StyleName, *otmStr;
4314 struct enum_fullname_data efnd;
4321 DWORD otm_size, ret, buf_size;
4322 OUTLINETEXTMETRICA *otm;
4323 BOOL want_vertical, get_vertical;
4324 want_vertical = ( Family[0] == '@' );
4326 hdc = CreateCompatibleDC(0);
4327 ok(hdc != NULL, "CreateCompatibleDC failed\n");
4329 memset(&lf, 0, sizeof(lf));
4330 lf.lfCharSet = DEFAULT_CHARSET;
4331 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4334 lf.lfQuality = DEFAULT_QUALITY;
4335 lf.lfItalic = FALSE;
4336 lf.lfWeight = FW_DONTCARE;
4337 lstrcpy(lf.lfFaceName, Family);
4339 EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4340 if (efnd.total == 0)
4341 skip("%s is not installed\n", lf.lfFaceName);
4343 for (i = 0; i < efnd.total; i++)
4345 FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4346 FaceName = (char *)efnd.elf[i].elfFullName;
4347 StyleName = (char *)efnd.elf[i].elfStyle;
4349 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4351 get_vertical = ( FamilyName[0] == '@' );
4352 ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4354 lstrcpyA(lf.lfFaceName, FaceName);
4355 hfont = CreateFontIndirectA(&lf);
4356 ok(hfont != 0, "CreateFontIndirectA failed\n");
4358 of = SelectObject(hdc, hfont);
4359 buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4360 ok(buf_size != GDI_ERROR, "no name table found\n");
4361 if (buf_size == GDI_ERROR) continue;
4363 bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4364 bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4366 otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4367 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4368 memset(otm, 0, otm_size);
4369 ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4370 ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4371 if (ret == 0) continue;
4375 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4378 trace("no localized FONT_FAMILY found.\n");
4379 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4381 ok(ret, "FAMILY (family name) could not be read\n");
4382 if (want_vertical) bufW = prepend_at(bufW);
4383 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4384 ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4385 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4386 ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4390 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4393 trace("no localized FULL_NAME found.\n");
4394 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4396 ok(ret, "FULL_NAME (face name) could not be read\n");
4397 if (want_vertical) bufW = prepend_at(bufW);
4398 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4399 ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4400 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4401 ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4405 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4408 trace("no localized FONT_SUBFAMILY found.\n");
4409 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4411 ok(ret, "SUBFAMILY (style name) could not be read\n");
4412 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4413 ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4414 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4415 ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4419 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4422 trace("no localized UNIQUE_ID found.\n");
4423 ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4425 ok(ret, "UNIQUE_ID (full name) could not be read\n");
4426 WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4427 otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4428 ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4430 SelectObject(hdc, of);
4431 DeleteObject(hfont);
4433 HeapFree(GetProcessHeap(), 0, otm);
4434 HeapFree(GetProcessHeap(), 0, bufW);
4435 HeapFree(GetProcessHeap(), 0, bufA);
4440 static void test_fullname2(void)
4442 test_fullname2_helper("Arial");
4443 test_fullname2_helper("DejaVu Sans");
4444 test_fullname2_helper("Lucida Sans");
4445 test_fullname2_helper("Tahoma");
4446 test_fullname2_helper("Webdings");
4447 test_fullname2_helper("Wingdings");
4448 test_fullname2_helper("SimSun");
4449 test_fullname2_helper("NSimSun");
4450 test_fullname2_helper("MingLiu");
4451 test_fullname2_helper("PMingLiu");
4452 test_fullname2_helper("WenQuanYi Micro Hei");
4453 test_fullname2_helper("MS UI Gothic");
4454 test_fullname2_helper("Ume UI Gothic");
4455 test_fullname2_helper("MS Gothic");
4456 test_fullname2_helper("Ume Gothic");
4457 test_fullname2_helper("MS PGothic");
4458 test_fullname2_helper("Ume P Gothic");
4459 test_fullname2_helper("Gulim");
4460 test_fullname2_helper("Batang");
4461 test_fullname2_helper("UnBatang");
4462 test_fullname2_helper("UnDotum");
4463 test_fullname2_helper("@SimSun");
4464 test_fullname2_helper("@NSimSun");
4465 test_fullname2_helper("@MingLiu");
4466 test_fullname2_helper("@PMingLiu");
4467 test_fullname2_helper("@WenQuanYi Micro Hei");
4468 test_fullname2_helper("@MS UI Gothic");
4469 test_fullname2_helper("@Ume UI Gothic");
4470 test_fullname2_helper("@MS Gothic");
4471 test_fullname2_helper("@Ume Gothic");
4472 test_fullname2_helper("@MS PGothic");
4473 test_fullname2_helper("@Ume P Gothic");
4474 test_fullname2_helper("@Gulim");
4475 test_fullname2_helper("@Batang");
4476 test_fullname2_helper("@UnBatang");
4477 test_fullname2_helper("@UnDotum");
4481 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4483 char tmp_path[MAX_PATH];
4490 SetLastError(0xdeadbeef);
4491 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4492 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4493 if (!rsrc) return FALSE;
4494 SetLastError(0xdeadbeef);
4495 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4496 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4497 if (!rsrc_data) return FALSE;
4498 SetLastError(0xdeadbeef);
4499 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4500 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4501 if (!rsrc_size) return FALSE;
4503 SetLastError(0xdeadbeef);
4504 ret = GetTempPath(MAX_PATH, tmp_path);
4505 ok(ret, "GetTempPath() error %d\n", GetLastError());
4506 SetLastError(0xdeadbeef);
4507 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4508 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4510 SetLastError(0xdeadbeef);
4511 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4512 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4513 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4515 SetLastError(0xdeadbeef);
4516 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4517 ok(ret, "WriteFile() error %d\n", GetLastError());
4523 static void test_GetGlyphOutline_empty_contour(void)
4527 HFONT hfont, hfont_prev;
4528 TTPOLYGONHEADER *header;
4533 memset(&lf, 0, sizeof(lf));
4535 lstrcpyA(lf.lfFaceName, "wine_test");
4537 hfont = CreateFontIndirectA(&lf);
4538 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
4542 hfont_prev = SelectObject(hdc, hfont);
4543 ok(hfont_prev != NULL, "SelectObject failed\n");
4545 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, 0, NULL, &mat);
4546 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4548 header = (TTPOLYGONHEADER*)buf;
4549 ret = GetGlyphOutlineW(hdc, 0xa8, GGO_NATIVE, &gm, sizeof(buf), buf, &mat);
4550 ok(ret == 228, "GetGlyphOutline returned %d, expected 228\n", ret);
4551 ok(header->cb == 36, "header->cb = %d, expected 36\n", header->cb);
4552 ok(header->dwType == TT_POLYGON_TYPE, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header->dwType);
4553 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4554 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4555 header = (TTPOLYGONHEADER*)((char*)header+header->cb);
4556 ok(header->cb == 96, "header->cb = %d, expected 96\n", header->cb);
4558 SelectObject(hdc, hfont_prev);
4559 DeleteObject(hfont);
4560 ReleaseDC(NULL, hdc);
4563 static void test_CreateScalableFontResource(void)
4565 char ttf_name[MAX_PATH];
4566 char tmp_path[MAX_PATH];
4567 char fot_name[MAX_PATH];
4572 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4574 win_skip("AddFontResourceExA is not available on this platform\n");
4578 if (!write_ttf_file("wine_test.ttf", ttf_name))
4580 skip("Failed to create ttf file for testing\n");
4584 trace("created %s\n", ttf_name);
4586 ret = is_truetype_font_installed("wine_test");
4587 ok(!ret, "font wine_test should not be enumerated\n");
4589 ret = GetTempPath(MAX_PATH, tmp_path);
4590 ok(ret, "GetTempPath() error %d\n", GetLastError());
4591 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4592 ok(ret, "GetTempFileName() error %d\n", GetLastError());
4594 ret = GetFileAttributes(fot_name);
4595 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4597 SetLastError(0xdeadbeef);
4598 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4599 ok(!ret, "CreateScalableFontResource() should fail\n");
4600 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4602 SetLastError(0xdeadbeef);
4603 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4604 ok(!ret, "CreateScalableFontResource() should fail\n");
4605 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4607 file_part = strrchr(ttf_name, '\\');
4608 SetLastError(0xdeadbeef);
4609 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4610 ok(!ret, "CreateScalableFontResource() should fail\n");
4611 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4613 SetLastError(0xdeadbeef);
4614 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4615 ok(!ret, "CreateScalableFontResource() should fail\n");
4616 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4618 SetLastError(0xdeadbeef);
4619 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4620 ok(!ret, "CreateScalableFontResource() should fail\n");
4621 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4623 ret = DeleteFile(fot_name);
4624 ok(ret, "DeleteFile() error %d\n", GetLastError());
4626 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4627 ok(!ret, "RemoveFontResourceEx() should fail\n");
4629 /* test public font resource */
4630 SetLastError(0xdeadbeef);
4631 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4632 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4634 ret = is_truetype_font_installed("wine_test");
4635 ok(!ret, "font wine_test should not be enumerated\n");
4637 SetLastError(0xdeadbeef);
4638 ret = pAddFontResourceExA(fot_name, 0, 0);
4639 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4641 ret = is_truetype_font_installed("wine_test");
4642 ok(ret, "font wine_test should be enumerated\n");
4644 test_GetGlyphOutline_empty_contour();
4646 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4647 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4649 SetLastError(0xdeadbeef);
4650 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4651 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4653 ret = is_truetype_font_installed("wine_test");
4654 ok(!ret, "font wine_test should not be enumerated\n");
4656 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4657 ok(!ret, "RemoveFontResourceEx() should fail\n");
4659 /* test refcounting */
4660 for (i = 0; i < 5; i++)
4662 SetLastError(0xdeadbeef);
4663 ret = pAddFontResourceExA(fot_name, 0, 0);
4664 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4666 for (i = 0; i < 5; i++)
4668 SetLastError(0xdeadbeef);
4669 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4670 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4672 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4673 ok(!ret, "RemoveFontResourceEx() should fail\n");
4675 DeleteFile(fot_name);
4677 /* test hidden font resource */
4678 SetLastError(0xdeadbeef);
4679 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4680 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4682 ret = is_truetype_font_installed("wine_test");
4683 ok(!ret, "font wine_test should not be enumerated\n");
4685 SetLastError(0xdeadbeef);
4686 ret = pAddFontResourceExA(fot_name, 0, 0);
4687 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4689 ret = is_truetype_font_installed("wine_test");
4691 ok(!ret, "font wine_test should not be enumerated\n");
4693 /* XP allows removing a private font added with 0 flags */
4694 SetLastError(0xdeadbeef);
4695 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4696 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4698 ret = is_truetype_font_installed("wine_test");
4699 ok(!ret, "font wine_test should not be enumerated\n");
4701 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4702 ok(!ret, "RemoveFontResourceEx() should fail\n");
4704 DeleteFile(fot_name);
4705 DeleteFile(ttf_name);
4708 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4711 HFONT hfont, hfont_prev;
4715 static const WCHAR str[] = { 0x2025 };
4717 *installed = is_truetype_font_installed(name);
4721 lf.lfEscapement = 0;
4722 lf.lfOrientation = 0;
4723 lf.lfWeight = FW_DONTCARE;
4727 lf.lfCharSet = DEFAULT_CHARSET;
4728 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4729 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4730 lf.lfQuality = DEFAULT_QUALITY;
4731 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4732 strcpy(lf.lfFaceName, name);
4734 hfont = CreateFontIndirectA(&lf);
4735 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4739 hfont_prev = SelectObject(hdc, hfont);
4740 ok(hfont_prev != NULL, "SelectObject failed\n");
4742 ret = GetTextFaceA(hdc, sizeof facename, facename);
4743 ok(ret, "GetTextFaceA failed\n");
4744 *selected = !strcmp(facename, name);
4746 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4747 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4749 memset(gm, 0, sizeof *gm);
4751 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4752 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4754 SelectObject(hdc, hfont_prev);
4755 DeleteObject(hfont);
4756 ReleaseDC(NULL, hdc);
4759 static void test_vertical_font(void)
4761 char ttf_name[MAX_PATH];
4763 BOOL ret, installed, selected;
4767 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4769 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4773 if (!write_ttf_file("vertical.ttf", ttf_name))
4775 skip("Failed to create ttf file for testing\n");
4779 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4780 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4782 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4783 ok(installed, "@WineTestVertical is not installed\n");
4784 ok(selected, "@WineTestVertical is not selected\n");
4785 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4786 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4787 gm.gmBlackBoxX, gm.gmBlackBoxY);
4789 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4790 ok(installed, "@@WineTestVertical is not installed\n");
4791 ok(selected, "@@WineTestVertical is not selected\n");
4792 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4793 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4794 gm.gmBlackBoxX, gm.gmBlackBoxY);
4796 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4798 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4799 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4801 DeleteFile(ttf_name);
4804 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4805 DWORD type, LPARAM lParam)
4807 if (lf->lfFaceName[0] == '@') {
4813 static void test_east_asian_font_selection(void)
4816 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4817 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4822 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4826 char face_name[LF_FACESIZE];
4829 memset(&lf, 0, sizeof lf);
4830 lf.lfFaceName[0] = '\0';
4831 lf.lfCharSet = charset[i];
4833 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4835 skip("Vertical font for charset %u is not installed\n", charset[i]);
4839 hfont = CreateFontIndirectA(&lf);
4840 hfont = SelectObject(hdc, hfont);
4841 memset(face_name, 0, sizeof face_name);
4842 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4843 ok(ret && face_name[0] != '@',
4844 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4845 DeleteObject(SelectObject(hdc, hfont));
4847 memset(&lf, 0, sizeof lf);
4848 strcpy(lf.lfFaceName, "@");
4849 lf.lfCharSet = charset[i];
4850 hfont = CreateFontIndirectA(&lf);
4851 hfont = SelectObject(hdc, hfont);
4852 memset(face_name, 0, sizeof face_name);
4853 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4854 ok(ret && face_name[0] == '@',
4855 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4856 DeleteObject(SelectObject(hdc, hfont));
4858 ReleaseDC(NULL, hdc);
4861 static int get_font_dpi(const LOGFONT *lf)
4863 HDC hdc = CreateCompatibleDC(0);
4868 hfont = CreateFontIndirect(lf);
4869 ok(hfont != 0, "CreateFontIndirect failed\n");
4871 SelectObject(hdc, hfont);
4872 ret = GetTextMetrics(hdc, &tm);
4873 ok(ret, "GetTextMetrics failed\n");
4874 ret = tm.tmDigitizedAspectX;
4877 DeleteObject(hfont);
4882 static void test_stock_fonts(void)
4884 static const int font[] =
4886 ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4887 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4889 static const struct test_data
4891 int charset, weight, height, dpi;
4892 const char face_name[LF_FACESIZE];
4895 { /* ANSI_FIXED_FONT */
4896 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4897 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4900 { /* ANSI_VAR_FONT */
4901 { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4902 { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4906 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4907 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4908 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4909 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4910 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4911 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4914 { /* DEVICE_DEFAULT_FONT */
4915 { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4916 { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4917 { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4918 { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4919 { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4920 { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4923 { /* DEFAULT_GUI_FONT */
4924 { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4925 { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4926 { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4927 { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4928 { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4929 { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4930 { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4931 { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4932 { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4933 { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4939 for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4945 hfont = GetStockObject(font[i]);
4946 ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4948 ret = GetObject(hfont, sizeof(lf), &lf);
4949 if (ret != sizeof(lf))
4952 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4956 for (j = 0; td[i][j].face_name[0] != 0; j++)
4958 if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4963 ret = get_font_dpi(&lf);
4964 if (ret != td[i][j].dpi)
4966 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4967 i, j, lf.lfFaceName, ret, td[i][j].dpi);
4971 ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4972 ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4973 if (td[i][j].face_name[0] == '?')
4975 /* Wine doesn't have this font, skip this case for now.
4976 Actually, the face name is localized on Windows and varies
4977 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4978 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4982 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);
4996 test_outline_font();
4997 test_bitmap_font_metrics();
4998 test_GdiGetCharDimensions();
4999 test_GetCharABCWidths();
5000 test_text_extents();
5001 test_GetGlyphIndices();
5002 test_GetKerningPairs();
5003 test_GetOutlineTextMetrics();
5004 test_SetTextJustification();
5005 test_font_charset();
5006 test_GdiGetCodePage();
5007 test_GetFontUnicodeRanges();
5008 test_nonexistent_font();
5010 test_height_selection();
5011 test_AddFontMemResource();
5014 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
5015 * I'd like to avoid them in this test.
5017 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
5018 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
5019 if (is_truetype_font_installed("Arial Black") &&
5020 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
5022 test_EnumFontFamilies("", ANSI_CHARSET);
5023 test_EnumFontFamilies("", SYMBOL_CHARSET);
5024 test_EnumFontFamilies("", DEFAULT_CHARSET);
5027 skip("Arial Black or Symbol/Wingdings is not installed\n");
5028 test_EnumFontFamiliesEx_default_charset();
5029 test_GetTextMetrics();
5030 test_GdiRealizationInfo();
5032 test_GetGlyphOutline();
5033 test_GetTextMetrics2("Tahoma", -11);
5034 test_GetTextMetrics2("Tahoma", -55);
5035 test_GetTextMetrics2("Tahoma", -110);
5036 test_GetTextMetrics2("Arial", -11);
5037 test_GetTextMetrics2("Arial", -55);
5038 test_GetTextMetrics2("Arial", -110);
5039 test_CreateFontIndirect();
5040 test_CreateFontIndirectEx();
5044 test_east_asian_font_selection();
5046 /* These tests should be last test until RemoveFontResource
5047 * is properly implemented.
5049 test_vertical_font();
5050 test_CreateScalableFontResource();