configure: Changes from running autconf after previous patch.
[wine/hacks.git] / dlls / gdi32 / tests / font.c
blobd89132db441de4b7cea7c1e8560cdefb8fe8e2e5
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
41 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
42 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
43 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
44 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
45 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
46 HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
48 static HMODULE hgdi32 = 0;
50 static void init(void)
52 hgdi32 = GetModuleHandleA("gdi32.dll");
54 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
55 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
56 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
57 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
58 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
59 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
60 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
61 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
64 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
66 if (type != TRUETYPE_FONTTYPE) return 1;
68 return 0;
71 static BOOL is_truetype_font_installed(const char *name)
73 HDC hdc = GetDC(0);
74 BOOL ret = FALSE;
76 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
77 ret = TRUE;
79 ReleaseDC(0, hdc);
80 return ret;
83 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
85 return 0;
88 static BOOL is_font_installed(const char *name)
90 HDC hdc = GetDC(0);
91 BOOL ret = FALSE;
93 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
94 ret = TRUE;
96 ReleaseDC(0, hdc);
97 return ret;
100 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
102 LOGFONTA getobj_lf;
103 int ret, minlen = 0;
105 if (!hfont)
106 return;
108 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
109 /* NT4 tries to be clever and only returns the minimum length */
110 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
111 minlen++;
112 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
113 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
114 ok(lf->lfHeight == getobj_lf.lfHeight ||
115 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
116 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
117 ok(lf->lfWidth == getobj_lf.lfWidth ||
118 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
119 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
120 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
121 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
122 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
123 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
124 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
125 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
126 ok(lf->lfWeight == getobj_lf.lfWeight ||
127 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
128 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
129 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
130 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
131 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
132 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
133 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
134 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
135 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
136 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
137 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
138 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
139 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
142 static HFONT create_font(const char* test, const LOGFONTA* lf)
144 HFONT hfont = CreateFontIndirectA(lf);
145 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
146 if (hfont)
147 check_font(test, lf, hfont);
148 return hfont;
151 static void test_logfont(void)
153 LOGFONTA lf;
154 HFONT hfont;
156 memset(&lf, 0, sizeof lf);
158 lf.lfCharSet = ANSI_CHARSET;
159 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
160 lf.lfWeight = FW_DONTCARE;
161 lf.lfHeight = 16;
162 lf.lfWidth = 16;
163 lf.lfQuality = DEFAULT_QUALITY;
165 lstrcpyA(lf.lfFaceName, "Arial");
166 hfont = create_font("Arial", &lf);
167 DeleteObject(hfont);
169 memset(&lf, 'A', sizeof(lf));
170 hfont = CreateFontIndirectA(&lf);
171 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
173 lf.lfFaceName[LF_FACESIZE - 1] = 0;
174 check_font("AAA...", &lf, hfont);
175 DeleteObject(hfont);
178 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
180 if (type & RASTER_FONTTYPE)
182 LOGFONT *lf = (LOGFONT *)lParam;
183 *lf = *elf;
184 return 0; /* stop enumeration */
187 return 1; /* continue enumeration */
190 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
192 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
193 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
194 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
195 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
196 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
197 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
198 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
199 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
200 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
201 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
202 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
203 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
204 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
205 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
206 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
207 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
208 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
209 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
210 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
211 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
214 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
215 LONG lfWidth, const char *test_str,
216 INT test_str_len, const TEXTMETRICA *tm_orig,
217 const SIZE *size_orig, INT width_of_A_orig,
218 INT scale_x, INT scale_y)
220 LOGFONTA lf;
221 OUTLINETEXTMETRIC otm;
222 TEXTMETRICA tm;
223 SIZE size;
224 INT width_of_A, cx, cy;
225 UINT ret;
227 if (!hfont)
228 return;
230 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
232 GetObjectA(hfont, sizeof(lf), &lf);
234 if (GetOutlineTextMetricsA(hdc, 0, NULL))
236 otm.otmSize = sizeof(otm) / 2;
237 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
238 ok(ret == sizeof(otm)/2 /* XP */ ||
239 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
241 memset(&otm, 0x1, sizeof(otm));
242 otm.otmSize = sizeof(otm);
243 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
244 ok(ret == sizeof(otm) /* XP */ ||
245 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
247 memset(&tm, 0x2, sizeof(tm));
248 ret = GetTextMetricsA(hdc, &tm);
249 ok(ret, "GetTextMetricsA failed\n");
250 /* the structure size is aligned */
251 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
253 ok(0, "tm != otm\n");
254 compare_tm(&tm, &otm.otmTextMetrics);
257 tm = otm.otmTextMetrics;
258 if (0) /* these metrics are scaled too, but with rounding errors */
260 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
261 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
263 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
264 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
265 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
266 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
267 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
268 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
270 else
272 ret = GetTextMetricsA(hdc, &tm);
273 ok(ret, "GetTextMetricsA failed\n");
276 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
277 cy = tm.tmHeight / tm_orig->tmHeight;
278 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
279 lfHeight, scale_x, scale_y, cx, cy);
280 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
281 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
282 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
283 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
284 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
286 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
287 if (lf.lfHeight)
289 if (lf.lfWidth)
290 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
292 else
293 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
295 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
297 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
298 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
300 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
302 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);
305 /* Test how GDI scales bitmap font metrics */
306 static void test_bitmap_font(void)
308 static const char test_str[11] = "Test String";
309 HDC hdc;
310 LOGFONTA bitmap_lf;
311 HFONT hfont, old_hfont;
312 TEXTMETRICA tm_orig;
313 SIZE size_orig;
314 INT ret, i, width_orig, height_orig, scale, lfWidth;
316 hdc = GetDC(0);
318 /* "System" has only 1 pixel size defined, otherwise the test breaks */
319 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
320 if (ret)
322 ReleaseDC(0, hdc);
323 trace("no bitmap fonts were found, skipping the test\n");
324 return;
327 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
329 height_orig = bitmap_lf.lfHeight;
330 lfWidth = bitmap_lf.lfWidth;
332 hfont = create_font("bitmap", &bitmap_lf);
333 old_hfont = SelectObject(hdc, hfont);
334 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
335 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
336 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
337 SelectObject(hdc, old_hfont);
338 DeleteObject(hfont);
340 bitmap_lf.lfHeight = 0;
341 bitmap_lf.lfWidth = 4;
342 hfont = create_font("bitmap", &bitmap_lf);
343 old_hfont = SelectObject(hdc, hfont);
344 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
345 SelectObject(hdc, old_hfont);
346 DeleteObject(hfont);
348 bitmap_lf.lfHeight = height_orig;
349 bitmap_lf.lfWidth = lfWidth;
351 /* test fractional scaling */
352 for (i = 1; i <= height_orig * 6; i++)
354 INT nearest_height;
356 bitmap_lf.lfHeight = i;
357 hfont = create_font("fractional", &bitmap_lf);
358 scale = (i + height_orig - 1) / height_orig;
359 nearest_height = scale * height_orig;
360 /* Only jump to the next height if the difference <= 25% original height */
361 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
362 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
363 so we'll not test this particular height. */
364 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
365 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
366 old_hfont = SelectObject(hdc, hfont);
367 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
368 SelectObject(hdc, old_hfont);
369 DeleteObject(hfont);
372 /* test integer scaling 3x2 */
373 bitmap_lf.lfHeight = height_orig * 2;
374 bitmap_lf.lfWidth *= 3;
375 hfont = create_font("3x2", &bitmap_lf);
376 old_hfont = SelectObject(hdc, hfont);
377 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
378 SelectObject(hdc, old_hfont);
379 DeleteObject(hfont);
381 /* test integer scaling 3x3 */
382 bitmap_lf.lfHeight = height_orig * 3;
383 bitmap_lf.lfWidth = 0;
384 hfont = create_font("3x3", &bitmap_lf);
385 old_hfont = SelectObject(hdc, hfont);
386 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
387 SelectObject(hdc, old_hfont);
388 DeleteObject(hfont);
390 ReleaseDC(0, hdc);
393 /* Test how GDI scales outline font metrics */
394 static void test_outline_font(void)
396 static const char test_str[11] = "Test String";
397 HDC hdc, hdc_2;
398 LOGFONTA lf;
399 HFONT hfont, old_hfont, old_hfont_2;
400 OUTLINETEXTMETRICA otm;
401 SIZE size_orig;
402 INT width_orig, height_orig, lfWidth;
403 XFORM xform;
404 GLYPHMETRICS gm;
405 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
406 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
407 POINT pt;
408 INT ret;
410 if (!is_truetype_font_installed("Arial"))
412 skip("Arial is not installed\n");
413 return;
416 hdc = CreateCompatibleDC(0);
418 memset(&lf, 0, sizeof(lf));
419 strcpy(lf.lfFaceName, "Arial");
420 lf.lfHeight = 72;
421 hfont = create_font("outline", &lf);
422 old_hfont = SelectObject(hdc, hfont);
423 otm.otmSize = sizeof(otm);
424 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
425 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
426 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
428 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
429 SelectObject(hdc, old_hfont);
430 DeleteObject(hfont);
432 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
433 lf.lfHeight = otm.otmEMSquare;
434 lf.lfHeight = -lf.lfHeight;
435 hfont = create_font("outline", &lf);
436 old_hfont = SelectObject(hdc, hfont);
437 otm.otmSize = sizeof(otm);
438 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
441 SelectObject(hdc, old_hfont);
442 DeleteObject(hfont);
444 height_orig = otm.otmTextMetrics.tmHeight;
445 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
447 /* test integer scaling 3x2 */
448 lf.lfHeight = height_orig * 2;
449 lf.lfWidth = lfWidth * 3;
450 hfont = create_font("3x2", &lf);
451 old_hfont = SelectObject(hdc, hfont);
452 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
453 SelectObject(hdc, old_hfont);
454 DeleteObject(hfont);
456 /* test integer scaling 3x3 */
457 lf.lfHeight = height_orig * 3;
458 lf.lfWidth = lfWidth * 3;
459 hfont = create_font("3x3", &lf);
460 old_hfont = SelectObject(hdc, hfont);
461 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
462 SelectObject(hdc, old_hfont);
463 DeleteObject(hfont);
465 /* test integer scaling 1x1 */
466 lf.lfHeight = height_orig * 1;
467 lf.lfWidth = lfWidth * 1;
468 hfont = create_font("1x1", &lf);
469 old_hfont = SelectObject(hdc, hfont);
470 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
471 SelectObject(hdc, old_hfont);
472 DeleteObject(hfont);
474 /* test integer scaling 1x1 */
475 lf.lfHeight = height_orig;
476 lf.lfWidth = 0;
477 hfont = create_font("1x1", &lf);
478 old_hfont = SelectObject(hdc, hfont);
479 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
481 /* with an identity matrix */
482 memset(&gm, 0, sizeof(gm));
483 SetLastError(0xdeadbeef);
484 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
485 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
486 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
487 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
488 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
489 /* with a custom matrix */
490 memset(&gm, 0, sizeof(gm));
491 SetLastError(0xdeadbeef);
492 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
493 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
495 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
496 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
498 /* Test that changing the DC transformation affects only the font
499 * selected on this DC and doesn't affect the same font selected on
500 * another DC.
502 hdc_2 = CreateCompatibleDC(0);
503 old_hfont_2 = SelectObject(hdc_2, hfont);
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 SetMapMode(hdc, MM_ANISOTROPIC);
508 /* font metrics on another DC should be unchanged */
509 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
511 /* test restrictions of compatibility mode GM_COMPATIBLE */
512 /* part 1: rescaling only X should not change font scaling on screen.
513 So compressing the X axis by 2 is not done, and this
514 appears as X scaling of 2 that no one requested. */
515 SetWindowExtEx(hdc, 100, 100, NULL);
516 SetViewportExtEx(hdc, 50, 100, NULL);
517 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
518 /* font metrics on another DC should be unchanged */
519 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
521 /* part 2: rescaling only Y should change font scaling.
522 As also X is scaled by a factor of 2, but this is not
523 requested by the DC transformation, we get a scaling factor
524 of 2 in the X coordinate. */
525 SetViewportExtEx(hdc, 100, 200, NULL);
526 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
527 /* font metrics on another DC should be unchanged */
528 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
530 /* restore scaling */
531 SetMapMode(hdc, MM_TEXT);
533 /* font metrics on another DC should be unchanged */
534 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
536 SelectObject(hdc_2, old_hfont_2);
537 DeleteDC(hdc_2);
539 if (!SetGraphicsMode(hdc, GM_ADVANCED))
541 SelectObject(hdc, old_hfont);
542 DeleteObject(hfont);
543 DeleteDC(hdc);
544 skip("GM_ADVANCED is not supported on this platform\n");
545 return;
548 xform.eM11 = 20.0f;
549 xform.eM12 = 0.0f;
550 xform.eM21 = 0.0f;
551 xform.eM22 = 20.0f;
552 xform.eDx = 0.0f;
553 xform.eDy = 0.0f;
555 SetLastError(0xdeadbeef);
556 ret = SetWorldTransform(hdc, &xform);
557 ok(ret, "SetWorldTransform error %u\n", GetLastError());
559 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
561 /* with an identity matrix */
562 memset(&gm, 0, sizeof(gm));
563 SetLastError(0xdeadbeef);
564 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
565 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
566 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
567 pt.x = width_orig; pt.y = 0;
568 LPtoDP(hdc, &pt, 1);
569 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
570 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
571 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
572 /* with a custom matrix */
573 memset(&gm, 0, sizeof(gm));
574 SetLastError(0xdeadbeef);
575 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
576 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
577 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
578 pt.x = width_orig; pt.y = 0;
579 LPtoDP(hdc, &pt, 1);
580 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
581 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
582 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
584 SetLastError(0xdeadbeef);
585 ret = SetMapMode(hdc, MM_LOMETRIC);
586 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
588 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
590 /* with an identity matrix */
591 memset(&gm, 0, sizeof(gm));
592 SetLastError(0xdeadbeef);
593 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
594 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
595 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
596 pt.x = width_orig; pt.y = 0;
597 LPtoDP(hdc, &pt, 1);
598 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
599 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
600 /* with a custom matrix */
601 memset(&gm, 0, sizeof(gm));
602 SetLastError(0xdeadbeef);
603 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
604 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
605 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
606 pt.x = width_orig; pt.y = 0;
607 LPtoDP(hdc, &pt, 1);
608 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
609 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
611 SetLastError(0xdeadbeef);
612 ret = SetMapMode(hdc, MM_TEXT);
613 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
615 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
617 /* with an identity matrix */
618 memset(&gm, 0, sizeof(gm));
619 SetLastError(0xdeadbeef);
620 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
621 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
622 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
623 pt.x = width_orig; pt.y = 0;
624 LPtoDP(hdc, &pt, 1);
625 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
626 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
627 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
628 /* with a custom matrix */
629 memset(&gm, 0, sizeof(gm));
630 SetLastError(0xdeadbeef);
631 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
632 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
633 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
634 pt.x = width_orig; pt.y = 0;
635 LPtoDP(hdc, &pt, 1);
636 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
637 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
638 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
640 SelectObject(hdc, old_hfont);
641 DeleteObject(hfont);
642 DeleteDC(hdc);
645 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
647 LOGFONT *lf = (LOGFONT *)lParam;
649 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
651 *lf = *elf;
652 return 0; /* stop enumeration */
654 return 1; /* continue enumeration */
657 static void test_bitmap_font_metrics(void)
659 static const struct font_data
661 const char face_name[LF_FACESIZE];
662 int weight, height, ascent, descent, int_leading, ext_leading;
663 int ave_char_width, max_char_width, dpi;
664 DWORD ansi_bitfield;
665 } fd[] =
667 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
668 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
669 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
670 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
671 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
672 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
673 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
674 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
675 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
676 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
677 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
679 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
680 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
681 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
682 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
684 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
685 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
688 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
689 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
690 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
691 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
692 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
693 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
694 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
695 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
696 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
697 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
698 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
699 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
700 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
701 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
702 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
703 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
704 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
706 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
707 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
709 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
710 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
711 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
712 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
713 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
714 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
715 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
718 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
719 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
720 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
722 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
723 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
724 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
726 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
727 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
729 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
730 * require a new system.sfd for that font
732 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
734 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
735 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
737 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
738 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
739 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
740 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
741 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
742 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
743 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
744 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
745 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
746 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
747 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
748 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
749 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
750 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
751 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
752 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
753 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
755 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
757 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
758 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
759 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
761 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
762 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
765 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
766 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
768 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
769 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
770 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
772 /* The 120dpi version still has its dpi marked as 96 */
773 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
775 /* FIXME: add "Terminal" */
777 HDC hdc;
778 LOGFONT lf;
779 HFONT hfont, old_hfont;
780 TEXTMETRIC tm;
781 INT ret, i;
783 hdc = CreateCompatibleDC(0);
784 assert(hdc);
786 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
788 int bit;
790 memset(&lf, 0, sizeof(lf));
792 lf.lfHeight = fd[i].height;
793 strcpy(lf.lfFaceName, fd[i].face_name);
795 for(bit = 0; bit < 32; bit++)
797 DWORD fs[2];
798 CHARSETINFO csi;
800 fs[0] = 1L << bit;
801 fs[1] = 0;
802 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
803 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
805 lf.lfCharSet = csi.ciCharset;
806 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
807 if (ret) continue;
809 hfont = create_font(lf.lfFaceName, &lf);
810 old_hfont = SelectObject(hdc, hfont);
811 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
812 if(fd[i].dpi == tm.tmDigitizedAspectX)
814 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
815 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);
816 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);
817 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);
818 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);
819 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);
820 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);
821 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);
823 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
824 that make the max width bigger */
825 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
826 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);
828 SelectObject(hdc, old_hfont);
829 DeleteObject(hfont);
833 DeleteDC(hdc);
836 static void test_GdiGetCharDimensions(void)
838 HDC hdc;
839 TEXTMETRICW tm;
840 LONG ret;
841 SIZE size;
842 LONG avgwidth, height;
843 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
845 if (!pGdiGetCharDimensions)
847 win_skip("GdiGetCharDimensions not available on this platform\n");
848 return;
851 hdc = CreateCompatibleDC(NULL);
853 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
854 avgwidth = ((size.cx / 26) + 1) / 2;
856 ret = pGdiGetCharDimensions(hdc, &tm, &height);
857 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
858 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
860 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
861 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
863 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
864 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
866 height = 0;
867 ret = pGdiGetCharDimensions(hdc, NULL, &height);
868 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
869 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
871 DeleteDC(hdc);
874 static void test_GetCharABCWidths(void)
876 static const WCHAR str[] = {'a',0};
877 BOOL ret;
878 HDC hdc;
879 LOGFONTA lf;
880 HFONT hfont;
881 ABC abc[1];
882 WORD glyphs[1];
883 DWORD nb;
885 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
887 win_skip("GetCharABCWidthsW/I not available on this platform\n");
888 return;
891 memset(&lf, 0, sizeof(lf));
892 strcpy(lf.lfFaceName, "System");
893 lf.lfHeight = 20;
895 hfont = CreateFontIndirectA(&lf);
896 hdc = GetDC(0);
897 hfont = SelectObject(hdc, hfont);
899 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
900 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
902 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
903 ok(!ret, "GetCharABCWidthsI should have failed\n");
905 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
906 ok(!ret, "GetCharABCWidthsI should have failed\n");
908 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
909 ok(ret, "GetCharABCWidthsI should have succeeded\n");
911 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
912 ok(!ret, "GetCharABCWidthsW should have failed\n");
914 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
915 ok(!ret, "GetCharABCWidthsW should have failed\n");
917 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
918 ok(!ret, "GetCharABCWidthsW should have failed\n");
920 hfont = SelectObject(hdc, hfont);
921 DeleteObject(hfont);
922 ReleaseDC(NULL, hdc);
925 static void test_text_extents(void)
927 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
928 LPINT extents;
929 INT i, len, fit1, fit2;
930 LOGFONTA lf;
931 TEXTMETRICA tm;
932 HDC hdc;
933 HFONT hfont;
934 SIZE sz;
935 SIZE sz1, sz2;
937 memset(&lf, 0, sizeof(lf));
938 strcpy(lf.lfFaceName, "Arial");
939 lf.lfHeight = 20;
941 hfont = CreateFontIndirectA(&lf);
942 hdc = GetDC(0);
943 hfont = SelectObject(hdc, hfont);
944 GetTextMetricsA(hdc, &tm);
945 GetTextExtentPointA(hdc, "o", 1, &sz);
946 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
948 SetLastError(0xdeadbeef);
949 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
950 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
952 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
953 hfont = SelectObject(hdc, hfont);
954 DeleteObject(hfont);
955 ReleaseDC(0, hdc);
956 return;
959 len = lstrlenW(wt);
960 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
961 extents[0] = 1; /* So that the increasing sequence test will fail
962 if the extents array is untouched. */
963 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
964 GetTextExtentPointW(hdc, wt, len, &sz2);
965 ok(sz1.cy == sz2.cy,
966 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
967 /* Because of the '\n' in the string GetTextExtentExPoint and
968 GetTextExtentPoint return different widths under Win2k, but
969 under WinXP they return the same width. So we don't test that
970 here. */
972 for (i = 1; i < len; ++i)
973 ok(extents[i-1] <= extents[i],
974 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
976 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
977 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
978 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
979 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
980 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
981 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
982 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
983 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
984 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
985 ok(extents[0] == extents[2] && extents[1] == extents[3],
986 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
987 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
988 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
989 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
990 HeapFree(GetProcessHeap(), 0, extents);
992 hfont = SelectObject(hdc, hfont);
993 DeleteObject(hfont);
994 ReleaseDC(NULL, hdc);
997 static void test_GetGlyphIndices(void)
999 HDC hdc;
1000 HFONT hfont;
1001 DWORD charcount;
1002 LOGFONTA lf;
1003 DWORD flags = 0;
1004 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1005 WORD glyphs[(sizeof(testtext)/2)-1];
1006 TEXTMETRIC textm;
1007 HFONT hOldFont;
1009 if (!pGetGlyphIndicesW) {
1010 win_skip("GetGlyphIndicesW not available on platform\n");
1011 return;
1014 hdc = GetDC(0);
1016 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1017 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1018 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1019 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1020 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1021 flags = 0;
1022 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1023 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1024 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1025 textm.tmDefaultChar, glyphs[4]);
1027 if(!is_font_installed("Tahoma"))
1029 skip("Tahoma is not installed so skipping this test\n");
1030 return;
1032 memset(&lf, 0, sizeof(lf));
1033 strcpy(lf.lfFaceName, "Tahoma");
1034 lf.lfHeight = 20;
1036 hfont = CreateFontIndirectA(&lf);
1037 hOldFont = SelectObject(hdc, hfont);
1038 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1039 flags |= GGI_MARK_NONEXISTING_GLYPHS;
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[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1043 flags = 0;
1044 testtext[0] = textm.tmDefaultChar;
1045 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1046 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1047 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1048 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1049 DeleteObject(SelectObject(hdc, hOldFont));
1052 static void test_GetKerningPairs(void)
1054 static const struct kerning_data
1056 const char face_name[LF_FACESIZE];
1057 LONG height;
1058 /* some interesting fields from OUTLINETEXTMETRIC */
1059 LONG tmHeight, tmAscent, tmDescent;
1060 UINT otmEMSquare;
1061 INT otmAscent;
1062 INT otmDescent;
1063 UINT otmLineGap;
1064 UINT otmsCapEmHeight;
1065 UINT otmsXHeight;
1066 INT otmMacAscent;
1067 INT otmMacDescent;
1068 UINT otmMacLineGap;
1069 UINT otmusMinimumPPEM;
1070 /* small subset of kerning pairs to test */
1071 DWORD total_kern_pairs;
1072 const KERNINGPAIR kern_pair[26];
1073 } kd[] =
1075 {"Arial", 12, 12, 9, 3,
1076 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1079 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1080 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1081 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1082 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1083 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1084 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1085 {933,970,+1},{933,972,-1}
1088 {"Arial", -34, 39, 32, 7,
1089 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1092 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1093 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1094 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1095 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1096 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1097 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1098 {933,970,+2},{933,972,-3}
1101 { "Arial", 120, 120, 97, 23,
1102 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1105 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1106 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1107 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1108 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1109 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1110 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1111 {933,970,+6},{933,972,-10}
1114 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1115 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1116 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1119 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1120 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1121 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1122 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1123 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1124 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1125 {933,970,+54},{933,972,-83}
1128 #endif
1130 LOGFONT lf;
1131 HFONT hfont, hfont_old;
1132 KERNINGPAIR *kern_pair;
1133 HDC hdc;
1134 DWORD total_kern_pairs, ret, i, n, matches;
1136 hdc = GetDC(0);
1138 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1139 * which may render this test unusable, so we're trying to avoid that.
1141 SetLastError(0xdeadbeef);
1142 GetKerningPairsW(hdc, 0, NULL);
1143 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1145 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1146 ReleaseDC(0, hdc);
1147 return;
1150 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1152 OUTLINETEXTMETRICW otm;
1154 if (!is_font_installed(kd[i].face_name))
1156 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1157 continue;
1160 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1162 memset(&lf, 0, sizeof(lf));
1163 strcpy(lf.lfFaceName, kd[i].face_name);
1164 lf.lfHeight = kd[i].height;
1165 hfont = CreateFontIndirect(&lf);
1166 assert(hfont != 0);
1168 hfont_old = SelectObject(hdc, hfont);
1170 SetLastError(0xdeadbeef);
1171 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1172 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1174 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1175 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1176 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1177 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1178 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1179 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1181 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1182 kd[i].otmEMSquare, otm.otmEMSquare);
1183 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1184 kd[i].otmAscent, otm.otmAscent);
1185 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1186 kd[i].otmDescent, otm.otmDescent);
1187 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1188 kd[i].otmLineGap, otm.otmLineGap);
1189 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1190 kd[i].otmMacDescent, otm.otmMacDescent);
1191 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1192 kd[i].otmMacAscent, otm.otmMacAscent);
1193 todo_wine {
1194 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1195 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1196 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1197 kd[i].otmsXHeight, otm.otmsXHeight);
1198 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1199 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1200 kd[i].otmMacLineGap, otm.otmMacLineGap);
1201 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1202 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1205 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1206 trace("total_kern_pairs %u\n", total_kern_pairs);
1207 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1209 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1210 SetLastError(0xdeadbeef);
1211 ret = GetKerningPairsW(hdc, 0, kern_pair);
1212 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1213 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1214 ok(ret == 0, "got %lu, expected 0\n", ret);
1215 #endif
1217 ret = GetKerningPairsW(hdc, 100, NULL);
1218 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1220 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1221 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1223 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1224 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1226 matches = 0;
1228 for (n = 0; n < ret; n++)
1230 DWORD j;
1231 #if 0
1232 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1233 trace("{'%c','%c',%d},\n",
1234 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1235 #endif
1236 for (j = 0; j < kd[i].total_kern_pairs; j++)
1238 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1239 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1241 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1242 "pair %d:%d got %d, expected %d\n",
1243 kern_pair[n].wFirst, kern_pair[n].wSecond,
1244 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1245 matches++;
1250 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1251 matches, kd[i].total_kern_pairs);
1253 HeapFree(GetProcessHeap(), 0, kern_pair);
1255 SelectObject(hdc, hfont_old);
1256 DeleteObject(hfont);
1259 ReleaseDC(0, hdc);
1262 static void test_height_selection(void)
1264 static const struct font_data
1266 const char face_name[LF_FACESIZE];
1267 int requested_height;
1268 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1269 } fd[] =
1271 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1272 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1273 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1274 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1275 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1276 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1277 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1278 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1279 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1280 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1282 HDC hdc;
1283 LOGFONT lf;
1284 HFONT hfont, old_hfont;
1285 TEXTMETRIC tm;
1286 INT ret, i;
1288 hdc = CreateCompatibleDC(0);
1289 assert(hdc);
1291 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1293 if (!is_truetype_font_installed(fd[i].face_name))
1295 skip("%s is not installed\n", fd[i].face_name);
1296 continue;
1299 memset(&lf, 0, sizeof(lf));
1300 lf.lfHeight = fd[i].requested_height;
1301 lf.lfWeight = fd[i].weight;
1302 strcpy(lf.lfFaceName, fd[i].face_name);
1304 hfont = CreateFontIndirect(&lf);
1305 assert(hfont);
1307 old_hfont = SelectObject(hdc, hfont);
1308 ret = GetTextMetrics(hdc, &tm);
1309 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1310 if(fd[i].dpi == tm.tmDigitizedAspectX)
1312 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1313 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1314 ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1315 ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1316 ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1317 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1318 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1319 #endif
1320 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1323 SelectObject(hdc, old_hfont);
1324 DeleteObject(hfont);
1327 DeleteDC(hdc);
1330 static void test_GetOutlineTextMetrics(void)
1332 OUTLINETEXTMETRIC *otm;
1333 LOGFONT lf;
1334 HFONT hfont, hfont_old;
1335 HDC hdc;
1336 DWORD ret, otm_size;
1337 LPSTR unset_ptr;
1339 if (!is_font_installed("Arial"))
1341 skip("Arial is not installed\n");
1342 return;
1345 hdc = GetDC(0);
1347 memset(&lf, 0, sizeof(lf));
1348 strcpy(lf.lfFaceName, "Arial");
1349 lf.lfHeight = -13;
1350 lf.lfWeight = FW_NORMAL;
1351 lf.lfPitchAndFamily = DEFAULT_PITCH;
1352 lf.lfQuality = PROOF_QUALITY;
1353 hfont = CreateFontIndirect(&lf);
1354 assert(hfont != 0);
1356 hfont_old = SelectObject(hdc, hfont);
1357 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1358 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1360 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1362 memset(otm, 0xAA, otm_size);
1363 SetLastError(0xdeadbeef);
1364 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1365 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1366 ok(ret == 1 /* Win9x */ ||
1367 ret == otm->otmSize /* XP*/,
1368 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1369 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1371 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1372 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1373 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1374 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1377 memset(otm, 0xAA, otm_size);
1378 SetLastError(0xdeadbeef);
1379 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1380 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1381 ok(ret == 1 /* Win9x */ ||
1382 ret == otm->otmSize /* XP*/,
1383 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1384 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1386 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1387 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1388 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1389 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1392 /* ask about truncated data */
1393 memset(otm, 0xAA, otm_size);
1394 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1395 SetLastError(0xdeadbeef);
1396 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1397 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1398 ok(ret == 1 /* Win9x */ ||
1399 ret == otm->otmSize /* XP*/,
1400 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1401 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1403 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1404 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1405 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1407 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1409 HeapFree(GetProcessHeap(), 0, otm);
1411 SelectObject(hdc, hfont_old);
1412 DeleteObject(hfont);
1414 ReleaseDC(0, hdc);
1417 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1419 INT y,
1420 breakCount,
1421 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1422 areaWidth = clientArea->right - clientArea->left,
1423 nErrors = 0, e;
1424 BOOL lastExtent = FALSE;
1425 PSTR pFirstChar, pLastChar;
1426 SIZE size;
1427 TEXTMETRICA tm;
1428 struct err
1430 char extent[100];
1431 int GetTextExtentExPointWWidth;
1432 } error[10];
1434 GetTextMetricsA(hdc, &tm);
1435 y = clientArea->top;
1436 do {
1437 breakCount = 0;
1438 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1439 pFirstChar = str;
1441 do {
1442 pLastChar = str;
1444 /* if not at the end of the string, ... */
1445 if (*str == '\0') break;
1446 /* ... add the next word to the current extent */
1447 while (*str != '\0' && *str++ != tm.tmBreakChar);
1448 breakCount++;
1449 SetTextJustification(hdc, 0, 0);
1450 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1451 } while ((int) size.cx < areaWidth);
1453 /* ignore trailing break chars */
1454 breakCount--;
1455 while (*(pLastChar - 1) == tm.tmBreakChar)
1457 pLastChar--;
1458 breakCount--;
1461 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1463 SetTextJustification(hdc, 0, 0);
1464 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1466 /* do not justify the last extent */
1467 if (*str != '\0' && breakCount > 0)
1469 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1470 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1471 justifiedWidth = size.cx;
1473 else lastExtent = TRUE;
1475 /* catch errors and report them */
1476 if (!lastExtent && (justifiedWidth != areaWidth))
1478 memset(error[nErrors].extent, 0, 100);
1479 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1480 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1481 nErrors++;
1484 y += size.cy;
1485 str = pLastChar;
1486 } while (*str && y < clientArea->bottom);
1488 for (e = 0; e < nErrors; e++)
1490 /* The width returned by GetTextExtentPoint32() is exactly the same
1491 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1492 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1493 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1494 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1498 static void test_SetTextJustification(void)
1500 HDC hdc;
1501 RECT clientArea;
1502 LOGFONTA lf;
1503 HFONT hfont;
1504 HWND hwnd;
1505 static char testText[] =
1506 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1507 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1508 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1509 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1510 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1511 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1512 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1514 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1515 GetClientRect( hwnd, &clientArea );
1516 hdc = GetDC( hwnd );
1518 memset(&lf, 0, sizeof lf);
1519 lf.lfCharSet = ANSI_CHARSET;
1520 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1521 lf.lfWeight = FW_DONTCARE;
1522 lf.lfHeight = 20;
1523 lf.lfQuality = DEFAULT_QUALITY;
1524 lstrcpyA(lf.lfFaceName, "Times New Roman");
1525 hfont = create_font("Times New Roman", &lf);
1526 SelectObject(hdc, hfont);
1528 testJustification(hdc, testText, &clientArea);
1530 DeleteObject(hfont);
1531 ReleaseDC(hwnd, hdc);
1532 DestroyWindow(hwnd);
1535 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1537 HDC hdc;
1538 LOGFONTA lf;
1539 HFONT hfont, hfont_old;
1540 CHARSETINFO csi;
1541 FONTSIGNATURE fs;
1542 INT cs;
1543 DWORD i, ret;
1544 char name[64];
1546 assert(count <= 128);
1548 memset(&lf, 0, sizeof(lf));
1550 lf.lfCharSet = charset;
1551 lf.lfHeight = 10;
1552 lstrcpyA(lf.lfFaceName, "Arial");
1553 SetLastError(0xdeadbeef);
1554 hfont = CreateFontIndirectA(&lf);
1555 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1557 hdc = GetDC(0);
1558 hfont_old = SelectObject(hdc, hfont);
1560 cs = GetTextCharsetInfo(hdc, &fs, 0);
1561 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1563 SetLastError(0xdeadbeef);
1564 ret = GetTextFaceA(hdc, sizeof(name), name);
1565 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1567 if (charset == SYMBOL_CHARSET)
1569 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1570 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1572 else
1574 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1575 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1578 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1580 trace("Can't find codepage for charset %d\n", cs);
1581 ReleaseDC(0, hdc);
1582 return FALSE;
1584 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1586 if (unicode)
1588 char ansi_buf[128];
1589 WCHAR unicode_buf[128];
1591 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1593 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1595 SetLastError(0xdeadbeef);
1596 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1597 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1599 else
1601 char ansi_buf[128];
1603 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1605 SetLastError(0xdeadbeef);
1606 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1607 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1610 SelectObject(hdc, hfont_old);
1611 DeleteObject(hfont);
1613 ReleaseDC(0, hdc);
1615 return TRUE;
1618 static void test_font_charset(void)
1620 static struct charset_data
1622 INT charset;
1623 UINT code_page;
1624 WORD font_idxA[128], font_idxW[128];
1625 } cd[] =
1627 { ANSI_CHARSET, 1252 },
1628 { RUSSIAN_CHARSET, 1251 },
1629 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1631 int i;
1633 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1635 win_skip("Skipping the font charset test on a Win9x platform\n");
1636 return;
1639 if (!is_font_installed("Arial"))
1641 skip("Arial is not installed\n");
1642 return;
1645 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1647 if (cd[i].charset == SYMBOL_CHARSET)
1649 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1651 skip("Symbol or Wingdings is not installed\n");
1652 break;
1655 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1656 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1657 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1660 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1661 if (i > 2)
1663 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1664 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1666 else
1667 skip("Symbol or Wingdings is not installed\n");
1670 static void test_GetFontUnicodeRanges(void)
1672 LOGFONTA lf;
1673 HDC hdc;
1674 HFONT hfont, hfont_old;
1675 DWORD size;
1676 GLYPHSET *gs;
1678 if (!pGetFontUnicodeRanges)
1680 win_skip("GetFontUnicodeRanges not available before W2K\n");
1681 return;
1684 memset(&lf, 0, sizeof(lf));
1685 lstrcpyA(lf.lfFaceName, "Arial");
1686 hfont = create_font("Arial", &lf);
1688 hdc = GetDC(0);
1689 hfont_old = SelectObject(hdc, hfont);
1691 size = pGetFontUnicodeRanges(NULL, NULL);
1692 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1694 size = pGetFontUnicodeRanges(hdc, NULL);
1695 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1697 gs = HeapAlloc(GetProcessHeap(), 0, size);
1699 size = pGetFontUnicodeRanges(hdc, gs);
1700 ok(size, "GetFontUnicodeRanges failed\n");
1701 #if 0
1702 for (i = 0; i < gs->cRanges; i++)
1703 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1704 #endif
1705 trace("found %u ranges\n", gs->cRanges);
1707 HeapFree(GetProcessHeap(), 0, gs);
1709 SelectObject(hdc, hfont_old);
1710 DeleteObject(hfont);
1711 ReleaseDC(NULL, hdc);
1714 #define MAX_ENUM_FONTS 4096
1716 struct enum_font_data
1718 int total;
1719 LOGFONT lf[MAX_ENUM_FONTS];
1722 struct enum_font_dataW
1724 int total;
1725 LOGFONTW lf[MAX_ENUM_FONTS];
1728 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1730 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1732 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1734 if (type != TRUETYPE_FONTTYPE) return 1;
1735 #if 0
1736 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1737 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1738 #endif
1739 if (efd->total < MAX_ENUM_FONTS)
1740 efd->lf[efd->total++] = *lf;
1741 else
1742 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1744 return 1;
1747 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1749 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1751 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1753 if (type != TRUETYPE_FONTTYPE) return 1;
1754 #if 0
1755 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1756 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1757 #endif
1758 if (efd->total < MAX_ENUM_FONTS)
1759 efd->lf[efd->total++] = *lf;
1760 else
1761 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1763 return 1;
1766 static void get_charset_stats(struct enum_font_data *efd,
1767 int *ansi_charset, int *symbol_charset,
1768 int *russian_charset)
1770 int i;
1772 *ansi_charset = 0;
1773 *symbol_charset = 0;
1774 *russian_charset = 0;
1776 for (i = 0; i < efd->total; i++)
1778 switch (efd->lf[i].lfCharSet)
1780 case ANSI_CHARSET:
1781 (*ansi_charset)++;
1782 break;
1783 case SYMBOL_CHARSET:
1784 (*symbol_charset)++;
1785 break;
1786 case RUSSIAN_CHARSET:
1787 (*russian_charset)++;
1788 break;
1793 static void get_charset_statsW(struct enum_font_dataW *efd,
1794 int *ansi_charset, int *symbol_charset,
1795 int *russian_charset)
1797 int i;
1799 *ansi_charset = 0;
1800 *symbol_charset = 0;
1801 *russian_charset = 0;
1803 for (i = 0; i < efd->total; i++)
1805 switch (efd->lf[i].lfCharSet)
1807 case ANSI_CHARSET:
1808 (*ansi_charset)++;
1809 break;
1810 case SYMBOL_CHARSET:
1811 (*symbol_charset)++;
1812 break;
1813 case RUSSIAN_CHARSET:
1814 (*russian_charset)++;
1815 break;
1820 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1822 struct enum_font_data efd;
1823 struct enum_font_dataW efdw;
1824 LOGFONT lf;
1825 HDC hdc;
1826 int i, ret, ansi_charset, symbol_charset, russian_charset;
1828 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1830 if (*font_name && !is_truetype_font_installed(font_name))
1832 skip("%s is not installed\n", font_name);
1833 return;
1836 hdc = GetDC(0);
1838 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1839 * while EnumFontFamiliesEx doesn't.
1841 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1844 * Use EnumFontFamiliesW since win98 crashes when the
1845 * second parameter is NULL using EnumFontFamilies
1847 efdw.total = 0;
1848 SetLastError(0xdeadbeef);
1849 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1850 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1851 if(ret)
1853 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1854 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1855 ansi_charset, symbol_charset, russian_charset);
1856 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1857 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1858 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1859 ok(russian_charset > 0 ||
1860 broken(russian_charset == 0), /* NT4 */
1861 "NULL family should enumerate RUSSIAN_CHARSET\n");
1864 efdw.total = 0;
1865 SetLastError(0xdeadbeef);
1866 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1867 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1868 if(ret)
1870 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1871 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1872 ansi_charset, symbol_charset, russian_charset);
1873 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1874 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1875 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1876 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1880 efd.total = 0;
1881 SetLastError(0xdeadbeef);
1882 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1883 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1884 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1885 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1886 ansi_charset, symbol_charset, russian_charset,
1887 *font_name ? font_name : "<empty>");
1888 if (*font_name)
1889 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1890 else
1891 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1892 for (i = 0; i < efd.total; i++)
1894 /* FIXME: remove completely once Wine is fixed */
1895 if (efd.lf[i].lfCharSet != font_charset)
1897 todo_wine
1898 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1900 else
1901 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1902 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1903 font_name, efd.lf[i].lfFaceName);
1906 memset(&lf, 0, sizeof(lf));
1907 lf.lfCharSet = ANSI_CHARSET;
1908 lstrcpy(lf.lfFaceName, font_name);
1909 efd.total = 0;
1910 SetLastError(0xdeadbeef);
1911 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1912 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1913 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1914 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1915 ansi_charset, symbol_charset, russian_charset,
1916 *font_name ? font_name : "<empty>");
1917 if (font_charset == SYMBOL_CHARSET)
1919 if (*font_name)
1920 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1921 else
1922 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1924 else
1926 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1927 for (i = 0; i < efd.total; i++)
1929 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1930 if (*font_name)
1931 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1932 font_name, efd.lf[i].lfFaceName);
1936 /* DEFAULT_CHARSET should enumerate all available charsets */
1937 memset(&lf, 0, sizeof(lf));
1938 lf.lfCharSet = DEFAULT_CHARSET;
1939 lstrcpy(lf.lfFaceName, font_name);
1940 efd.total = 0;
1941 SetLastError(0xdeadbeef);
1942 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1943 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1944 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1945 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1946 ansi_charset, symbol_charset, russian_charset,
1947 *font_name ? font_name : "<empty>");
1948 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1949 for (i = 0; i < efd.total; i++)
1951 if (*font_name)
1952 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1953 font_name, efd.lf[i].lfFaceName);
1955 if (*font_name)
1957 switch (font_charset)
1959 case ANSI_CHARSET:
1960 ok(ansi_charset > 0,
1961 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1962 ok(!symbol_charset,
1963 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1964 ok(russian_charset > 0,
1965 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1966 break;
1967 case SYMBOL_CHARSET:
1968 ok(!ansi_charset,
1969 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1970 ok(symbol_charset,
1971 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1972 ok(!russian_charset,
1973 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1974 break;
1975 case DEFAULT_CHARSET:
1976 ok(ansi_charset > 0,
1977 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1978 ok(symbol_charset > 0,
1979 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1980 ok(russian_charset > 0,
1981 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1982 break;
1985 else
1987 ok(ansi_charset > 0,
1988 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1989 ok(symbol_charset > 0,
1990 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1991 ok(russian_charset > 0,
1992 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1995 memset(&lf, 0, sizeof(lf));
1996 lf.lfCharSet = SYMBOL_CHARSET;
1997 lstrcpy(lf.lfFaceName, font_name);
1998 efd.total = 0;
1999 SetLastError(0xdeadbeef);
2000 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2001 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2002 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2003 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2004 ansi_charset, symbol_charset, russian_charset,
2005 *font_name ? font_name : "<empty>");
2006 if (*font_name && font_charset == ANSI_CHARSET)
2007 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2008 else
2010 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2011 for (i = 0; i < efd.total; i++)
2013 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2014 if (*font_name)
2015 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2016 font_name, efd.lf[i].lfFaceName);
2019 ok(!ansi_charset,
2020 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2021 ok(symbol_charset > 0,
2022 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2023 ok(!russian_charset,
2024 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2027 ReleaseDC(0, hdc);
2030 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2032 HFONT hfont, hfont_prev;
2033 DWORD ret;
2034 GLYPHMETRICS gm1, gm2;
2035 LOGFONTA lf2 = *lf;
2036 WORD idx;
2037 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2039 if(!pGetGlyphIndicesA)
2040 return;
2042 /* negative widths are handled just as positive ones */
2043 lf2.lfWidth = -lf->lfWidth;
2045 SetLastError(0xdeadbeef);
2046 hfont = CreateFontIndirectA(lf);
2047 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2048 check_font("original", lf, hfont);
2050 hfont_prev = SelectObject(hdc, hfont);
2052 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2053 if (ret == GDI_ERROR || idx == 0xffff)
2055 SelectObject(hdc, hfont_prev);
2056 DeleteObject(hfont);
2057 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2058 return;
2061 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2062 memset(&gm1, 0xab, sizeof(gm1));
2063 SetLastError(0xdeadbeef);
2064 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2065 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2067 SelectObject(hdc, hfont_prev);
2068 DeleteObject(hfont);
2070 SetLastError(0xdeadbeef);
2071 hfont = CreateFontIndirectA(&lf2);
2072 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2073 check_font("negative width", &lf2, hfont);
2075 hfont_prev = SelectObject(hdc, hfont);
2077 memset(&gm2, 0xbb, sizeof(gm2));
2078 SetLastError(0xdeadbeef);
2079 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2080 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2082 SelectObject(hdc, hfont_prev);
2083 DeleteObject(hfont);
2085 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2086 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2087 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2088 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2089 gm1.gmCellIncX == gm2.gmCellIncX &&
2090 gm1.gmCellIncY == gm2.gmCellIncY,
2091 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2092 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2093 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2094 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2095 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2098 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2099 #include "pshpack2.h"
2100 typedef struct
2102 USHORT version;
2103 SHORT xAvgCharWidth;
2104 USHORT usWeightClass;
2105 USHORT usWidthClass;
2106 SHORT fsType;
2107 SHORT ySubscriptXSize;
2108 SHORT ySubscriptYSize;
2109 SHORT ySubscriptXOffset;
2110 SHORT ySubscriptYOffset;
2111 SHORT ySuperscriptXSize;
2112 SHORT ySuperscriptYSize;
2113 SHORT ySuperscriptXOffset;
2114 SHORT ySuperscriptYOffset;
2115 SHORT yStrikeoutSize;
2116 SHORT yStrikeoutPosition;
2117 SHORT sFamilyClass;
2118 PANOSE panose;
2119 ULONG ulUnicodeRange1;
2120 ULONG ulUnicodeRange2;
2121 ULONG ulUnicodeRange3;
2122 ULONG ulUnicodeRange4;
2123 CHAR achVendID[4];
2124 USHORT fsSelection;
2125 USHORT usFirstCharIndex;
2126 USHORT usLastCharIndex;
2127 /* According to the Apple spec, original version didn't have the below fields,
2128 * version numbers were taked from the OpenType spec.
2130 /* version 0 (TrueType 1.5) */
2131 USHORT sTypoAscender;
2132 USHORT sTypoDescender;
2133 USHORT sTypoLineGap;
2134 USHORT usWinAscent;
2135 USHORT usWinDescent;
2136 /* version 1 (TrueType 1.66) */
2137 ULONG ulCodePageRange1;
2138 ULONG ulCodePageRange2;
2139 /* version 2 (OpenType 1.2) */
2140 SHORT sxHeight;
2141 SHORT sCapHeight;
2142 USHORT usDefaultChar;
2143 USHORT usBreakChar;
2144 USHORT usMaxContext;
2145 } TT_OS2_V2;
2146 #include "poppack.h"
2148 #ifdef WORDS_BIGENDIAN
2149 #define GET_BE_WORD(x) (x)
2150 #define GET_BE_DWORD(x) (x)
2151 #else
2152 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2153 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2154 #endif
2156 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2157 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2158 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2159 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2160 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2162 typedef struct
2164 USHORT version;
2165 USHORT num_tables;
2166 } cmap_header;
2168 typedef struct
2170 USHORT plat_id;
2171 USHORT enc_id;
2172 ULONG offset;
2173 } cmap_encoding_record;
2175 typedef struct
2177 USHORT format;
2178 USHORT length;
2179 USHORT language;
2181 BYTE glyph_ids[256];
2182 } cmap_format_0;
2184 typedef struct
2186 USHORT format;
2187 USHORT length;
2188 USHORT language;
2190 USHORT seg_countx2;
2191 USHORT search_range;
2192 USHORT entry_selector;
2193 USHORT range_shift;
2195 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2196 /* Then follows:
2197 USHORT pad;
2198 USHORT start_count[seg_countx2 / 2];
2199 USHORT id_delta[seg_countx2 / 2];
2200 USHORT id_range_offset[seg_countx2 / 2];
2201 USHORT glyph_ids[];
2203 } cmap_format_4;
2205 typedef struct
2207 USHORT end_count;
2208 USHORT start_count;
2209 USHORT id_delta;
2210 USHORT id_range_offset;
2211 } cmap_format_4_seg;
2213 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2215 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2216 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2217 os2->panose.bWeight, os2->panose.bProportion);
2220 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2222 int i;
2223 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2225 *first = 256;
2227 for(i = 0; i < 256; i++)
2229 if(cmap->glyph_ids[i] == 0) continue;
2230 *last = i;
2231 if(*first == 256) *first = i;
2233 if(*first == 256) return FALSE;
2234 return TRUE;
2237 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2239 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2240 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2241 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2242 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2243 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2246 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2248 int i;
2249 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2250 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2251 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2253 *first = 0x10000;
2255 for(i = 0; i < seg_count; i++)
2257 DWORD code, index;
2258 cmap_format_4_seg seg;
2260 get_seg4(cmap, i, &seg);
2261 for(code = seg.start_count; code <= seg.end_count; code++)
2263 if(seg.id_range_offset == 0)
2264 index = (seg.id_delta + code) & 0xffff;
2265 else
2267 index = seg.id_range_offset / 2
2268 + code - seg.start_count
2269 + i - seg_count;
2271 /* some fonts have broken last segment */
2272 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2273 index = GET_BE_WORD(glyph_ids[index]);
2274 else
2276 trace("segment %04x/%04x index %04x points to nowhere\n",
2277 seg.start_count, seg.end_count, index);
2278 index = 0;
2280 if(index) index += seg.id_delta;
2282 if(*first == 0x10000)
2283 *last = *first = code;
2284 else if(index)
2285 *last = code;
2289 if(*first == 0x10000) return FALSE;
2290 return TRUE;
2293 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2295 USHORT i;
2296 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2298 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2300 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2301 return (BYTE *)header + GET_BE_DWORD(record->offset);
2302 record++;
2304 return NULL;
2307 typedef enum
2309 cmap_none,
2310 cmap_ms_unicode,
2311 cmap_ms_symbol
2312 } cmap_type;
2314 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2316 LONG size, ret;
2317 cmap_header *header;
2318 void *cmap;
2319 BOOL r = FALSE;
2320 WORD format;
2322 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2323 ok(size != GDI_ERROR, "no cmap table found\n");
2324 if(size == GDI_ERROR) return FALSE;
2326 header = HeapAlloc(GetProcessHeap(), 0, size);
2327 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2328 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2329 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2331 cmap = get_cmap(header, 3, 1);
2332 if(cmap)
2333 *cmap_type = cmap_ms_unicode;
2334 else
2336 cmap = get_cmap(header, 3, 0);
2337 if(cmap) *cmap_type = cmap_ms_symbol;
2339 if(!cmap)
2341 *cmap_type = cmap_none;
2342 goto end;
2345 format = GET_BE_WORD(*(WORD *)cmap);
2346 switch(format)
2348 case 0:
2349 r = get_first_last_from_cmap0(cmap, first, last);
2350 break;
2351 case 4:
2352 r = get_first_last_from_cmap4(cmap, first, last, size);
2353 break;
2354 default:
2355 trace("unhandled cmap format %d\n", format);
2356 break;
2359 end:
2360 HeapFree(GetProcessHeap(), 0, header);
2361 return r;
2364 static void test_text_metrics(const LOGFONTA *lf)
2366 HDC hdc;
2367 HFONT hfont, hfont_old;
2368 TEXTMETRICA tmA;
2369 TT_OS2_V2 tt_os2;
2370 LONG size, ret;
2371 const char *font_name = lf->lfFaceName;
2372 DWORD cmap_first = 0, cmap_last = 0;
2373 cmap_type cmap_type;
2375 hdc = GetDC(0);
2377 SetLastError(0xdeadbeef);
2378 hfont = CreateFontIndirectA(lf);
2379 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2381 hfont_old = SelectObject(hdc, hfont);
2383 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2384 if (size == GDI_ERROR)
2386 trace("OS/2 chunk was not found\n");
2387 goto end_of_test;
2389 if (size > sizeof(tt_os2))
2391 trace("got too large OS/2 chunk of size %u\n", size);
2392 size = sizeof(tt_os2);
2395 memset(&tt_os2, 0, sizeof(tt_os2));
2396 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2397 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2399 SetLastError(0xdeadbeef);
2400 ret = GetTextMetricsA(hdc, &tmA);
2401 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2403 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2405 skip("Unable to retrieve first and last glyphs from cmap\n");
2407 else
2409 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2410 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2411 UINT os2_first_char, os2_last_char, default_char, break_char;
2412 USHORT version;
2413 TEXTMETRICW tmW;
2415 version = GET_BE_WORD(tt_os2.version);
2417 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2418 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2419 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2420 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2422 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2423 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2424 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2426 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2428 expect_first_W = 0;
2429 switch(GetACP())
2431 case 1257: /* Baltic */
2432 expect_last_W = 0xf8fd;
2433 break;
2434 default:
2435 expect_last_W = 0xf0ff;
2437 expect_break_W = 0x20;
2438 expect_default_W = expect_break_W - 1;
2439 expect_first_A = 0x1e;
2440 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2442 else
2444 expect_first_W = cmap_first;
2445 expect_last_W = min(cmap_last, os2_last_char);
2446 if(os2_first_char <= 1)
2447 expect_break_W = os2_first_char + 2;
2448 else if(os2_first_char > 0xff)
2449 expect_break_W = 0x20;
2450 else
2451 expect_break_W = os2_first_char;
2452 expect_default_W = expect_break_W - 1;
2453 expect_first_A = expect_default_W - 1;
2454 expect_last_A = min(expect_last_W, 0xff);
2456 expect_break_A = expect_break_W;
2457 expect_default_A = expect_default_W;
2459 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2460 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2461 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2462 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2463 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2464 else
2465 ok(tmA.tmFirstChar == expect_first_A ||
2466 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2467 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2468 ok(tmA.tmLastChar == expect_last_A ||
2469 tmA.tmLastChar == 0xff /* win9x */,
2470 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2471 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2472 font_name, tmA.tmBreakChar, expect_break_A);
2473 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2474 font_name, tmA.tmDefaultChar, expect_default_A);
2477 SetLastError(0xdeadbeef);
2478 ret = GetTextMetricsW(hdc, &tmW);
2479 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2480 "GetTextMetricsW error %u\n", GetLastError());
2481 if (ret)
2483 /* Wine uses the os2 first char */
2484 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2485 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2486 font_name, tmW.tmFirstChar, expect_first_W);
2487 else
2488 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2489 font_name, tmW.tmFirstChar, expect_first_W);
2491 /* Wine uses the os2 last char */
2492 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2493 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2494 font_name, tmW.tmLastChar, expect_last_W);
2495 else
2496 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2497 font_name, tmW.tmLastChar, expect_last_W);
2498 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2499 font_name, tmW.tmBreakChar, expect_break_W);
2500 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2501 font_name, tmW.tmDefaultChar, expect_default_W);
2503 /* Test the aspect ratio while we have tmW */
2504 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2505 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2506 tmW.tmDigitizedAspectX, ret);
2507 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2508 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2509 tmW.tmDigitizedAspectX, ret);
2513 /* test FF_ values */
2514 switch(tt_os2.panose.bFamilyType)
2516 case PAN_ANY:
2517 case PAN_NO_FIT:
2518 case PAN_FAMILY_TEXT_DISPLAY:
2519 case PAN_FAMILY_PICTORIAL:
2520 default:
2521 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2522 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2524 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2525 break;
2527 switch(tt_os2.panose.bSerifStyle)
2529 case PAN_ANY:
2530 case PAN_NO_FIT:
2531 default:
2532 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2533 break;
2535 case PAN_SERIF_COVE:
2536 case PAN_SERIF_OBTUSE_COVE:
2537 case PAN_SERIF_SQUARE_COVE:
2538 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2539 case PAN_SERIF_SQUARE:
2540 case PAN_SERIF_THIN:
2541 case PAN_SERIF_BONE:
2542 case PAN_SERIF_EXAGGERATED:
2543 case PAN_SERIF_TRIANGLE:
2544 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2545 break;
2547 case PAN_SERIF_NORMAL_SANS:
2548 case PAN_SERIF_OBTUSE_SANS:
2549 case PAN_SERIF_PERP_SANS:
2550 case PAN_SERIF_FLARED:
2551 case PAN_SERIF_ROUNDED:
2552 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2553 break;
2555 break;
2557 case PAN_FAMILY_SCRIPT:
2558 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2559 break;
2561 case PAN_FAMILY_DECORATIVE:
2562 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2563 break;
2566 test_negative_width(hdc, lf);
2568 end_of_test:
2569 SelectObject(hdc, hfont_old);
2570 DeleteObject(hfont);
2572 ReleaseDC(0, hdc);
2575 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2577 INT *enumed = (INT *)lParam;
2579 if (type == TRUETYPE_FONTTYPE)
2581 (*enumed)++;
2582 test_text_metrics(lf);
2584 return 1;
2587 static void test_GetTextMetrics(void)
2589 LOGFONTA lf;
2590 HDC hdc;
2591 INT enumed;
2593 /* Report only once */
2594 if(!pGetGlyphIndicesA)
2595 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2597 hdc = GetDC(0);
2599 memset(&lf, 0, sizeof(lf));
2600 lf.lfCharSet = DEFAULT_CHARSET;
2601 enumed = 0;
2602 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2603 trace("Tested metrics of %d truetype fonts\n", enumed);
2605 ReleaseDC(0, hdc);
2608 static void test_nonexistent_font(void)
2610 static const struct
2612 const char *name;
2613 int charset;
2614 } font_subst[] =
2616 { "Times New Roman Baltic", 186 },
2617 { "Times New Roman CE", 238 },
2618 { "Times New Roman CYR", 204 },
2619 { "Times New Roman Greek", 161 },
2620 { "Times New Roman TUR", 162 }
2622 LOGFONTA lf;
2623 HDC hdc;
2624 HFONT hfont;
2625 CHARSETINFO csi;
2626 INT cs, expected_cs, i;
2627 char buf[LF_FACESIZE];
2629 if (!is_truetype_font_installed("Arial") ||
2630 !is_truetype_font_installed("Times New Roman"))
2632 skip("Arial or Times New Roman not installed\n");
2633 return;
2636 expected_cs = GetACP();
2637 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2639 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2640 return;
2642 expected_cs = csi.ciCharset;
2643 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2645 hdc = GetDC(0);
2647 memset(&lf, 0, sizeof(lf));
2648 lf.lfHeight = 100;
2649 lf.lfWeight = FW_REGULAR;
2650 lf.lfCharSet = ANSI_CHARSET;
2651 lf.lfPitchAndFamily = FF_SWISS;
2652 strcpy(lf.lfFaceName, "Nonexistent font");
2653 hfont = CreateFontIndirectA(&lf);
2654 hfont = SelectObject(hdc, hfont);
2655 GetTextFaceA(hdc, sizeof(buf), buf);
2656 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2657 cs = GetTextCharset(hdc);
2658 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2659 DeleteObject(SelectObject(hdc, hfont));
2661 memset(&lf, 0, sizeof(lf));
2662 lf.lfHeight = -13;
2663 lf.lfWeight = FW_DONTCARE;
2664 strcpy(lf.lfFaceName, "Nonexistent font");
2665 hfont = CreateFontIndirectA(&lf);
2666 hfont = SelectObject(hdc, hfont);
2667 GetTextFaceA(hdc, sizeof(buf), buf);
2668 todo_wine /* Wine uses Arial for all substitutions */
2669 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2670 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2671 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2672 "Got %s\n", buf);
2673 cs = GetTextCharset(hdc);
2674 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2675 DeleteObject(SelectObject(hdc, hfont));
2677 memset(&lf, 0, sizeof(lf));
2678 lf.lfHeight = -13;
2679 lf.lfWeight = FW_REGULAR;
2680 strcpy(lf.lfFaceName, "Nonexistent font");
2681 hfont = CreateFontIndirectA(&lf);
2682 hfont = SelectObject(hdc, hfont);
2683 GetTextFaceA(hdc, sizeof(buf), buf);
2684 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2685 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2686 cs = GetTextCharset(hdc);
2687 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2688 DeleteObject(SelectObject(hdc, hfont));
2690 memset(&lf, 0, sizeof(lf));
2691 lf.lfHeight = -13;
2692 lf.lfWeight = FW_DONTCARE;
2693 strcpy(lf.lfFaceName, "Times New Roman");
2694 hfont = CreateFontIndirectA(&lf);
2695 hfont = SelectObject(hdc, hfont);
2696 GetTextFaceA(hdc, sizeof(buf), buf);
2697 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2698 cs = GetTextCharset(hdc);
2699 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2700 DeleteObject(SelectObject(hdc, hfont));
2702 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2704 memset(&lf, 0, sizeof(lf));
2705 lf.lfHeight = -13;
2706 lf.lfWeight = FW_REGULAR;
2707 strcpy(lf.lfFaceName, font_subst[i].name);
2708 hfont = CreateFontIndirectA(&lf);
2709 hfont = SelectObject(hdc, hfont);
2710 cs = GetTextCharset(hdc);
2711 if (font_subst[i].charset == expected_cs)
2713 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2714 GetTextFaceA(hdc, sizeof(buf), buf);
2715 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2717 else
2719 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2720 GetTextFaceA(hdc, sizeof(buf), buf);
2721 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2722 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2724 DeleteObject(SelectObject(hdc, hfont));
2726 memset(&lf, 0, sizeof(lf));
2727 lf.lfHeight = -13;
2728 lf.lfWeight = FW_DONTCARE;
2729 strcpy(lf.lfFaceName, font_subst[i].name);
2730 hfont = CreateFontIndirectA(&lf);
2731 hfont = SelectObject(hdc, hfont);
2732 GetTextFaceA(hdc, sizeof(buf), buf);
2733 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2734 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2735 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2736 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2737 "got %s for font %s\n", buf, font_subst[i].name);
2738 cs = GetTextCharset(hdc);
2739 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2740 DeleteObject(SelectObject(hdc, hfont));
2743 ReleaseDC(0, hdc);
2746 static void test_GdiRealizationInfo(void)
2748 HDC hdc;
2749 DWORD info[4];
2750 BOOL r;
2751 HFONT hfont, hfont_old;
2752 LOGFONTA lf;
2754 if(!pGdiRealizationInfo)
2756 win_skip("GdiRealizationInfo not available\n");
2757 return;
2760 hdc = GetDC(0);
2762 memset(info, 0xcc, sizeof(info));
2763 r = pGdiRealizationInfo(hdc, info);
2764 ok(r != 0, "ret 0\n");
2765 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2766 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2768 if (!is_truetype_font_installed("Arial"))
2770 skip("skipping GdiRealizationInfo with truetype font\n");
2771 goto end;
2774 memset(&lf, 0, sizeof(lf));
2775 strcpy(lf.lfFaceName, "Arial");
2776 lf.lfHeight = 20;
2777 lf.lfWeight = FW_NORMAL;
2778 hfont = CreateFontIndirectA(&lf);
2779 hfont_old = SelectObject(hdc, hfont);
2781 memset(info, 0xcc, sizeof(info));
2782 r = pGdiRealizationInfo(hdc, info);
2783 ok(r != 0, "ret 0\n");
2784 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2785 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2787 DeleteObject(SelectObject(hdc, hfont_old));
2789 end:
2790 ReleaseDC(0, hdc);
2793 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2794 the nul in the count of characters copied when the face name buffer is not
2795 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2796 always includes it. */
2797 static void test_GetTextFace(void)
2799 static const char faceA[] = "Tahoma";
2800 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2801 LOGFONTA fA = {0};
2802 LOGFONTW fW = {0};
2803 char bufA[LF_FACESIZE];
2804 WCHAR bufW[LF_FACESIZE];
2805 HFONT f, g;
2806 HDC dc;
2807 int n;
2809 if(!is_font_installed("Tahoma"))
2811 skip("Tahoma is not installed so skipping this test\n");
2812 return;
2815 /* 'A' case. */
2816 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2817 f = CreateFontIndirectA(&fA);
2818 ok(f != NULL, "CreateFontIndirectA failed\n");
2820 dc = GetDC(NULL);
2821 g = SelectObject(dc, f);
2822 n = GetTextFaceA(dc, sizeof bufA, bufA);
2823 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2824 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2826 /* Play with the count arg. */
2827 bufA[0] = 'x';
2828 n = GetTextFaceA(dc, 0, bufA);
2829 ok(n == 0, "GetTextFaceA returned %d\n", n);
2830 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2832 bufA[0] = 'x';
2833 n = GetTextFaceA(dc, 1, bufA);
2834 ok(n == 0, "GetTextFaceA returned %d\n", n);
2835 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2837 bufA[0] = 'x'; bufA[1] = 'y';
2838 n = GetTextFaceA(dc, 2, bufA);
2839 ok(n == 1, "GetTextFaceA returned %d\n", n);
2840 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2842 n = GetTextFaceA(dc, 0, NULL);
2843 ok(n == sizeof faceA ||
2844 broken(n == 0), /* win98, winMe */
2845 "GetTextFaceA returned %d\n", n);
2847 DeleteObject(SelectObject(dc, g));
2848 ReleaseDC(NULL, dc);
2850 /* 'W' case. */
2851 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2852 SetLastError(0xdeadbeef);
2853 f = CreateFontIndirectW(&fW);
2854 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2856 win_skip("CreateFontIndirectW is not implemented\n");
2857 return;
2859 ok(f != NULL, "CreateFontIndirectW failed\n");
2861 dc = GetDC(NULL);
2862 g = SelectObject(dc, f);
2863 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2864 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2865 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2867 /* Play with the count arg. */
2868 bufW[0] = 'x';
2869 n = GetTextFaceW(dc, 0, bufW);
2870 ok(n == 0, "GetTextFaceW returned %d\n", n);
2871 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2873 bufW[0] = 'x';
2874 n = GetTextFaceW(dc, 1, bufW);
2875 ok(n == 1, "GetTextFaceW returned %d\n", n);
2876 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2878 bufW[0] = 'x'; bufW[1] = 'y';
2879 n = GetTextFaceW(dc, 2, bufW);
2880 ok(n == 2, "GetTextFaceW returned %d\n", n);
2881 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2883 n = GetTextFaceW(dc, 0, NULL);
2884 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2886 DeleteObject(SelectObject(dc, g));
2887 ReleaseDC(NULL, dc);
2890 static void test_orientation(void)
2892 static const char test_str[11] = "Test String";
2893 HDC hdc;
2894 LOGFONTA lf;
2895 HFONT hfont, old_hfont;
2896 SIZE size;
2898 if (!is_truetype_font_installed("Arial"))
2900 skip("Arial is not installed\n");
2901 return;
2904 hdc = CreateCompatibleDC(0);
2905 memset(&lf, 0, sizeof(lf));
2906 lstrcpyA(lf.lfFaceName, "Arial");
2907 lf.lfHeight = 72;
2908 lf.lfOrientation = lf.lfEscapement = 900;
2909 hfont = create_font("orientation", &lf);
2910 old_hfont = SelectObject(hdc, hfont);
2911 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2912 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2913 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2914 SelectObject(hdc, old_hfont);
2915 DeleteObject(hfont);
2916 DeleteDC(hdc);
2919 static void test_oemcharset(void)
2921 HDC hdc;
2922 LOGFONTA lf, clf;
2923 HFONT hfont, old_hfont;
2924 int charset;
2926 hdc = CreateCompatibleDC(0);
2927 ZeroMemory(&lf, sizeof(lf));
2928 lf.lfHeight = 12;
2929 lf.lfCharSet = OEM_CHARSET;
2930 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
2931 lstrcpyA(lf.lfFaceName, "Terminal");
2932 hfont = CreateFontIndirectA(&lf);
2933 old_hfont = SelectObject(hdc, hfont);
2934 charset = GetTextCharset(hdc);
2935 todo_wine
2936 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
2937 hfont = SelectObject(hdc, old_hfont);
2938 GetObjectA(hfont, sizeof(clf), &clf);
2939 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
2940 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
2941 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
2942 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
2943 DeleteObject(hfont);
2944 DeleteDC(hdc);
2947 static void test_GetGlyphOutline(void)
2949 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2950 HDC hdc;
2951 GLYPHMETRICS gm;
2952 LOGFONTA lf;
2953 HFONT hfont, old_hfont;
2954 INT ret;
2956 if (!is_truetype_font_installed("Tahoma"))
2958 skip("Tahoma is not installed\n");
2959 return;
2962 hdc = CreateCompatibleDC(0);
2963 memset(&lf, 0, sizeof(lf));
2964 lf.lfHeight = 72;
2965 lstrcpyA(lf.lfFaceName, "Tahoma");
2966 SetLastError(0xdeadbeef);
2967 hfont = CreateFontIndirectA(&lf);
2968 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2969 old_hfont = SelectObject(hdc, hfont);
2971 memset(&gm, 0, sizeof(gm));
2972 SetLastError(0xdeadbeef);
2973 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2974 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2976 memset(&gm, 0, sizeof(gm));
2977 SetLastError(0xdeadbeef);
2978 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2979 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2980 ok(GetLastError() == 0xdeadbeef ||
2981 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2982 "expected 0xdeadbeef, got %u\n", GetLastError());
2984 memset(&gm, 0, sizeof(gm));
2985 SetLastError(0xdeadbeef);
2986 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2987 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2988 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
2990 memset(&gm, 0, sizeof(gm));
2991 SetLastError(0xdeadbeef);
2992 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2993 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2995 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
2996 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2999 /* test for needed buffer size request on space char */
3000 memset(&gm, 0, sizeof(gm));
3001 SetLastError(0xdeadbeef);
3002 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3003 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3004 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3006 /* requesting buffer size for space char + error */
3007 memset(&gm, 0, sizeof(gm));
3008 SetLastError(0xdeadbeef);
3009 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3010 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3012 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3013 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3016 SelectObject(hdc, old_hfont);
3017 DeleteObject(hfont);
3018 DeleteDC(hdc);
3021 /* bug #9995: there is a limit to the character width that can be specified */
3022 static void test_GetTextMetrics2(const char *fontname, int font_height)
3024 HFONT of, hf;
3025 HDC hdc;
3026 TEXTMETRICA tm;
3027 BOOL ret;
3028 int ave_width, height, width, ratio, scale;
3030 if (!is_truetype_font_installed( fontname)) {
3031 skip("%s is not installed\n", fontname);
3032 return;
3034 hdc = CreateCompatibleDC(0);
3035 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3036 /* select width = 0 */
3037 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3038 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3039 DEFAULT_QUALITY, VARIABLE_PITCH,
3040 fontname);
3041 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3042 of = SelectObject( hdc, hf);
3043 ret = GetTextMetricsA( hdc, &tm);
3044 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3045 height = tm.tmHeight;
3046 ave_width = tm.tmAveCharWidth;
3047 SelectObject( hdc, of);
3048 DeleteObject( hf);
3050 trace("height %d, ave width %d\n", height, ave_width);
3052 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3054 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3055 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3056 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3057 ok(hf != 0, "CreateFont failed\n");
3058 of = SelectObject(hdc, hf);
3059 ret = GetTextMetrics(hdc, &tm);
3060 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3061 SelectObject(hdc, of);
3062 DeleteObject(hf);
3064 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3065 break;
3068 DeleteDC(hdc);
3070 ratio = width / height;
3071 scale = width / ave_width;
3073 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3074 width, height, ratio, width, ave_width, scale);
3076 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3079 static void test_CreateFontIndirect(void)
3081 LOGFONTA lf, getobj_lf;
3082 int ret, i;
3083 HFONT hfont;
3084 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3086 memset(&lf, 0, sizeof(lf));
3087 lf.lfCharSet = ANSI_CHARSET;
3088 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3089 lf.lfHeight = 16;
3090 lf.lfWidth = 16;
3091 lf.lfQuality = DEFAULT_QUALITY;
3092 lf.lfItalic = FALSE;
3093 lf.lfWeight = FW_DONTCARE;
3095 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3097 lstrcpyA(lf.lfFaceName, TestName[i]);
3098 hfont = CreateFontIndirectA(&lf);
3099 ok(hfont != 0, "CreateFontIndirectA failed\n");
3100 SetLastError(0xdeadbeef);
3101 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3102 ok(ret, "GetObject failed: %d\n", GetLastError());
3103 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3104 ok(lf.lfWeight == getobj_lf.lfWeight ||
3105 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3106 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3107 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3108 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3109 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3110 DeleteObject(hfont);
3114 static void test_CreateFontIndirectEx(void)
3116 ENUMLOGFONTEXDVA lfex;
3117 HFONT hfont;
3119 if (!pCreateFontIndirectExA)
3121 win_skip("CreateFontIndirectExA is not available\n");
3122 return;
3125 if (!is_truetype_font_installed("Arial"))
3127 skip("Arial is not installed\n");
3128 return;
3131 SetLastError(0xdeadbeef);
3132 hfont = pCreateFontIndirectExA(NULL);
3133 ok(hfont == NULL, "got %p\n", hfont);
3134 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3136 memset(&lfex, 0, sizeof(lfex));
3137 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3138 hfont = pCreateFontIndirectExA(&lfex);
3139 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3140 if (hfont)
3141 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3142 DeleteObject(hfont);
3145 START_TEST(font)
3147 init();
3149 test_logfont();
3150 test_bitmap_font();
3151 test_outline_font();
3152 test_bitmap_font_metrics();
3153 test_GdiGetCharDimensions();
3154 test_GetCharABCWidths();
3155 test_text_extents();
3156 test_GetGlyphIndices();
3157 test_GetKerningPairs();
3158 test_GetOutlineTextMetrics();
3159 test_SetTextJustification();
3160 test_font_charset();
3161 test_GetFontUnicodeRanges();
3162 test_nonexistent_font();
3163 test_orientation();
3164 test_height_selection();
3166 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3167 * I'd like to avoid them in this test.
3169 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3170 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3171 if (is_truetype_font_installed("Arial Black") &&
3172 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3174 test_EnumFontFamilies("", ANSI_CHARSET);
3175 test_EnumFontFamilies("", SYMBOL_CHARSET);
3176 test_EnumFontFamilies("", DEFAULT_CHARSET);
3178 else
3179 skip("Arial Black or Symbol/Wingdings is not installed\n");
3180 test_GetTextMetrics();
3181 test_GdiRealizationInfo();
3182 test_GetTextFace();
3183 test_GetGlyphOutline();
3184 test_GetTextMetrics2("Tahoma", -11);
3185 test_GetTextMetrics2("Tahoma", -55);
3186 test_GetTextMetrics2("Tahoma", -110);
3187 test_GetTextMetrics2("Arial", -11);
3188 test_GetTextMetrics2("Arial", -55);
3189 test_GetTextMetrics2("Arial", -110);
3190 test_CreateFontIndirect();
3191 test_CreateFontIndirectEx();
3192 test_oemcharset();