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 #define near_match(a, b) (abs((a) - (b)) <= 6)
34 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
36 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
37 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
38 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
39 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
40 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
41 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
42 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
44 static HMODULE hgdi32 = 0;
46 static void init(void)
48 hgdi32 = GetModuleHandleA("gdi32.dll");
50 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
51 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
52 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
53 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
54 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
55 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
56 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
59 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
61 if (type != TRUETYPE_FONTTYPE) return 1;
66 static BOOL is_truetype_font_installed(const char *name)
71 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
78 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
83 static BOOL is_font_installed(const char *name)
88 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
95 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
103 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
104 /* NT4 tries to be clever and only returns the minimum length */
105 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
107 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
108 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
109 ok(lf->lfHeight == getobj_lf.lfHeight ||
110 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
111 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
112 ok(lf->lfWidth == getobj_lf.lfWidth ||
113 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
114 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
115 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
116 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
117 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
118 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
119 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
120 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
121 ok(lf->lfWeight == getobj_lf.lfWeight ||
122 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
123 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
124 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
125 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
126 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
127 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
128 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
129 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
130 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
131 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
132 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
133 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
134 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
137 static HFONT create_font(const char* test, const LOGFONTA* lf)
139 HFONT hfont = CreateFontIndirectA(lf);
140 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
142 check_font(test, lf, hfont);
146 static void test_logfont(void)
151 memset(&lf, 0, sizeof lf);
153 lf.lfCharSet = ANSI_CHARSET;
154 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
155 lf.lfWeight = FW_DONTCARE;
158 lf.lfQuality = DEFAULT_QUALITY;
160 lstrcpyA(lf.lfFaceName, "Arial");
161 hfont = create_font("Arial", &lf);
164 memset(&lf, 'A', sizeof(lf));
165 hfont = CreateFontIndirectA(&lf);
166 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
168 lf.lfFaceName[LF_FACESIZE - 1] = 0;
169 check_font("AAA...", &lf, hfont);
173 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
175 if (type & RASTER_FONTTYPE)
177 LOGFONT *lf = (LOGFONT *)lParam;
179 return 0; /* stop enumeration */
182 return 1; /* continue enumeration */
185 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
187 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
188 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
189 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
190 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
191 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
192 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
193 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
194 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
195 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
196 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
197 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
198 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
199 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
200 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
201 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
202 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
203 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
204 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
205 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
206 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
209 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
210 LONG lfWidth, const char *test_str,
211 INT test_str_len, const TEXTMETRICA *tm_orig,
212 const SIZE *size_orig, INT width_of_A_orig,
213 INT scale_x, INT scale_y)
216 OUTLINETEXTMETRIC otm;
219 INT width_of_A, cx, cy;
225 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
227 GetObjectA(hfont, sizeof(lf), &lf);
229 if (GetOutlineTextMetricsA(hdc, 0, NULL))
231 otm.otmSize = sizeof(otm) / 2;
232 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
233 ok(ret == sizeof(otm)/2 /* XP */ ||
234 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
236 memset(&otm, 0x1, sizeof(otm));
237 otm.otmSize = sizeof(otm);
238 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
239 ok(ret == sizeof(otm) /* XP */ ||
240 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
242 memset(&tm, 0x2, sizeof(tm));
243 ret = GetTextMetricsA(hdc, &tm);
244 ok(ret, "GetTextMetricsA failed\n");
245 /* the structure size is aligned */
246 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
248 ok(0, "tm != otm\n");
249 compare_tm(&tm, &otm.otmTextMetrics);
252 tm = otm.otmTextMetrics;
253 if (0) /* these metrics are scaled too, but with rounding errors */
255 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
256 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
258 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
259 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
260 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
261 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
262 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
263 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
267 ret = GetTextMetricsA(hdc, &tm);
268 ok(ret, "GetTextMetricsA failed\n");
271 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
272 cy = tm.tmHeight / tm_orig->tmHeight;
273 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
274 lfHeight, scale_x, scale_y, cx, cy);
275 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
276 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
277 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
278 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
279 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
281 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
285 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
288 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
290 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
292 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
293 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
295 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
297 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);
300 /* Test how GDI scales bitmap font metrics */
301 static void test_bitmap_font(void)
303 static const char test_str[11] = "Test String";
306 HFONT hfont, old_hfont;
309 INT ret, i, width_orig, height_orig, scale, lfWidth;
313 /* "System" has only 1 pixel size defined, otherwise the test breaks */
314 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
318 trace("no bitmap fonts were found, skipping the test\n");
322 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
324 height_orig = bitmap_lf.lfHeight;
325 lfWidth = bitmap_lf.lfWidth;
327 hfont = create_font("bitmap", &bitmap_lf);
328 old_hfont = SelectObject(hdc, hfont);
329 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
330 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
331 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
332 SelectObject(hdc, old_hfont);
335 bitmap_lf.lfHeight = 0;
336 bitmap_lf.lfWidth = 4;
337 hfont = create_font("bitmap", &bitmap_lf);
338 old_hfont = SelectObject(hdc, hfont);
339 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
340 SelectObject(hdc, old_hfont);
343 bitmap_lf.lfHeight = height_orig;
344 bitmap_lf.lfWidth = lfWidth;
346 /* test fractional scaling */
347 for (i = 1; i <= height_orig * 6; i++)
351 bitmap_lf.lfHeight = i;
352 hfont = create_font("fractional", &bitmap_lf);
353 scale = (i + height_orig - 1) / height_orig;
354 nearest_height = scale * height_orig;
355 /* Only jump to the next height if the difference <= 25% original height */
356 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
357 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
358 so we'll not test this particular height. */
359 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
360 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
361 old_hfont = SelectObject(hdc, hfont);
362 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
363 SelectObject(hdc, old_hfont);
367 /* test integer scaling 3x2 */
368 bitmap_lf.lfHeight = height_orig * 2;
369 bitmap_lf.lfWidth *= 3;
370 hfont = create_font("3x2", &bitmap_lf);
371 old_hfont = SelectObject(hdc, hfont);
372 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
373 SelectObject(hdc, old_hfont);
376 /* test integer scaling 3x3 */
377 bitmap_lf.lfHeight = height_orig * 3;
378 bitmap_lf.lfWidth = 0;
379 hfont = create_font("3x3", &bitmap_lf);
380 old_hfont = SelectObject(hdc, hfont);
381 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
382 SelectObject(hdc, old_hfont);
388 /* Test how GDI scales outline font metrics */
389 static void test_outline_font(void)
391 static const char test_str[11] = "Test String";
394 HFONT hfont, old_hfont, old_hfont_2;
395 OUTLINETEXTMETRICA otm;
397 INT width_orig, height_orig, lfWidth;
400 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
401 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
405 if (!is_truetype_font_installed("Arial"))
407 skip("Arial is not installed\n");
411 hdc = CreateCompatibleDC(0);
413 memset(&lf, 0, sizeof(lf));
414 strcpy(lf.lfFaceName, "Arial");
416 hfont = create_font("outline", &lf);
417 old_hfont = SelectObject(hdc, hfont);
418 otm.otmSize = sizeof(otm);
419 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
420 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
421 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
423 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
424 SelectObject(hdc, old_hfont);
427 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
428 lf.lfHeight = otm.otmEMSquare;
429 lf.lfHeight = -lf.lfHeight;
430 hfont = create_font("outline", &lf);
431 old_hfont = SelectObject(hdc, hfont);
432 otm.otmSize = sizeof(otm);
433 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
434 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
435 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
436 SelectObject(hdc, old_hfont);
439 height_orig = otm.otmTextMetrics.tmHeight;
440 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
442 /* test integer scaling 3x2 */
443 lf.lfHeight = height_orig * 2;
444 lf.lfWidth = lfWidth * 3;
445 hfont = create_font("3x2", &lf);
446 old_hfont = SelectObject(hdc, hfont);
447 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
448 SelectObject(hdc, old_hfont);
451 /* test integer scaling 3x3 */
452 lf.lfHeight = height_orig * 3;
453 lf.lfWidth = lfWidth * 3;
454 hfont = create_font("3x3", &lf);
455 old_hfont = SelectObject(hdc, hfont);
456 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
457 SelectObject(hdc, old_hfont);
460 /* test integer scaling 1x1 */
461 lf.lfHeight = height_orig * 1;
462 lf.lfWidth = lfWidth * 1;
463 hfont = create_font("1x1", &lf);
464 old_hfont = SelectObject(hdc, hfont);
465 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
466 SelectObject(hdc, old_hfont);
469 /* test integer scaling 1x1 */
470 lf.lfHeight = height_orig;
472 hfont = create_font("1x1", &lf);
473 old_hfont = SelectObject(hdc, hfont);
474 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
476 /* with an identity matrix */
477 memset(&gm, 0, sizeof(gm));
478 SetLastError(0xdeadbeef);
479 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
480 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
481 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
482 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
483 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
484 /* with a custom matrix */
485 memset(&gm, 0, sizeof(gm));
486 SetLastError(0xdeadbeef);
487 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
488 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
489 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
490 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
491 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
493 /* Test that changing the DC transformation affects only the font
494 * selected on this DC and doesn't affect the same font selected on
497 hdc_2 = CreateCompatibleDC(0);
498 old_hfont_2 = SelectObject(hdc_2, hfont);
499 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
501 SetMapMode(hdc, MM_ANISOTROPIC);
503 /* font metrics on another DC should be unchanged */
504 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
506 /* test restrictions of compatibility mode GM_COMPATIBLE */
507 /* part 1: rescaling only X should not change font scaling on screen.
508 So compressing the X axis by 2 is not done, and this
509 appears as X scaling of 2 that no one requested. */
510 SetWindowExtEx(hdc, 100, 100, NULL);
511 SetViewportExtEx(hdc, 50, 100, NULL);
512 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
513 /* font metrics on another DC should be unchanged */
514 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
516 /* part 2: rescaling only Y should change font scaling.
517 As also X is scaled by a factor of 2, but this is not
518 requested by the DC transformation, we get a scaling factor
519 of 2 in the X coordinate. */
520 SetViewportExtEx(hdc, 100, 200, NULL);
521 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* restore scaling */
526 SetMapMode(hdc, MM_TEXT);
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 SelectObject(hdc_2, old_hfont_2);
534 if (!SetGraphicsMode(hdc, GM_ADVANCED))
536 SelectObject(hdc, old_hfont);
539 skip("GM_ADVANCED is not supported on this platform\n");
550 SetLastError(0xdeadbeef);
551 ret = SetWorldTransform(hdc, &xform);
552 ok(ret, "SetWorldTransform error %u\n", GetLastError());
554 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 /* with an identity matrix */
557 memset(&gm, 0, sizeof(gm));
558 SetLastError(0xdeadbeef);
559 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
560 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
561 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
562 pt.x = width_orig; pt.y = 0;
564 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
565 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
566 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
567 /* with a custom matrix */
568 memset(&gm, 0, sizeof(gm));
569 SetLastError(0xdeadbeef);
570 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
571 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
572 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
573 pt.x = width_orig; pt.y = 0;
575 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
576 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
577 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
579 SetLastError(0xdeadbeef);
580 ret = SetMapMode(hdc, MM_LOMETRIC);
581 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
583 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
585 /* with an identity matrix */
586 memset(&gm, 0, sizeof(gm));
587 SetLastError(0xdeadbeef);
588 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
589 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
590 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
591 pt.x = width_orig; pt.y = 0;
593 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
594 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
595 /* with a custom matrix */
596 memset(&gm, 0, sizeof(gm));
597 SetLastError(0xdeadbeef);
598 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
599 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
600 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
601 pt.x = width_orig; pt.y = 0;
603 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
604 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
606 SetLastError(0xdeadbeef);
607 ret = SetMapMode(hdc, MM_TEXT);
608 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
610 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
612 /* with an identity matrix */
613 memset(&gm, 0, sizeof(gm));
614 SetLastError(0xdeadbeef);
615 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
616 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
617 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
618 pt.x = width_orig; pt.y = 0;
620 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
621 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
622 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
623 /* with a custom matrix */
624 memset(&gm, 0, sizeof(gm));
625 SetLastError(0xdeadbeef);
626 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
627 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
628 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
629 pt.x = width_orig; pt.y = 0;
631 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
632 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
633 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
635 SelectObject(hdc, old_hfont);
640 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
642 LOGFONT *lf = (LOGFONT *)lParam;
644 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
647 return 0; /* stop enumeration */
649 return 1; /* continue enumeration */
652 static void test_bitmap_font_metrics(void)
654 static const struct font_data
656 const char face_name[LF_FACESIZE];
657 int weight, height, ascent, descent, int_leading, ext_leading;
658 int ave_char_width, max_char_width, dpi;
662 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
663 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
664 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
665 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
666 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
667 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
668 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
669 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
670 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
671 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
672 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
674 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
675 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
676 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
677 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
679 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
680 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
681 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
683 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
684 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
685 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
686 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
687 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
688 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
689 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
690 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
691 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
692 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
693 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
694 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
695 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
696 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
697 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
698 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
699 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
701 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
702 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
703 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
705 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
706 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
707 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
708 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
709 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
710 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
711 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
713 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
714 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
715 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
717 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
718 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
719 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
721 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
722 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
724 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
725 * require a new system.sfd for that font
727 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
729 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
730 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
732 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
733 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
734 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
735 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
736 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
737 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
738 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
739 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
740 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
741 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
742 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
743 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
744 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
745 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
746 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
747 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
748 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
750 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
751 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
752 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
753 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
754 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
755 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
756 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
757 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
759 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
760 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
761 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
763 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
764 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
765 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
767 /* The 120dpi version still has its dpi marked as 96 */
768 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
770 /* FIXME: add "Terminal" */
774 HFONT hfont, old_hfont;
778 hdc = CreateCompatibleDC(0);
781 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
785 memset(&lf, 0, sizeof(lf));
787 lf.lfHeight = fd[i].height;
788 strcpy(lf.lfFaceName, fd[i].face_name);
790 for(bit = 0; bit < 32; bit++)
797 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
798 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
800 lf.lfCharSet = csi.ciCharset;
801 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
804 hfont = create_font(lf.lfFaceName, &lf);
805 old_hfont = SelectObject(hdc, hfont);
806 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
807 if(fd[i].dpi == tm.tmDigitizedAspectX)
809 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
810 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
811 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);
812 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
813 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
814 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
815 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
816 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
818 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
819 that make the max width bigger */
820 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
821 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
823 SelectObject(hdc, old_hfont);
831 static void test_GdiGetCharDimensions(void)
837 LONG avgwidth, height;
838 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
840 if (!pGdiGetCharDimensions)
842 win_skip("GdiGetCharDimensions not available on this platform\n");
846 hdc = CreateCompatibleDC(NULL);
848 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
849 avgwidth = ((size.cx / 26) + 1) / 2;
851 ret = pGdiGetCharDimensions(hdc, &tm, &height);
852 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
853 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
855 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
856 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
858 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
859 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
862 ret = pGdiGetCharDimensions(hdc, NULL, &height);
863 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
864 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
869 static void test_GetCharABCWidths(void)
871 static const WCHAR str[] = {'a',0};
880 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
882 win_skip("GetCharABCWidthsW/I not available on this platform\n");
886 memset(&lf, 0, sizeof(lf));
887 strcpy(lf.lfFaceName, "System");
890 hfont = CreateFontIndirectA(&lf);
892 hfont = SelectObject(hdc, hfont);
894 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
895 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
897 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
898 ok(!ret, "GetCharABCWidthsI should have failed\n");
900 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
901 ok(!ret, "GetCharABCWidthsI should have failed\n");
903 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
904 ok(ret, "GetCharABCWidthsI should have succeeded\n");
906 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
907 ok(!ret, "GetCharABCWidthsW should have failed\n");
909 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
910 ok(!ret, "GetCharABCWidthsW should have failed\n");
912 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
913 ok(!ret, "GetCharABCWidthsW should have failed\n");
915 hfont = SelectObject(hdc, hfont);
917 ReleaseDC(NULL, hdc);
920 static void test_text_extents(void)
922 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
924 INT i, len, fit1, fit2;
932 memset(&lf, 0, sizeof(lf));
933 strcpy(lf.lfFaceName, "Arial");
936 hfont = CreateFontIndirectA(&lf);
938 hfont = SelectObject(hdc, hfont);
939 GetTextMetricsA(hdc, &tm);
940 GetTextExtentPointA(hdc, "o", 1, &sz);
941 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
943 SetLastError(0xdeadbeef);
944 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
945 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
947 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
948 hfont = SelectObject(hdc, hfont);
955 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
956 extents[0] = 1; /* So that the increasing sequence test will fail
957 if the extents array is untouched. */
958 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
959 GetTextExtentPointW(hdc, wt, len, &sz2);
961 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
962 /* Because of the '\n' in the string GetTextExtentExPoint and
963 GetTextExtentPoint return different widths under Win2k, but
964 under WinXP they return the same width. So we don't test that
967 for (i = 1; i < len; ++i)
968 ok(extents[i-1] <= extents[i],
969 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
971 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
972 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
973 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
974 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
975 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
976 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
977 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
978 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
979 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
980 ok(extents[0] == extents[2] && extents[1] == extents[3],
981 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
982 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
983 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
984 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
985 HeapFree(GetProcessHeap(), 0, extents);
987 hfont = SelectObject(hdc, hfont);
989 ReleaseDC(NULL, hdc);
992 static void test_GetGlyphIndices(void)
999 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1000 WORD glyphs[(sizeof(testtext)/2)-1];
1004 if (!pGetGlyphIndicesW) {
1005 win_skip("GetGlyphIndicesW not available on platform\n");
1011 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1012 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1013 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1014 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1015 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1017 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1018 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1019 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1020 textm.tmDefaultChar, glyphs[4]);
1022 if(!is_font_installed("Tahoma"))
1024 skip("Tahoma is not installed so skipping this test\n");
1027 memset(&lf, 0, sizeof(lf));
1028 strcpy(lf.lfFaceName, "Tahoma");
1031 hfont = CreateFontIndirectA(&lf);
1032 hOldFont = SelectObject(hdc, hfont);
1033 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1034 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1035 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1036 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1037 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1039 testtext[0] = textm.tmDefaultChar;
1040 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1041 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1042 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1043 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1044 DeleteObject(SelectObject(hdc, hOldFont));
1047 static void test_GetKerningPairs(void)
1049 static const struct kerning_data
1051 const char face_name[LF_FACESIZE];
1053 /* some interesting fields from OUTLINETEXTMETRIC */
1054 LONG tmHeight, tmAscent, tmDescent;
1059 UINT otmsCapEmHeight;
1064 UINT otmusMinimumPPEM;
1065 /* small subset of kerning pairs to test */
1066 DWORD total_kern_pairs;
1067 const KERNINGPAIR kern_pair[26];
1070 {"Arial", 12, 12, 9, 3,
1071 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1074 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1075 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1076 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1077 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1078 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1079 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1080 {933,970,+1},{933,972,-1}
1083 {"Arial", -34, 39, 32, 7,
1084 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1087 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1088 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1089 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1090 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1091 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1092 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1093 {933,970,+2},{933,972,-3}
1096 { "Arial", 120, 120, 97, 23,
1097 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1100 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1101 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1102 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1103 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1104 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1105 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1106 {933,970,+6},{933,972,-10}
1109 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1110 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1111 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1114 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1115 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1116 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1117 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1118 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1119 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1120 {933,970,+54},{933,972,-83}
1126 HFONT hfont, hfont_old;
1127 KERNINGPAIR *kern_pair;
1129 DWORD total_kern_pairs, ret, i, n, matches;
1133 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1134 * which may render this test unusable, so we're trying to avoid that.
1136 SetLastError(0xdeadbeef);
1137 GetKerningPairsW(hdc, 0, NULL);
1138 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1140 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1145 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1147 OUTLINETEXTMETRICW otm;
1149 if (!is_font_installed(kd[i].face_name))
1151 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1155 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1157 memset(&lf, 0, sizeof(lf));
1158 strcpy(lf.lfFaceName, kd[i].face_name);
1159 lf.lfHeight = kd[i].height;
1160 hfont = CreateFontIndirect(&lf);
1163 hfont_old = SelectObject(hdc, hfont);
1165 SetLastError(0xdeadbeef);
1166 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1167 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1169 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1170 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1171 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1172 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1173 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1174 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1176 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1177 kd[i].otmEMSquare, otm.otmEMSquare);
1178 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1179 kd[i].otmAscent, otm.otmAscent);
1180 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1181 kd[i].otmDescent, otm.otmDescent);
1182 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1183 kd[i].otmLineGap, otm.otmLineGap);
1184 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1185 kd[i].otmMacDescent, otm.otmMacDescent);
1187 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1188 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1189 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1190 kd[i].otmsXHeight, otm.otmsXHeight);
1191 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1192 kd[i].otmMacAscent, otm.otmMacAscent);
1193 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1194 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1195 kd[i].otmMacLineGap, otm.otmMacLineGap);
1196 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1197 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1200 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1201 trace("total_kern_pairs %u\n", total_kern_pairs);
1202 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1204 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1205 SetLastError(0xdeadbeef);
1206 ret = GetKerningPairsW(hdc, 0, kern_pair);
1207 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1208 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1209 ok(ret == 0, "got %lu, expected 0\n", ret);
1212 ret = GetKerningPairsW(hdc, 100, NULL);
1213 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1215 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1216 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1218 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1219 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1223 for (n = 0; n < ret; n++)
1227 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1228 trace("{'%c','%c',%d},\n",
1229 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1231 for (j = 0; j < kd[i].total_kern_pairs; j++)
1233 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1234 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1236 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1237 "pair %d:%d got %d, expected %d\n",
1238 kern_pair[n].wFirst, kern_pair[n].wSecond,
1239 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1245 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1246 matches, kd[i].total_kern_pairs);
1248 HeapFree(GetProcessHeap(), 0, kern_pair);
1250 SelectObject(hdc, hfont_old);
1251 DeleteObject(hfont);
1257 static void test_GetOutlineTextMetrics(void)
1259 OUTLINETEXTMETRIC *otm;
1261 HFONT hfont, hfont_old;
1263 DWORD ret, otm_size;
1266 if (!is_font_installed("Arial"))
1268 skip("Arial is not installed\n");
1274 memset(&lf, 0, sizeof(lf));
1275 strcpy(lf.lfFaceName, "Arial");
1277 lf.lfWeight = FW_NORMAL;
1278 lf.lfPitchAndFamily = DEFAULT_PITCH;
1279 lf.lfQuality = PROOF_QUALITY;
1280 hfont = CreateFontIndirect(&lf);
1283 hfont_old = SelectObject(hdc, hfont);
1284 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1285 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1287 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1289 memset(otm, 0xAA, otm_size);
1290 SetLastError(0xdeadbeef);
1291 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1292 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1293 ok(ret == 1 /* Win9x */ ||
1294 ret == otm->otmSize /* XP*/,
1295 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1296 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1298 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1299 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1300 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1301 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1304 memset(otm, 0xAA, otm_size);
1305 SetLastError(0xdeadbeef);
1306 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1307 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1308 ok(ret == 1 /* Win9x */ ||
1309 ret == otm->otmSize /* XP*/,
1310 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1311 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1313 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1314 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1315 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1316 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1319 /* ask about truncated data */
1320 memset(otm, 0xAA, otm_size);
1321 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1322 SetLastError(0xdeadbeef);
1323 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1324 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1325 ok(ret == 1 /* Win9x */ ||
1326 ret == otm->otmSize /* XP*/,
1327 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1328 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1330 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1331 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1332 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1334 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1336 HeapFree(GetProcessHeap(), 0, otm);
1338 SelectObject(hdc, hfont_old);
1339 DeleteObject(hfont);
1344 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1348 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1349 areaWidth = clientArea->right - clientArea->left,
1351 BOOL lastExtent = FALSE;
1352 PSTR pFirstChar, pLastChar;
1358 int GetTextExtentExPointWWidth;
1361 GetTextMetricsA(hdc, &tm);
1362 y = clientArea->top;
1365 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1371 /* if not at the end of the string, ... */
1372 if (*str == '\0') break;
1373 /* ... add the next word to the current extent */
1374 while (*str != '\0' && *str++ != tm.tmBreakChar);
1376 SetTextJustification(hdc, 0, 0);
1377 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1378 } while ((int) size.cx < areaWidth);
1380 /* ignore trailing break chars */
1382 while (*(pLastChar - 1) == tm.tmBreakChar)
1388 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1390 SetTextJustification(hdc, 0, 0);
1391 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1393 /* do not justify the last extent */
1394 if (*str != '\0' && breakCount > 0)
1396 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1397 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1398 justifiedWidth = size.cx;
1400 else lastExtent = TRUE;
1402 /* catch errors and report them */
1403 if (!lastExtent && (justifiedWidth != areaWidth))
1405 memset(error[nErrors].extent, 0, 100);
1406 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1407 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1413 } while (*str && y < clientArea->bottom);
1415 for (e = 0; e < nErrors; e++)
1417 /* The width returned by GetTextExtentPoint32() is exactly the same
1418 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1419 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1420 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1421 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1425 static void test_SetTextJustification(void)
1432 static char testText[] =
1433 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1434 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1435 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1436 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1437 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1438 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1439 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1441 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1442 GetClientRect( hwnd, &clientArea );
1443 hdc = GetDC( hwnd );
1445 memset(&lf, 0, sizeof lf);
1446 lf.lfCharSet = ANSI_CHARSET;
1447 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1448 lf.lfWeight = FW_DONTCARE;
1450 lf.lfQuality = DEFAULT_QUALITY;
1451 lstrcpyA(lf.lfFaceName, "Times New Roman");
1452 hfont = create_font("Times New Roman", &lf);
1453 SelectObject(hdc, hfont);
1455 testJustification(hdc, testText, &clientArea);
1457 DeleteObject(hfont);
1458 ReleaseDC(hwnd, hdc);
1459 DestroyWindow(hwnd);
1462 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1466 HFONT hfont, hfont_old;
1473 assert(count <= 128);
1475 memset(&lf, 0, sizeof(lf));
1477 lf.lfCharSet = charset;
1479 lstrcpyA(lf.lfFaceName, "Arial");
1480 SetLastError(0xdeadbeef);
1481 hfont = CreateFontIndirectA(&lf);
1482 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1485 hfont_old = SelectObject(hdc, hfont);
1487 cs = GetTextCharsetInfo(hdc, &fs, 0);
1488 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1490 SetLastError(0xdeadbeef);
1491 ret = GetTextFaceA(hdc, sizeof(name), name);
1492 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1494 if (charset == SYMBOL_CHARSET)
1496 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1497 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1501 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1502 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1505 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1507 trace("Can't find codepage for charset %d\n", cs);
1511 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1516 WCHAR unicode_buf[128];
1518 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1520 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1522 SetLastError(0xdeadbeef);
1523 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1524 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1530 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1532 SetLastError(0xdeadbeef);
1533 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1534 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1537 SelectObject(hdc, hfont_old);
1538 DeleteObject(hfont);
1545 static void test_font_charset(void)
1547 static struct charset_data
1551 WORD font_idxA[128], font_idxW[128];
1554 { ANSI_CHARSET, 1252 },
1555 { RUSSIAN_CHARSET, 1251 },
1556 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1560 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1562 win_skip("Skipping the font charset test on a Win9x platform\n");
1566 if (!is_font_installed("Arial"))
1568 skip("Arial is not installed\n");
1572 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1574 if (cd[i].charset == SYMBOL_CHARSET)
1576 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1578 skip("Symbol or Wingdings is not installed\n");
1582 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1583 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1584 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1587 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1590 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1591 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1594 skip("Symbol or Wingdings is not installed\n");
1597 static void test_GetFontUnicodeRanges(void)
1601 HFONT hfont, hfont_old;
1605 if (!pGetFontUnicodeRanges)
1607 win_skip("GetFontUnicodeRanges not available before W2K\n");
1611 memset(&lf, 0, sizeof(lf));
1612 lstrcpyA(lf.lfFaceName, "Arial");
1613 hfont = create_font("Arial", &lf);
1616 hfont_old = SelectObject(hdc, hfont);
1618 size = pGetFontUnicodeRanges(NULL, NULL);
1619 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1621 size = pGetFontUnicodeRanges(hdc, NULL);
1622 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1624 gs = HeapAlloc(GetProcessHeap(), 0, size);
1626 size = pGetFontUnicodeRanges(hdc, gs);
1627 ok(size, "GetFontUnicodeRanges failed\n");
1629 for (i = 0; i < gs->cRanges; i++)
1630 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1632 trace("found %u ranges\n", gs->cRanges);
1634 HeapFree(GetProcessHeap(), 0, gs);
1636 SelectObject(hdc, hfont_old);
1637 DeleteObject(hfont);
1638 ReleaseDC(NULL, hdc);
1641 #define MAX_ENUM_FONTS 4096
1643 struct enum_font_data
1646 LOGFONT lf[MAX_ENUM_FONTS];
1649 struct enum_font_dataW
1652 LOGFONTW lf[MAX_ENUM_FONTS];
1655 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1657 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1659 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1661 if (type != TRUETYPE_FONTTYPE) return 1;
1663 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1664 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1666 if (efd->total < MAX_ENUM_FONTS)
1667 efd->lf[efd->total++] = *lf;
1669 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1674 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1676 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1678 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1680 if (type != TRUETYPE_FONTTYPE) return 1;
1682 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1683 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1685 if (efd->total < MAX_ENUM_FONTS)
1686 efd->lf[efd->total++] = *lf;
1688 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1693 static void get_charset_stats(struct enum_font_data *efd,
1694 int *ansi_charset, int *symbol_charset,
1695 int *russian_charset)
1700 *symbol_charset = 0;
1701 *russian_charset = 0;
1703 for (i = 0; i < efd->total; i++)
1705 switch (efd->lf[i].lfCharSet)
1710 case SYMBOL_CHARSET:
1711 (*symbol_charset)++;
1713 case RUSSIAN_CHARSET:
1714 (*russian_charset)++;
1720 static void get_charset_statsW(struct enum_font_dataW *efd,
1721 int *ansi_charset, int *symbol_charset,
1722 int *russian_charset)
1727 *symbol_charset = 0;
1728 *russian_charset = 0;
1730 for (i = 0; i < efd->total; i++)
1732 switch (efd->lf[i].lfCharSet)
1737 case SYMBOL_CHARSET:
1738 (*symbol_charset)++;
1740 case RUSSIAN_CHARSET:
1741 (*russian_charset)++;
1747 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1749 struct enum_font_data efd;
1750 struct enum_font_dataW efdw;
1753 int i, ret, ansi_charset, symbol_charset, russian_charset;
1755 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1757 if (*font_name && !is_truetype_font_installed(font_name))
1759 skip("%s is not installed\n", font_name);
1765 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1766 * while EnumFontFamiliesEx doesn't.
1768 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1771 * Use EnumFontFamiliesW since win98 crashes when the
1772 * second parameter is NULL using EnumFontFamilies
1775 SetLastError(0xdeadbeef);
1776 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1777 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1780 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1781 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1782 ansi_charset, symbol_charset, russian_charset);
1783 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1784 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1785 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1786 ok(russian_charset > 0 ||
1787 broken(russian_charset == 0), /* NT4 */
1788 "NULL family should enumerate RUSSIAN_CHARSET\n");
1792 SetLastError(0xdeadbeef);
1793 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1794 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1797 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1798 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1799 ansi_charset, symbol_charset, russian_charset);
1800 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1801 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1802 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1803 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1808 SetLastError(0xdeadbeef);
1809 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1810 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1811 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1812 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1813 ansi_charset, symbol_charset, russian_charset,
1814 *font_name ? font_name : "<empty>");
1816 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1818 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1819 for (i = 0; i < efd.total; i++)
1821 /* FIXME: remove completely once Wine is fixed */
1822 if (efd.lf[i].lfCharSet != font_charset)
1825 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1828 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1829 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1830 font_name, efd.lf[i].lfFaceName);
1833 memset(&lf, 0, sizeof(lf));
1834 lf.lfCharSet = ANSI_CHARSET;
1835 lstrcpy(lf.lfFaceName, font_name);
1837 SetLastError(0xdeadbeef);
1838 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1839 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1840 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1841 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1842 ansi_charset, symbol_charset, russian_charset,
1843 *font_name ? font_name : "<empty>");
1844 if (font_charset == SYMBOL_CHARSET)
1847 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1849 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1853 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1854 for (i = 0; i < efd.total; i++)
1856 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1858 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1859 font_name, efd.lf[i].lfFaceName);
1863 /* DEFAULT_CHARSET should enumerate all available charsets */
1864 memset(&lf, 0, sizeof(lf));
1865 lf.lfCharSet = DEFAULT_CHARSET;
1866 lstrcpy(lf.lfFaceName, font_name);
1868 SetLastError(0xdeadbeef);
1869 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1870 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1871 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1872 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1873 ansi_charset, symbol_charset, russian_charset,
1874 *font_name ? font_name : "<empty>");
1875 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1876 for (i = 0; i < efd.total; i++)
1879 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1880 font_name, efd.lf[i].lfFaceName);
1884 switch (font_charset)
1887 ok(ansi_charset > 0,
1888 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1890 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1891 ok(russian_charset > 0,
1892 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1894 case SYMBOL_CHARSET:
1896 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1898 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1899 ok(!russian_charset,
1900 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1902 case DEFAULT_CHARSET:
1903 ok(ansi_charset > 0,
1904 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1905 ok(symbol_charset > 0,
1906 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1907 ok(russian_charset > 0,
1908 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1914 ok(ansi_charset > 0,
1915 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1916 ok(symbol_charset > 0,
1917 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1918 ok(russian_charset > 0,
1919 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1922 memset(&lf, 0, sizeof(lf));
1923 lf.lfCharSet = SYMBOL_CHARSET;
1924 lstrcpy(lf.lfFaceName, font_name);
1926 SetLastError(0xdeadbeef);
1927 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1928 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1929 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1930 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1931 ansi_charset, symbol_charset, russian_charset,
1932 *font_name ? font_name : "<empty>");
1933 if (*font_name && font_charset == ANSI_CHARSET)
1934 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1937 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1938 for (i = 0; i < efd.total; i++)
1940 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1942 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1943 font_name, efd.lf[i].lfFaceName);
1947 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1948 ok(symbol_charset > 0,
1949 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1950 ok(!russian_charset,
1951 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1957 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1959 HFONT hfont, hfont_prev;
1961 GLYPHMETRICS gm1, gm2;
1964 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1966 if(!pGetGlyphIndicesA)
1969 /* negative widths are handled just as positive ones */
1970 lf2.lfWidth = -lf->lfWidth;
1972 SetLastError(0xdeadbeef);
1973 hfont = CreateFontIndirectA(lf);
1974 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1975 check_font("original", lf, hfont);
1977 hfont_prev = SelectObject(hdc, hfont);
1979 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1980 if (ret == GDI_ERROR || idx == 0xffff)
1982 SelectObject(hdc, hfont_prev);
1983 DeleteObject(hfont);
1984 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1988 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1989 memset(&gm1, 0xab, sizeof(gm1));
1990 SetLastError(0xdeadbeef);
1991 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1992 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1994 SelectObject(hdc, hfont_prev);
1995 DeleteObject(hfont);
1997 SetLastError(0xdeadbeef);
1998 hfont = CreateFontIndirectA(&lf2);
1999 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2000 check_font("negative width", &lf2, hfont);
2002 hfont_prev = SelectObject(hdc, hfont);
2004 memset(&gm2, 0xbb, sizeof(gm2));
2005 SetLastError(0xdeadbeef);
2006 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2007 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2009 SelectObject(hdc, hfont_prev);
2010 DeleteObject(hfont);
2012 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2013 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2014 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2015 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2016 gm1.gmCellIncX == gm2.gmCellIncX &&
2017 gm1.gmCellIncY == gm2.gmCellIncY,
2018 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2019 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2020 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2021 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2022 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2025 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2026 #include "pshpack2.h"
2030 SHORT xAvgCharWidth;
2031 USHORT usWeightClass;
2032 USHORT usWidthClass;
2034 SHORT ySubscriptXSize;
2035 SHORT ySubscriptYSize;
2036 SHORT ySubscriptXOffset;
2037 SHORT ySubscriptYOffset;
2038 SHORT ySuperscriptXSize;
2039 SHORT ySuperscriptYSize;
2040 SHORT ySuperscriptXOffset;
2041 SHORT ySuperscriptYOffset;
2042 SHORT yStrikeoutSize;
2043 SHORT yStrikeoutPosition;
2046 ULONG ulUnicodeRange1;
2047 ULONG ulUnicodeRange2;
2048 ULONG ulUnicodeRange3;
2049 ULONG ulUnicodeRange4;
2052 USHORT usFirstCharIndex;
2053 USHORT usLastCharIndex;
2054 /* According to the Apple spec, original version didn't have the below fields,
2055 * version numbers were taked from the OpenType spec.
2057 /* version 0 (TrueType 1.5) */
2058 USHORT sTypoAscender;
2059 USHORT sTypoDescender;
2060 USHORT sTypoLineGap;
2062 USHORT usWinDescent;
2063 /* version 1 (TrueType 1.66) */
2064 ULONG ulCodePageRange1;
2065 ULONG ulCodePageRange2;
2066 /* version 2 (OpenType 1.2) */
2069 USHORT usDefaultChar;
2071 USHORT usMaxContext;
2073 #include "poppack.h"
2075 #ifdef WORDS_BIGENDIAN
2076 #define GET_BE_WORD(x) (x)
2077 #define GET_BE_DWORD(x) (x)
2079 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2080 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2083 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2084 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2085 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2086 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2087 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2100 } cmap_encoding_record;
2108 BYTE glyph_ids[256];
2118 USHORT search_range;
2119 USHORT entry_selector;
2122 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2125 USHORT start_count[seg_countx2 / 2];
2126 USHORT id_delta[seg_countx2 / 2];
2127 USHORT id_range_offset[seg_countx2 / 2];
2137 USHORT id_range_offset;
2138 } cmap_format_4_seg;
2140 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2142 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2143 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2144 os2->panose.bWeight, os2->panose.bProportion);
2147 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2150 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2154 for(i = 0; i < 256; i++)
2156 if(cmap->glyph_ids[i] == 0) continue;
2158 if(*first == 256) *first = i;
2160 if(*first == 256) return FALSE;
2164 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2166 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2167 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2168 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2169 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2170 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2173 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2176 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2177 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2178 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2182 for(i = 0; i < seg_count; i++)
2185 cmap_format_4_seg seg;
2187 get_seg4(cmap, i, &seg);
2188 for(code = seg.start_count; code <= seg.end_count; code++)
2190 if(seg.id_range_offset == 0)
2191 index = (seg.id_delta + code) & 0xffff;
2194 index = seg.id_range_offset / 2
2195 + code - seg.start_count
2198 /* some fonts have broken last segment */
2199 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2200 index = GET_BE_WORD(glyph_ids[index]);
2203 trace("segment %04x/%04x index %04x points to nowhere\n",
2204 seg.start_count, seg.end_count, index);
2207 if(index) index += seg.id_delta;
2209 if(*first == 0x10000)
2210 *last = *first = code;
2216 if(*first == 0x10000) return FALSE;
2220 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2223 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2225 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2227 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2228 return (BYTE *)header + GET_BE_DWORD(record->offset);
2241 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2244 cmap_header *header;
2249 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2250 ok(size != GDI_ERROR, "no cmap table found\n");
2251 if(size == GDI_ERROR) return FALSE;
2253 header = HeapAlloc(GetProcessHeap(), 0, size);
2254 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2255 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2256 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2258 cmap = get_cmap(header, 3, 1);
2260 *cmap_type = cmap_ms_unicode;
2263 cmap = get_cmap(header, 3, 0);
2264 if(cmap) *cmap_type = cmap_ms_symbol;
2268 *cmap_type = cmap_none;
2272 format = GET_BE_WORD(*(WORD *)cmap);
2276 r = get_first_last_from_cmap0(cmap, first, last);
2279 r = get_first_last_from_cmap4(cmap, first, last, size);
2282 trace("unhandled cmap format %d\n", format);
2287 HeapFree(GetProcessHeap(), 0, header);
2291 static void test_text_metrics(const LOGFONTA *lf)
2294 HFONT hfont, hfont_old;
2298 const char *font_name = lf->lfFaceName;
2299 DWORD cmap_first = 0, cmap_last = 0;
2300 cmap_type cmap_type;
2304 SetLastError(0xdeadbeef);
2305 hfont = CreateFontIndirectA(lf);
2306 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2308 hfont_old = SelectObject(hdc, hfont);
2310 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2311 if (size == GDI_ERROR)
2313 trace("OS/2 chunk was not found\n");
2316 if (size > sizeof(tt_os2))
2318 trace("got too large OS/2 chunk of size %u\n", size);
2319 size = sizeof(tt_os2);
2322 memset(&tt_os2, 0, sizeof(tt_os2));
2323 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2324 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2326 SetLastError(0xdeadbeef);
2327 ret = GetTextMetricsA(hdc, &tmA);
2328 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2330 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2332 skip("Unable to retrieve first and last glyphs from cmap\n");
2336 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2337 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2338 UINT os2_first_char, os2_last_char, default_char, break_char;
2342 version = GET_BE_WORD(tt_os2.version);
2344 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2345 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2346 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2347 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2349 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2350 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2351 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2353 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2358 case 1257: /* Baltic */
2359 expect_last_W = 0xf8fd;
2362 expect_last_W = 0xf0ff;
2364 expect_break_W = 0x20;
2365 expect_default_W = expect_break_W - 1;
2366 expect_first_A = 0x1e;
2367 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2371 expect_first_W = cmap_first;
2372 expect_last_W = min(cmap_last, os2_last_char);
2373 if(os2_first_char <= 1)
2374 expect_break_W = os2_first_char + 2;
2375 else if(os2_first_char > 0xff)
2376 expect_break_W = 0x20;
2378 expect_break_W = os2_first_char;
2379 expect_default_W = expect_break_W - 1;
2380 expect_first_A = expect_default_W - 1;
2381 expect_last_A = min(expect_last_W, 0xff);
2383 expect_break_A = expect_break_W;
2384 expect_default_A = expect_default_W;
2386 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2387 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2388 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2389 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2390 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2392 ok(tmA.tmFirstChar == expect_first_A ||
2393 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2394 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2395 ok(tmA.tmLastChar == expect_last_A ||
2396 tmA.tmLastChar == 0xff /* win9x */,
2397 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2398 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2399 font_name, tmA.tmBreakChar, expect_break_A);
2400 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2401 font_name, tmA.tmDefaultChar, expect_default_A);
2404 SetLastError(0xdeadbeef);
2405 ret = GetTextMetricsW(hdc, &tmW);
2406 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2407 "GetTextMetricsW error %u\n", GetLastError());
2410 /* Wine uses the os2 first char */
2411 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2412 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2413 font_name, tmW.tmFirstChar, expect_first_W);
2415 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2416 font_name, tmW.tmFirstChar, expect_first_W);
2418 /* Wine uses the os2 last char */
2419 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2420 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2421 font_name, tmW.tmLastChar, expect_last_W);
2423 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2424 font_name, tmW.tmLastChar, expect_last_W);
2425 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2426 font_name, tmW.tmBreakChar, expect_break_W);
2427 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2428 font_name, tmW.tmDefaultChar, expect_default_W);
2430 /* Test the aspect ratio while we have tmW */
2431 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2432 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2433 tmW.tmDigitizedAspectX, ret);
2434 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2435 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2436 tmW.tmDigitizedAspectX, ret);
2440 /* test FF_ values */
2441 switch(tt_os2.panose.bFamilyType)
2445 case PAN_FAMILY_TEXT_DISPLAY:
2446 case PAN_FAMILY_PICTORIAL:
2448 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2449 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2451 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2454 switch(tt_os2.panose.bSerifStyle)
2459 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2462 case PAN_SERIF_COVE:
2463 case PAN_SERIF_OBTUSE_COVE:
2464 case PAN_SERIF_SQUARE_COVE:
2465 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2466 case PAN_SERIF_SQUARE:
2467 case PAN_SERIF_THIN:
2468 case PAN_SERIF_BONE:
2469 case PAN_SERIF_EXAGGERATED:
2470 case PAN_SERIF_TRIANGLE:
2471 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2474 case PAN_SERIF_NORMAL_SANS:
2475 case PAN_SERIF_OBTUSE_SANS:
2476 case PAN_SERIF_PERP_SANS:
2477 case PAN_SERIF_FLARED:
2478 case PAN_SERIF_ROUNDED:
2479 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2484 case PAN_FAMILY_SCRIPT:
2485 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2488 case PAN_FAMILY_DECORATIVE:
2489 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2493 test_negative_width(hdc, lf);
2496 SelectObject(hdc, hfont_old);
2497 DeleteObject(hfont);
2502 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2504 INT *enumed = (INT *)lParam;
2506 if (type == TRUETYPE_FONTTYPE)
2509 test_text_metrics(lf);
2514 static void test_GetTextMetrics(void)
2520 /* Report only once */
2521 if(!pGetGlyphIndicesA)
2522 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2526 memset(&lf, 0, sizeof(lf));
2527 lf.lfCharSet = DEFAULT_CHARSET;
2529 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2530 trace("Tested metrics of %d truetype fonts\n", enumed);
2535 static void test_nonexistent_font(void)
2543 { "Times New Roman Baltic", 186 },
2544 { "Times New Roman CE", 238 },
2545 { "Times New Roman CYR", 204 },
2546 { "Times New Roman Greek", 161 },
2547 { "Times New Roman TUR", 162 }
2553 INT cs, expected_cs, i;
2554 char buf[LF_FACESIZE];
2556 if (!is_truetype_font_installed("Arial") ||
2557 !is_truetype_font_installed("Times New Roman"))
2559 skip("Arial or Times New Roman not installed\n");
2563 expected_cs = GetACP();
2564 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2566 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2569 expected_cs = csi.ciCharset;
2570 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2574 memset(&lf, 0, sizeof(lf));
2576 lf.lfWeight = FW_REGULAR;
2577 lf.lfCharSet = ANSI_CHARSET;
2578 lf.lfPitchAndFamily = FF_SWISS;
2579 strcpy(lf.lfFaceName, "Nonexistent font");
2580 hfont = CreateFontIndirectA(&lf);
2581 hfont = SelectObject(hdc, hfont);
2582 GetTextFaceA(hdc, sizeof(buf), buf);
2583 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2584 cs = GetTextCharset(hdc);
2585 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2586 DeleteObject(SelectObject(hdc, hfont));
2588 memset(&lf, 0, sizeof(lf));
2590 lf.lfWeight = FW_DONTCARE;
2591 strcpy(lf.lfFaceName, "Nonexistent font");
2592 hfont = CreateFontIndirectA(&lf);
2593 hfont = SelectObject(hdc, hfont);
2594 GetTextFaceA(hdc, sizeof(buf), buf);
2595 todo_wine /* Wine uses Arial for all substitutions */
2596 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2597 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2598 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2600 cs = GetTextCharset(hdc);
2601 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2602 DeleteObject(SelectObject(hdc, hfont));
2604 memset(&lf, 0, sizeof(lf));
2606 lf.lfWeight = FW_REGULAR;
2607 strcpy(lf.lfFaceName, "Nonexistent font");
2608 hfont = CreateFontIndirectA(&lf);
2609 hfont = SelectObject(hdc, hfont);
2610 GetTextFaceA(hdc, sizeof(buf), buf);
2611 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2612 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2613 cs = GetTextCharset(hdc);
2614 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2615 DeleteObject(SelectObject(hdc, hfont));
2617 memset(&lf, 0, sizeof(lf));
2619 lf.lfWeight = FW_DONTCARE;
2620 strcpy(lf.lfFaceName, "Times New Roman");
2621 hfont = CreateFontIndirectA(&lf);
2622 hfont = SelectObject(hdc, hfont);
2623 GetTextFaceA(hdc, sizeof(buf), buf);
2624 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2625 cs = GetTextCharset(hdc);
2626 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2627 DeleteObject(SelectObject(hdc, hfont));
2629 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2631 memset(&lf, 0, sizeof(lf));
2633 lf.lfWeight = FW_REGULAR;
2634 strcpy(lf.lfFaceName, font_subst[i].name);
2635 hfont = CreateFontIndirectA(&lf);
2636 hfont = SelectObject(hdc, hfont);
2637 cs = GetTextCharset(hdc);
2638 if (font_subst[i].charset == expected_cs)
2640 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2641 GetTextFaceA(hdc, sizeof(buf), buf);
2642 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2646 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2647 GetTextFaceA(hdc, sizeof(buf), buf);
2648 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2649 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2651 DeleteObject(SelectObject(hdc, hfont));
2653 memset(&lf, 0, sizeof(lf));
2655 lf.lfWeight = FW_DONTCARE;
2656 strcpy(lf.lfFaceName, font_subst[i].name);
2657 hfont = CreateFontIndirectA(&lf);
2658 hfont = SelectObject(hdc, hfont);
2659 GetTextFaceA(hdc, sizeof(buf), buf);
2660 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2661 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2662 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2663 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2664 "got %s for font %s\n", buf, font_subst[i].name);
2665 cs = GetTextCharset(hdc);
2666 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2667 DeleteObject(SelectObject(hdc, hfont));
2673 static void test_GdiRealizationInfo(void)
2678 HFONT hfont, hfont_old;
2681 if(!pGdiRealizationInfo)
2683 win_skip("GdiRealizationInfo not available\n");
2689 memset(info, 0xcc, sizeof(info));
2690 r = pGdiRealizationInfo(hdc, info);
2691 ok(r != 0, "ret 0\n");
2692 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2693 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2695 if (!is_truetype_font_installed("Arial"))
2697 skip("skipping GdiRealizationInfo with truetype font\n");
2701 memset(&lf, 0, sizeof(lf));
2702 strcpy(lf.lfFaceName, "Arial");
2704 lf.lfWeight = FW_NORMAL;
2705 hfont = CreateFontIndirectA(&lf);
2706 hfont_old = SelectObject(hdc, hfont);
2708 memset(info, 0xcc, sizeof(info));
2709 r = pGdiRealizationInfo(hdc, info);
2710 ok(r != 0, "ret 0\n");
2711 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2712 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2714 DeleteObject(SelectObject(hdc, hfont_old));
2720 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2721 the nul in the count of characters copied when the face name buffer is not
2722 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2723 always includes it. */
2724 static void test_GetTextFace(void)
2726 static const char faceA[] = "Tahoma";
2727 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2730 char bufA[LF_FACESIZE];
2731 WCHAR bufW[LF_FACESIZE];
2736 if(!is_font_installed("Tahoma"))
2738 skip("Tahoma is not installed so skipping this test\n");
2743 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2744 f = CreateFontIndirectA(&fA);
2745 ok(f != NULL, "CreateFontIndirectA failed\n");
2748 g = SelectObject(dc, f);
2749 n = GetTextFaceA(dc, sizeof bufA, bufA);
2750 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2751 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2753 /* Play with the count arg. */
2755 n = GetTextFaceA(dc, 0, bufA);
2756 ok(n == 0, "GetTextFaceA returned %d\n", n);
2757 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2760 n = GetTextFaceA(dc, 1, bufA);
2761 ok(n == 0, "GetTextFaceA returned %d\n", n);
2762 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2764 bufA[0] = 'x'; bufA[1] = 'y';
2765 n = GetTextFaceA(dc, 2, bufA);
2766 ok(n == 1, "GetTextFaceA returned %d\n", n);
2767 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2769 n = GetTextFaceA(dc, 0, NULL);
2770 ok(n == sizeof faceA ||
2771 broken(n == 0), /* win98, winMe */
2772 "GetTextFaceA returned %d\n", n);
2774 DeleteObject(SelectObject(dc, g));
2775 ReleaseDC(NULL, dc);
2778 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2779 SetLastError(0xdeadbeef);
2780 f = CreateFontIndirectW(&fW);
2781 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2783 win_skip("CreateFontIndirectW is not implemented\n");
2786 ok(f != NULL, "CreateFontIndirectW failed\n");
2789 g = SelectObject(dc, f);
2790 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2791 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2792 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2794 /* Play with the count arg. */
2796 n = GetTextFaceW(dc, 0, bufW);
2797 ok(n == 0, "GetTextFaceW returned %d\n", n);
2798 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2801 n = GetTextFaceW(dc, 1, bufW);
2802 ok(n == 1, "GetTextFaceW returned %d\n", n);
2803 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2805 bufW[0] = 'x'; bufW[1] = 'y';
2806 n = GetTextFaceW(dc, 2, bufW);
2807 ok(n == 2, "GetTextFaceW returned %d\n", n);
2808 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2810 n = GetTextFaceW(dc, 0, NULL);
2811 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2813 DeleteObject(SelectObject(dc, g));
2814 ReleaseDC(NULL, dc);
2817 static void test_orientation(void)
2819 static const char test_str[11] = "Test String";
2822 HFONT hfont, old_hfont;
2825 if (!is_truetype_font_installed("Arial"))
2827 skip("Arial is not installed\n");
2831 hdc = CreateCompatibleDC(0);
2832 memset(&lf, 0, sizeof(lf));
2833 lstrcpyA(lf.lfFaceName, "Arial");
2835 lf.lfOrientation = lf.lfEscapement = 900;
2836 hfont = create_font("orientation", &lf);
2837 old_hfont = SelectObject(hdc, hfont);
2838 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2839 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2840 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2841 SelectObject(hdc, old_hfont);
2842 DeleteObject(hfont);
2846 static void test_oemcharset(void)
2850 HFONT hfont, old_hfont;
2853 hdc = CreateCompatibleDC(0);
2854 ZeroMemory(&lf, sizeof(lf));
2856 lf.lfCharSet = OEM_CHARSET;
2857 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
2858 lstrcpyA(lf.lfFaceName, "Terminal");
2859 hfont = CreateFontIndirectA(&lf);
2860 old_hfont = SelectObject(hdc, hfont);
2861 charset = GetTextCharset(hdc);
2863 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
2864 hfont = SelectObject(hdc, old_hfont);
2865 GetObjectA(hfont, sizeof(clf), &clf);
2866 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
2867 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
2868 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
2869 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
2870 DeleteObject(hfont);
2874 static void test_GetGlyphOutline(void)
2876 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2880 HFONT hfont, old_hfont;
2883 if (!is_truetype_font_installed("Tahoma"))
2885 skip("Tahoma is not installed\n");
2889 hdc = CreateCompatibleDC(0);
2890 memset(&lf, 0, sizeof(lf));
2892 lstrcpyA(lf.lfFaceName, "Tahoma");
2893 SetLastError(0xdeadbeef);
2894 hfont = CreateFontIndirectA(&lf);
2895 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2896 old_hfont = SelectObject(hdc, hfont);
2898 memset(&gm, 0, sizeof(gm));
2899 SetLastError(0xdeadbeef);
2900 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2901 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2903 memset(&gm, 0, sizeof(gm));
2904 SetLastError(0xdeadbeef);
2905 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2906 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2907 ok(GetLastError() == 0xdeadbeef ||
2908 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2909 "expected 0xdeadbeef, got %u\n", GetLastError());
2911 memset(&gm, 0, sizeof(gm));
2912 SetLastError(0xdeadbeef);
2913 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2914 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2915 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
2917 memset(&gm, 0, sizeof(gm));
2918 SetLastError(0xdeadbeef);
2919 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2920 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2922 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
2923 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2926 /* test for needed buffer size request on space char */
2927 memset(&gm, 0, sizeof(gm));
2928 SetLastError(0xdeadbeef);
2929 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
2930 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2931 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
2933 /* requesting buffer size for space char + error */
2934 memset(&gm, 0, sizeof(gm));
2935 SetLastError(0xdeadbeef);
2936 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
2937 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2939 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
2940 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2943 SelectObject(hdc, old_hfont);
2944 DeleteObject(hfont);
2948 /* bug #9995: there is a limit to the character width that can be specified */
2949 static void test_GetTextMetrics2(const char *fontname, int font_height)
2955 int ave_width, height, width, ratio, scale;
2957 if (!is_truetype_font_installed( fontname)) {
2958 skip("%s is not installed\n", fontname);
2961 hdc = CreateCompatibleDC(0);
2962 ok( hdc != NULL, "CreateCompatibleDC failed\n");
2963 /* select width = 0 */
2964 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
2965 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
2966 DEFAULT_QUALITY, VARIABLE_PITCH,
2968 ok( hf != NULL, "CreateFontA failed\n");
2969 of = SelectObject( hdc, hf);
2970 ret = GetTextMetricsA( hdc, &tm);
2971 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2972 height = tm.tmHeight;
2973 ave_width = tm.tmAveCharWidth;
2974 SelectObject( hdc, of);
2977 trace("height %d, ave width %d\n", height, ave_width);
2979 for (width = ave_width * 2; /* nothing*/; width += ave_width)
2981 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
2982 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
2983 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
2984 ok(hf != 0, "CreateFont failed\n");
2985 of = SelectObject(hdc, hf);
2986 ret = GetTextMetrics(hdc, &tm);
2987 ok(ret, "GetTextMetrics error %u\n", GetLastError());
2988 SelectObject(hdc, of);
2991 if (tm.tmAveCharWidth == ave_width || width / height > 200)
2997 ratio = width / height;
2998 scale = width / ave_width;
3000 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3001 width, height, ratio, width, ave_width, scale);
3003 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3006 static void test_CreateFontIndirect(void)
3008 LOGFONTA lf, getobj_lf;
3011 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3013 memset(&lf, 0, sizeof(lf));
3014 lf.lfCharSet = ANSI_CHARSET;
3015 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3018 lf.lfQuality = DEFAULT_QUALITY;
3019 lf.lfItalic = FALSE;
3020 lf.lfWeight = FW_DONTCARE;
3022 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3024 lstrcpyA(lf.lfFaceName, TestName[i]);
3025 hfont = CreateFontIndirectA(&lf);
3026 ok(hfont != 0, "CreateFontIndirectA failed\n");
3027 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3028 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3029 ok(lf.lfWeight == getobj_lf.lfWeight ||
3030 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3031 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3032 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3033 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3034 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3035 DeleteObject(hfont);
3044 test_outline_font();
3045 test_bitmap_font_metrics();
3046 test_GdiGetCharDimensions();
3047 test_GetCharABCWidths();
3048 test_text_extents();
3049 test_GetGlyphIndices();
3050 test_GetKerningPairs();
3051 test_GetOutlineTextMetrics();
3052 test_SetTextJustification();
3053 test_font_charset();
3054 test_GetFontUnicodeRanges();
3055 test_nonexistent_font();
3058 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3059 * I'd like to avoid them in this test.
3061 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3062 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3063 if (is_truetype_font_installed("Arial Black") &&
3064 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3066 test_EnumFontFamilies("", ANSI_CHARSET);
3067 test_EnumFontFamilies("", SYMBOL_CHARSET);
3068 test_EnumFontFamilies("", DEFAULT_CHARSET);
3071 skip("Arial Black or Symbol/Wingdings is not installed\n");
3072 test_GetTextMetrics();
3073 test_GdiRealizationInfo();
3075 test_GetGlyphOutline();
3076 test_GetTextMetrics2("Tahoma", -11);
3077 test_GetTextMetrics2("Tahoma", -55);
3078 test_GetTextMetrics2("Tahoma", -110);
3079 test_GetTextMetrics2("Arial", -11);
3080 test_GetTextMetrics2("Arial", -55);
3081 test_GetTextMetrics2("Arial", -110);
3082 test_CreateFontIndirect();