2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 #define near_match(a, b) (abs((a) - (b)) <= 6)
34 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
36 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
37 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
38 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
39 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
40 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
41 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
42 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
44 static HMODULE hgdi32 = 0;
46 static void init(void)
48 hgdi32 = GetModuleHandleA("gdi32.dll");
50 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
51 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
52 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
53 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
54 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
55 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
56 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
59 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
61 if (type != TRUETYPE_FONTTYPE) return 1;
66 static BOOL is_truetype_font_installed(const char *name)
71 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
78 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
83 static BOOL is_font_installed(const char *name)
88 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
95 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
103 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
104 /* NT4 tries to be clever and only returns the minimum length */
105 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
107 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
108 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
109 ok(lf->lfHeight == getobj_lf.lfHeight ||
110 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
111 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
112 ok(lf->lfWidth == getobj_lf.lfWidth ||
113 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
114 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
115 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
116 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
117 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
118 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
119 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
120 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
121 ok(lf->lfWeight == getobj_lf.lfWeight ||
122 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
123 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
124 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
125 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
126 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
127 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
128 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
129 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
130 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
131 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
132 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
133 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
134 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
137 static HFONT create_font(const char* test, const LOGFONTA* lf)
139 HFONT hfont = CreateFontIndirectA(lf);
140 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
142 check_font(test, lf, hfont);
146 static void test_logfont(void)
151 memset(&lf, 0, sizeof lf);
153 lf.lfCharSet = ANSI_CHARSET;
154 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
155 lf.lfWeight = FW_DONTCARE;
158 lf.lfQuality = DEFAULT_QUALITY;
160 lstrcpyA(lf.lfFaceName, "Arial");
161 hfont = create_font("Arial", &lf);
164 memset(&lf, 'A', sizeof(lf));
165 hfont = CreateFontIndirectA(&lf);
166 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
168 lf.lfFaceName[LF_FACESIZE - 1] = 0;
169 check_font("AAA...", &lf, hfont);
173 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
175 if (type & RASTER_FONTTYPE)
177 LOGFONT *lf = (LOGFONT *)lParam;
179 return 0; /* stop enumeration */
182 return 1; /* continue enumeration */
185 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
187 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
188 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
189 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
190 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
191 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
192 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
193 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
194 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
195 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
196 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
197 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
198 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
199 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
200 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
201 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
202 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
203 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
204 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
205 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
206 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
209 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
210 LONG lfWidth, const char *test_str,
211 INT test_str_len, const TEXTMETRICA *tm_orig,
212 const SIZE *size_orig, INT width_of_A_orig,
213 INT scale_x, INT scale_y)
216 OUTLINETEXTMETRIC otm;
219 INT width_of_A, cx, cy;
225 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
227 GetObjectA(hfont, sizeof(lf), &lf);
229 if (GetOutlineTextMetricsA(hdc, 0, NULL))
231 otm.otmSize = sizeof(otm) / 2;
232 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
233 ok(ret == sizeof(otm)/2 /* XP */ ||
234 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
236 memset(&otm, 0x1, sizeof(otm));
237 otm.otmSize = sizeof(otm);
238 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
239 ok(ret == sizeof(otm) /* XP */ ||
240 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
242 memset(&tm, 0x2, sizeof(tm));
243 ret = GetTextMetricsA(hdc, &tm);
244 ok(ret, "GetTextMetricsA failed\n");
245 /* the structure size is aligned */
246 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
248 ok(0, "tm != otm\n");
249 compare_tm(&tm, &otm.otmTextMetrics);
252 tm = otm.otmTextMetrics;
253 if (0) /* these metrics are scaled too, but with rounding errors */
255 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
256 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
258 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
259 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
260 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
261 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
262 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
263 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
267 ret = GetTextMetricsA(hdc, &tm);
268 ok(ret, "GetTextMetricsA failed\n");
271 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
272 cy = tm.tmHeight / tm_orig->tmHeight;
273 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
274 lfHeight, scale_x, scale_y, cx, cy);
275 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
276 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
277 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
278 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
279 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
281 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
285 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
288 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
290 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
292 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
293 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
295 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
297 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
300 /* Test how GDI scales bitmap font metrics */
301 static void test_bitmap_font(void)
303 static const char test_str[11] = "Test String";
306 HFONT hfont, old_hfont;
309 INT ret, i, width_orig, height_orig, scale, lfWidth;
313 /* "System" has only 1 pixel size defined, otherwise the test breaks */
314 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
318 trace("no bitmap fonts were found, skipping the test\n");
322 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
324 height_orig = bitmap_lf.lfHeight;
325 lfWidth = bitmap_lf.lfWidth;
327 hfont = create_font("bitmap", &bitmap_lf);
328 old_hfont = SelectObject(hdc, hfont);
329 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
330 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
331 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
332 SelectObject(hdc, old_hfont);
335 bitmap_lf.lfHeight = 0;
336 bitmap_lf.lfWidth = 4;
337 hfont = create_font("bitmap", &bitmap_lf);
338 old_hfont = SelectObject(hdc, hfont);
339 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
340 SelectObject(hdc, old_hfont);
343 bitmap_lf.lfHeight = height_orig;
344 bitmap_lf.lfWidth = lfWidth;
346 /* test fractional scaling */
347 for (i = 1; i <= height_orig * 3; i++)
351 bitmap_lf.lfHeight = i;
352 hfont = create_font("fractional", &bitmap_lf);
353 scale = (i + height_orig - 1) / height_orig;
354 nearest_height = scale * height_orig;
355 /* XP allows not more than 10% deviation */
356 if (scale > 1 && nearest_height - i > nearest_height / 10) scale--;
357 old_hfont = SelectObject(hdc, hfont);
358 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
359 SelectObject(hdc, old_hfont);
363 /* test integer scaling 3x2 */
364 bitmap_lf.lfHeight = height_orig * 2;
365 bitmap_lf.lfWidth *= 3;
366 hfont = create_font("3x2", &bitmap_lf);
367 old_hfont = SelectObject(hdc, hfont);
368 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
369 SelectObject(hdc, old_hfont);
372 /* test integer scaling 3x3 */
373 bitmap_lf.lfHeight = height_orig * 3;
374 bitmap_lf.lfWidth = 0;
375 hfont = create_font("3x3", &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, 3);
378 SelectObject(hdc, old_hfont);
384 /* Test how GDI scales outline font metrics */
385 static void test_outline_font(void)
387 static const char test_str[11] = "Test String";
390 HFONT hfont, old_hfont, old_hfont_2;
391 OUTLINETEXTMETRICA otm;
393 INT width_orig, height_orig, lfWidth;
396 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
397 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
401 if (!is_truetype_font_installed("Arial"))
403 skip("Arial is not installed\n");
407 hdc = CreateCompatibleDC(0);
409 memset(&lf, 0, sizeof(lf));
410 strcpy(lf.lfFaceName, "Arial");
412 hfont = create_font("outline", &lf);
413 old_hfont = SelectObject(hdc, hfont);
414 otm.otmSize = sizeof(otm);
415 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
416 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
417 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
419 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
420 SelectObject(hdc, old_hfont);
423 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
424 lf.lfHeight = otm.otmEMSquare;
425 lf.lfHeight = -lf.lfHeight;
426 hfont = create_font("outline", &lf);
427 old_hfont = SelectObject(hdc, hfont);
428 otm.otmSize = sizeof(otm);
429 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
430 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
431 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
432 SelectObject(hdc, old_hfont);
435 height_orig = otm.otmTextMetrics.tmHeight;
436 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
438 /* test integer scaling 3x2 */
439 lf.lfHeight = height_orig * 2;
440 lf.lfWidth = lfWidth * 3;
441 hfont = create_font("3x2", &lf);
442 old_hfont = SelectObject(hdc, hfont);
443 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
444 SelectObject(hdc, old_hfont);
447 /* test integer scaling 3x3 */
448 lf.lfHeight = height_orig * 3;
449 lf.lfWidth = lfWidth * 3;
450 hfont = create_font("3x3", &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, 3);
453 SelectObject(hdc, old_hfont);
456 /* test integer scaling 1x1 */
457 lf.lfHeight = height_orig * 1;
458 lf.lfWidth = lfWidth * 1;
459 hfont = create_font("1x1", &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, 1, 1);
462 SelectObject(hdc, old_hfont);
465 /* test integer scaling 1x1 */
466 lf.lfHeight = height_orig;
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);
472 /* with an identity matrix */
473 memset(&gm, 0, sizeof(gm));
474 SetLastError(0xdeadbeef);
475 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
476 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
477 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
478 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
479 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
480 /* with a custom matrix */
481 memset(&gm, 0, sizeof(gm));
482 SetLastError(0xdeadbeef);
483 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
484 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
485 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
486 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
487 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
489 /* Test that changing the DC transformation affects only the font
490 * selected on this DC and doesn't affect the same font selected on
493 hdc_2 = CreateCompatibleDC(0);
494 old_hfont_2 = SelectObject(hdc_2, hfont);
495 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
497 SetMapMode(hdc, MM_ANISOTROPIC);
499 /* font metrics on another DC should be unchanged */
500 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
502 /* test restrictions of compatibility mode GM_COMPATIBLE */
503 /* part 1: rescaling only X should not change font scaling on screen.
504 So compressing the X axis by 2 is not done, and this
505 appears as X scaling of 2 that no one requested. */
506 SetWindowExtEx(hdc, 100, 100, NULL);
507 SetViewportExtEx(hdc, 50, 100, NULL);
508 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
509 /* font metrics on another DC should be unchanged */
510 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
512 /* part 2: rescaling only Y should change font scaling.
513 As also X is scaled by a factor of 2, but this is not
514 requested by the DC transformation, we get a scaling factor
515 of 2 in the X coordinate. */
516 SetViewportExtEx(hdc, 100, 200, 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 /* restore scaling */
522 SetMapMode(hdc, MM_TEXT);
524 /* font metrics on another DC should be unchanged */
525 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
527 SelectObject(hdc_2, old_hfont_2);
530 if (!SetGraphicsMode(hdc, GM_ADVANCED))
532 SelectObject(hdc, old_hfont);
535 skip("GM_ADVANCED is not supported on this platform\n");
546 SetLastError(0xdeadbeef);
547 ret = SetWorldTransform(hdc, &xform);
548 ok(ret, "SetWorldTransform error %u\n", GetLastError());
550 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
552 /* with an identity matrix */
553 memset(&gm, 0, sizeof(gm));
554 SetLastError(0xdeadbeef);
555 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
556 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
557 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
558 pt.x = width_orig; pt.y = 0;
560 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
561 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
562 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
563 /* with a custom matrix */
564 memset(&gm, 0, sizeof(gm));
565 SetLastError(0xdeadbeef);
566 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
567 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
568 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
569 pt.x = width_orig; pt.y = 0;
571 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
572 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
573 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
575 SetLastError(0xdeadbeef);
576 ret = SetMapMode(hdc, MM_LOMETRIC);
577 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
579 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
581 /* with an identity matrix */
582 memset(&gm, 0, sizeof(gm));
583 SetLastError(0xdeadbeef);
584 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
585 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
586 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
587 pt.x = width_orig; pt.y = 0;
589 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
591 /* with a custom matrix */
592 memset(&gm, 0, sizeof(gm));
593 SetLastError(0xdeadbeef);
594 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
595 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
596 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
597 pt.x = width_orig; pt.y = 0;
599 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
600 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
602 SetLastError(0xdeadbeef);
603 ret = SetMapMode(hdc, MM_TEXT);
604 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
606 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
608 /* with an identity matrix */
609 memset(&gm, 0, sizeof(gm));
610 SetLastError(0xdeadbeef);
611 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
612 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
613 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
614 pt.x = width_orig; pt.y = 0;
616 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
617 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
618 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
619 /* with a custom matrix */
620 memset(&gm, 0, sizeof(gm));
621 SetLastError(0xdeadbeef);
622 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
623 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
624 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
625 pt.x = width_orig; pt.y = 0;
627 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
628 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
629 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
631 SelectObject(hdc, old_hfont);
636 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
638 LOGFONT *lf = (LOGFONT *)lParam;
640 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
643 return 0; /* stop enumeration */
645 return 1; /* continue enumeration */
648 static void test_bitmap_font_metrics(void)
650 static const struct font_data
652 const char face_name[LF_FACESIZE];
653 int weight, height, ascent, descent, int_leading, ext_leading;
654 int ave_char_width, max_char_width;
658 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
659 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
660 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
661 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
662 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
663 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
664 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
665 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
666 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
667 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
668 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
669 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
670 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
671 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
672 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
673 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
674 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
675 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
676 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
677 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
678 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
679 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
680 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
681 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
682 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
683 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
684 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
685 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
686 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
687 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
688 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
689 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
690 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
692 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
693 * require a new system.sfd for that font
695 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
696 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
697 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
698 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
699 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
700 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
701 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
702 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
703 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
704 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
705 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
706 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
707 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
708 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
709 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
710 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
711 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
712 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
713 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
714 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
715 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
717 /* FIXME: add "Terminal" */
721 HFONT hfont, old_hfont;
725 hdc = CreateCompatibleDC(0);
728 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
732 memset(&lf, 0, sizeof(lf));
734 lf.lfHeight = fd[i].height;
735 strcpy(lf.lfFaceName, fd[i].face_name);
737 for(bit = 0; bit < 32; bit++)
744 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
745 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
747 lf.lfCharSet = csi.ciCharset;
748 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
751 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
753 hfont = create_font(lf.lfFaceName, &lf);
754 old_hfont = SelectObject(hdc, hfont);
755 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
757 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);
758 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);
759 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);
760 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);
761 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);
762 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);
763 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);
765 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
766 that make the max width bigger */
767 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
768 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);
770 SelectObject(hdc, old_hfont);
778 static void test_GdiGetCharDimensions(void)
784 LONG avgwidth, height;
785 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
787 if (!pGdiGetCharDimensions)
789 skip("GdiGetCharDimensions not available on this platform\n");
793 hdc = CreateCompatibleDC(NULL);
795 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
796 avgwidth = ((size.cx / 26) + 1) / 2;
798 ret = pGdiGetCharDimensions(hdc, &tm, &height);
799 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
800 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
802 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
803 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
805 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
806 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
809 ret = pGdiGetCharDimensions(hdc, NULL, &height);
810 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
811 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
816 static void test_GetCharABCWidths(void)
818 static const WCHAR str[] = {'a',0};
827 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
829 skip("GetCharABCWidthsW/I not available on this platform\n");
833 memset(&lf, 0, sizeof(lf));
834 strcpy(lf.lfFaceName, "System");
837 hfont = CreateFontIndirectA(&lf);
839 hfont = SelectObject(hdc, hfont);
841 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
842 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
844 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
845 ok(!ret, "GetCharABCWidthsI should have failed\n");
847 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
848 ok(!ret, "GetCharABCWidthsI should have failed\n");
850 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
851 ok(ret, "GetCharABCWidthsI should have succeeded\n");
853 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
854 ok(!ret, "GetCharABCWidthsW should have failed\n");
856 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
857 ok(!ret, "GetCharABCWidthsW should have failed\n");
859 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
860 ok(!ret, "GetCharABCWidthsW should have failed\n");
862 hfont = SelectObject(hdc, hfont);
864 ReleaseDC(NULL, hdc);
867 static void test_text_extents(void)
869 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
871 INT i, len, fit1, fit2;
879 memset(&lf, 0, sizeof(lf));
880 strcpy(lf.lfFaceName, "Arial");
883 hfont = CreateFontIndirectA(&lf);
885 hfont = SelectObject(hdc, hfont);
886 GetTextMetricsA(hdc, &tm);
887 GetTextExtentPointA(hdc, "o", 1, &sz);
888 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
890 SetLastError(0xdeadbeef);
891 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
892 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
894 skip("Skipping remainder of text extents test on a Win9x platform\n");
895 hfont = SelectObject(hdc, hfont);
902 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
903 extents[0] = 1; /* So that the increasing sequence test will fail
904 if the extents array is untouched. */
905 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
906 GetTextExtentPointW(hdc, wt, len, &sz2);
908 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
909 /* Because of the '\n' in the string GetTextExtentExPoint and
910 GetTextExtentPoint return different widths under Win2k, but
911 under WinXP they return the same width. So we don't test that
914 for (i = 1; i < len; ++i)
915 ok(extents[i-1] <= extents[i],
916 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
918 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
919 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
920 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
921 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
922 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
923 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
924 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
925 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
926 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
927 ok(extents[0] == extents[2] && extents[1] == extents[3],
928 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
929 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
930 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
931 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
932 HeapFree(GetProcessHeap(), 0, extents);
934 hfont = SelectObject(hdc, hfont);
936 ReleaseDC(NULL, hdc);
939 static void test_GetGlyphIndices(void)
946 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
947 WORD glyphs[(sizeof(testtext)/2)-1];
951 if (!pGetGlyphIndicesW) {
952 skip("GetGlyphIndicesW not available on platform\n");
958 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
959 flags |= GGI_MARK_NONEXISTING_GLYPHS;
960 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
961 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
962 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
964 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
965 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
966 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
967 textm.tmDefaultChar, glyphs[4]);
969 if(!is_font_installed("Tahoma"))
971 skip("Tahoma is not installed so skipping this test\n");
974 memset(&lf, 0, sizeof(lf));
975 strcpy(lf.lfFaceName, "Tahoma");
978 hfont = CreateFontIndirectA(&lf);
979 hOldFont = SelectObject(hdc, hfont);
980 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
981 flags |= GGI_MARK_NONEXISTING_GLYPHS;
982 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
983 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
984 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
986 testtext[0] = textm.tmDefaultChar;
987 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
988 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
989 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
990 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
991 DeleteObject(SelectObject(hdc, hOldFont));
994 static void test_GetKerningPairs(void)
996 static const struct kerning_data
998 const char face_name[LF_FACESIZE];
1000 /* some interesting fields from OUTLINETEXTMETRIC */
1001 LONG tmHeight, tmAscent, tmDescent;
1006 UINT otmsCapEmHeight;
1011 UINT otmusMinimumPPEM;
1012 /* small subset of kerning pairs to test */
1013 DWORD total_kern_pairs;
1014 const KERNINGPAIR kern_pair[26];
1017 {"Arial", 12, 12, 9, 3,
1018 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1021 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1022 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1023 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1024 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1025 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1026 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1027 {933,970,+1},{933,972,-1}
1030 {"Arial", -34, 39, 32, 7,
1031 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1034 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1035 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1036 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1037 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1038 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1039 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1040 {933,970,+2},{933,972,-3}
1043 { "Arial", 120, 120, 97, 23,
1044 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1047 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1048 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1049 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1050 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1051 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1052 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1053 {933,970,+6},{933,972,-10}
1056 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1057 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1058 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1061 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1062 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1063 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1064 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1065 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1066 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1067 {933,970,+54},{933,972,-83}
1073 HFONT hfont, hfont_old;
1074 KERNINGPAIR *kern_pair;
1076 DWORD total_kern_pairs, ret, i, n, matches;
1080 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1081 * which may render this test unusable, so we're trying to avoid that.
1083 SetLastError(0xdeadbeef);
1084 GetKerningPairsW(hdc, 0, NULL);
1085 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1087 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1092 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1094 OUTLINETEXTMETRICW otm;
1096 if (!is_font_installed(kd[i].face_name))
1098 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1102 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1104 memset(&lf, 0, sizeof(lf));
1105 strcpy(lf.lfFaceName, kd[i].face_name);
1106 lf.lfHeight = kd[i].height;
1107 hfont = CreateFontIndirect(&lf);
1110 hfont_old = SelectObject(hdc, hfont);
1112 SetLastError(0xdeadbeef);
1113 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1114 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1116 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1117 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1118 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1119 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1120 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1121 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1123 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1124 kd[i].otmEMSquare, otm.otmEMSquare);
1125 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1126 kd[i].otmAscent, otm.otmAscent);
1127 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1128 kd[i].otmDescent, otm.otmDescent);
1129 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1130 kd[i].otmLineGap, otm.otmLineGap);
1131 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1132 kd[i].otmMacDescent, otm.otmMacDescent);
1134 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1135 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1136 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1137 kd[i].otmsXHeight, otm.otmsXHeight);
1138 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1139 kd[i].otmMacAscent, otm.otmMacAscent);
1140 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1141 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1142 kd[i].otmMacLineGap, otm.otmMacLineGap);
1143 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1144 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1147 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1148 trace("total_kern_pairs %u\n", total_kern_pairs);
1149 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1151 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1152 SetLastError(0xdeadbeef);
1153 ret = GetKerningPairsW(hdc, 0, kern_pair);
1154 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1155 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1156 ok(ret == 0, "got %lu, expected 0\n", ret);
1159 ret = GetKerningPairsW(hdc, 100, NULL);
1160 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1162 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1163 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1165 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1166 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1170 for (n = 0; n < ret; n++)
1174 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1175 trace("{'%c','%c',%d},\n",
1176 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1178 for (j = 0; j < kd[i].total_kern_pairs; j++)
1180 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1181 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1183 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1184 "pair %d:%d got %d, expected %d\n",
1185 kern_pair[n].wFirst, kern_pair[n].wSecond,
1186 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1192 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1193 matches, kd[i].total_kern_pairs);
1195 HeapFree(GetProcessHeap(), 0, kern_pair);
1197 SelectObject(hdc, hfont_old);
1198 DeleteObject(hfont);
1204 static void test_GetOutlineTextMetrics(void)
1206 OUTLINETEXTMETRIC *otm;
1208 HFONT hfont, hfont_old;
1210 DWORD ret, otm_size;
1213 if (!is_font_installed("Arial"))
1215 skip("Arial is not installed\n");
1221 memset(&lf, 0, sizeof(lf));
1222 strcpy(lf.lfFaceName, "Arial");
1224 lf.lfWeight = FW_NORMAL;
1225 lf.lfPitchAndFamily = DEFAULT_PITCH;
1226 lf.lfQuality = PROOF_QUALITY;
1227 hfont = CreateFontIndirect(&lf);
1230 hfont_old = SelectObject(hdc, hfont);
1231 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1232 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1234 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1236 memset(otm, 0xAA, otm_size);
1237 SetLastError(0xdeadbeef);
1238 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1239 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1240 ok(ret == 1 /* Win9x */ ||
1241 ret == otm->otmSize /* XP*/,
1242 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1243 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1245 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1246 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1247 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1248 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1251 memset(otm, 0xAA, otm_size);
1252 SetLastError(0xdeadbeef);
1253 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1254 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1255 ok(ret == 1 /* Win9x */ ||
1256 ret == otm->otmSize /* XP*/,
1257 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1258 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1260 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1261 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1262 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1263 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1266 /* ask about truncated data */
1267 memset(otm, 0xAA, otm_size);
1268 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1269 SetLastError(0xdeadbeef);
1270 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1271 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1272 ok(ret == 1 /* Win9x */ ||
1273 ret == otm->otmSize /* XP*/,
1274 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1275 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1277 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1278 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1279 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1281 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1283 HeapFree(GetProcessHeap(), 0, otm);
1285 SelectObject(hdc, hfont_old);
1286 DeleteObject(hfont);
1291 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1295 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1296 areaWidth = clientArea->right - clientArea->left,
1298 BOOL lastExtent = FALSE;
1299 PSTR pFirstChar, pLastChar;
1305 int GetTextExtentExPointWWidth;
1308 GetTextMetricsA(hdc, &tm);
1309 y = clientArea->top;
1312 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1318 /* if not at the end of the string, ... */
1319 if (*str == '\0') break;
1320 /* ... add the next word to the current extent */
1321 while (*str != '\0' && *str++ != tm.tmBreakChar);
1323 SetTextJustification(hdc, 0, 0);
1324 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1325 } while ((int) size.cx < areaWidth);
1327 /* ignore trailing break chars */
1329 while (*(pLastChar - 1) == tm.tmBreakChar)
1335 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1337 SetTextJustification(hdc, 0, 0);
1338 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1340 /* do not justify the last extent */
1341 if (*str != '\0' && breakCount > 0)
1343 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1344 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1345 justifiedWidth = size.cx;
1347 else lastExtent = TRUE;
1349 x = clientArea->left;
1351 /* catch errors and report them */
1352 if (!lastExtent && (justifiedWidth != areaWidth))
1354 memset(error[nErrors].extent, 0, 100);
1355 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1356 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1362 } while (*str && y < clientArea->bottom);
1364 for (e = 0; e < nErrors; e++)
1366 /* The width returned by GetTextExtentPoint32() is exactly the same
1367 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1368 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1369 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1370 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1374 static void test_SetTextJustification(void)
1381 static char testText[] =
1382 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1383 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1384 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1385 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1386 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1387 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1388 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1390 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1391 GetClientRect( hwnd, &clientArea );
1392 hdc = GetDC( hwnd );
1394 memset(&lf, 0, sizeof lf);
1395 lf.lfCharSet = ANSI_CHARSET;
1396 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1397 lf.lfWeight = FW_DONTCARE;
1399 lf.lfQuality = DEFAULT_QUALITY;
1400 lstrcpyA(lf.lfFaceName, "Times New Roman");
1401 hfont = create_font("Times New Roman", &lf);
1402 SelectObject(hdc, hfont);
1404 testJustification(hdc, testText, &clientArea);
1406 DeleteObject(hfont);
1407 ReleaseDC(hwnd, hdc);
1408 DestroyWindow(hwnd);
1411 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1415 HFONT hfont, hfont_old;
1422 assert(count <= 128);
1424 memset(&lf, 0, sizeof(lf));
1426 lf.lfCharSet = charset;
1428 lstrcpyA(lf.lfFaceName, "Arial");
1429 SetLastError(0xdeadbeef);
1430 hfont = CreateFontIndirectA(&lf);
1431 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1434 hfont_old = SelectObject(hdc, hfont);
1436 cs = GetTextCharsetInfo(hdc, &fs, 0);
1437 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1439 SetLastError(0xdeadbeef);
1440 ret = GetTextFaceA(hdc, sizeof(name), name);
1441 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1443 if (charset == SYMBOL_CHARSET)
1445 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1446 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1450 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1451 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1454 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1456 trace("Can't find codepage for charset %d\n", cs);
1460 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1465 WCHAR unicode_buf[128];
1467 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1469 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1471 SetLastError(0xdeadbeef);
1472 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1473 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1479 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1481 SetLastError(0xdeadbeef);
1482 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1483 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1486 SelectObject(hdc, hfont_old);
1487 DeleteObject(hfont);
1494 static void test_font_charset(void)
1496 static struct charset_data
1500 WORD font_idxA[128], font_idxW[128];
1503 { ANSI_CHARSET, 1252 },
1504 { RUSSIAN_CHARSET, 1251 },
1505 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1509 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1511 skip("Skipping the font charset test on a Win9x platform\n");
1515 if (!is_font_installed("Arial"))
1517 skip("Arial is not installed\n");
1521 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1523 if (cd[i].charset == SYMBOL_CHARSET)
1525 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1527 skip("Symbol or Wingdings is not installed\n");
1531 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1532 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1533 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1536 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1539 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1540 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1543 skip("Symbol or Wingdings is not installed\n");
1546 static void test_GetFontUnicodeRanges(void)
1550 HFONT hfont, hfont_old;
1554 if (!pGetFontUnicodeRanges)
1556 skip("GetFontUnicodeRanges not available before W2K\n");
1560 memset(&lf, 0, sizeof(lf));
1561 lstrcpyA(lf.lfFaceName, "Arial");
1562 hfont = create_font("Arial", &lf);
1565 hfont_old = SelectObject(hdc, hfont);
1567 size = pGetFontUnicodeRanges(NULL, NULL);
1568 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1570 size = pGetFontUnicodeRanges(hdc, NULL);
1571 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1573 gs = HeapAlloc(GetProcessHeap(), 0, size);
1575 size = pGetFontUnicodeRanges(hdc, gs);
1576 ok(size, "GetFontUnicodeRanges failed\n");
1578 for (i = 0; i < gs->cRanges; i++)
1579 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1581 trace("found %u ranges\n", gs->cRanges);
1583 HeapFree(GetProcessHeap(), 0, gs);
1585 SelectObject(hdc, hfont_old);
1586 DeleteObject(hfont);
1587 ReleaseDC(NULL, hdc);
1590 #define MAX_ENUM_FONTS 4096
1592 struct enum_font_data
1595 LOGFONT lf[MAX_ENUM_FONTS];
1598 struct enum_font_dataW
1601 LOGFONTW lf[MAX_ENUM_FONTS];
1604 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1606 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1608 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1610 if (type != TRUETYPE_FONTTYPE) return 1;
1612 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1613 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1615 if (efd->total < MAX_ENUM_FONTS)
1616 efd->lf[efd->total++] = *lf;
1618 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1623 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1625 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1627 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1629 if (type != TRUETYPE_FONTTYPE) return 1;
1631 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1632 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1634 if (efd->total < MAX_ENUM_FONTS)
1635 efd->lf[efd->total++] = *lf;
1637 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1642 static void get_charset_stats(struct enum_font_data *efd,
1643 int *ansi_charset, int *symbol_charset,
1644 int *russian_charset)
1649 *symbol_charset = 0;
1650 *russian_charset = 0;
1652 for (i = 0; i < efd->total; i++)
1654 switch (efd->lf[i].lfCharSet)
1659 case SYMBOL_CHARSET:
1660 (*symbol_charset)++;
1662 case RUSSIAN_CHARSET:
1663 (*russian_charset)++;
1669 static void get_charset_statsW(struct enum_font_dataW *efd,
1670 int *ansi_charset, int *symbol_charset,
1671 int *russian_charset)
1676 *symbol_charset = 0;
1677 *russian_charset = 0;
1679 for (i = 0; i < efd->total; i++)
1681 switch (efd->lf[i].lfCharSet)
1686 case SYMBOL_CHARSET:
1687 (*symbol_charset)++;
1689 case RUSSIAN_CHARSET:
1690 (*russian_charset)++;
1696 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1698 struct enum_font_data efd;
1699 struct enum_font_dataW efdw;
1702 int i, ret, ansi_charset, symbol_charset, russian_charset;
1704 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1706 if (*font_name && !is_truetype_font_installed(font_name))
1708 skip("%s is not installed\n", font_name);
1714 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1715 * while EnumFontFamiliesEx doesn't.
1717 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1720 * Use EnumFontFamiliesW since win98 crashes when the
1721 * second parameter is NULL using EnumFontFamilies
1724 SetLastError(0xdeadbeef);
1725 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1726 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1729 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1730 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1731 ansi_charset, symbol_charset, russian_charset);
1732 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1733 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1734 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1735 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1739 SetLastError(0xdeadbeef);
1740 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1741 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1744 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1745 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1746 ansi_charset, symbol_charset, russian_charset);
1747 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1748 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1749 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1750 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1755 SetLastError(0xdeadbeef);
1756 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1757 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1758 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1759 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1760 ansi_charset, symbol_charset, russian_charset,
1761 *font_name ? font_name : "<empty>");
1763 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1765 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1766 for (i = 0; i < efd.total; i++)
1768 /* FIXME: remove completely once Wine is fixed */
1769 if (efd.lf[i].lfCharSet != font_charset)
1772 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1775 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1776 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1777 font_name, efd.lf[i].lfFaceName);
1780 memset(&lf, 0, sizeof(lf));
1781 lf.lfCharSet = ANSI_CHARSET;
1782 lstrcpy(lf.lfFaceName, font_name);
1784 SetLastError(0xdeadbeef);
1785 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1786 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1787 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1788 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1789 ansi_charset, symbol_charset, russian_charset,
1790 *font_name ? font_name : "<empty>");
1791 if (font_charset == SYMBOL_CHARSET)
1794 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1796 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1800 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1801 for (i = 0; i < efd.total; i++)
1803 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1805 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1806 font_name, efd.lf[i].lfFaceName);
1810 /* DEFAULT_CHARSET should enumerate all available charsets */
1811 memset(&lf, 0, sizeof(lf));
1812 lf.lfCharSet = DEFAULT_CHARSET;
1813 lstrcpy(lf.lfFaceName, font_name);
1815 SetLastError(0xdeadbeef);
1816 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1817 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1818 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1819 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1820 ansi_charset, symbol_charset, russian_charset,
1821 *font_name ? font_name : "<empty>");
1822 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1823 for (i = 0; i < efd.total; i++)
1826 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1827 font_name, efd.lf[i].lfFaceName);
1831 switch (font_charset)
1834 ok(ansi_charset > 0,
1835 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1837 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1838 ok(russian_charset > 0,
1839 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1841 case SYMBOL_CHARSET:
1843 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1845 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1846 ok(!russian_charset,
1847 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1849 case DEFAULT_CHARSET:
1850 ok(ansi_charset > 0,
1851 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1852 ok(symbol_charset > 0,
1853 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1854 ok(russian_charset > 0,
1855 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1861 ok(ansi_charset > 0,
1862 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1863 ok(symbol_charset > 0,
1864 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1865 ok(russian_charset > 0,
1866 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1869 memset(&lf, 0, sizeof(lf));
1870 lf.lfCharSet = SYMBOL_CHARSET;
1871 lstrcpy(lf.lfFaceName, font_name);
1873 SetLastError(0xdeadbeef);
1874 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1875 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1876 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1877 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1878 ansi_charset, symbol_charset, russian_charset,
1879 *font_name ? font_name : "<empty>");
1880 if (*font_name && font_charset == ANSI_CHARSET)
1881 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1884 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1885 for (i = 0; i < efd.total; i++)
1887 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1889 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1890 font_name, efd.lf[i].lfFaceName);
1894 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1895 ok(symbol_charset > 0,
1896 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1897 ok(!russian_charset,
1898 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1904 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1906 HFONT hfont, hfont_prev;
1908 GLYPHMETRICS gm1, gm2;
1911 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1913 if(!pGetGlyphIndicesA)
1915 skip("GetGlyphIndicesA is unavailable\n");
1919 /* negative widths are handled just as positive ones */
1920 lf2.lfWidth = -lf->lfWidth;
1922 SetLastError(0xdeadbeef);
1923 hfont = CreateFontIndirectA(lf);
1924 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1925 check_font("original", lf, hfont);
1927 hfont_prev = SelectObject(hdc, hfont);
1929 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1930 if (ret == GDI_ERROR || idx == 0xffff)
1932 SelectObject(hdc, hfont_prev);
1933 DeleteObject(hfont);
1934 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1938 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1939 memset(&gm1, 0xab, sizeof(gm1));
1940 SetLastError(0xdeadbeef);
1941 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1942 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1944 SelectObject(hdc, hfont_prev);
1945 DeleteObject(hfont);
1947 SetLastError(0xdeadbeef);
1948 hfont = CreateFontIndirectA(&lf2);
1949 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1950 check_font("negative width", &lf2, hfont);
1952 hfont_prev = SelectObject(hdc, hfont);
1954 memset(&gm2, 0xbb, sizeof(gm2));
1955 SetLastError(0xdeadbeef);
1956 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1957 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1959 SelectObject(hdc, hfont_prev);
1960 DeleteObject(hfont);
1962 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1963 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1964 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1965 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1966 gm1.gmCellIncX == gm2.gmCellIncX &&
1967 gm1.gmCellIncY == gm2.gmCellIncY,
1968 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1969 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1970 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1971 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1972 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1975 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1976 #include "pshpack2.h"
1980 SHORT xAvgCharWidth;
1981 USHORT usWeightClass;
1982 USHORT usWidthClass;
1984 SHORT ySubscriptXSize;
1985 SHORT ySubscriptYSize;
1986 SHORT ySubscriptXOffset;
1987 SHORT ySubscriptYOffset;
1988 SHORT ySuperscriptXSize;
1989 SHORT ySuperscriptYSize;
1990 SHORT ySuperscriptXOffset;
1991 SHORT ySuperscriptYOffset;
1992 SHORT yStrikeoutSize;
1993 SHORT yStrikeoutPosition;
1996 ULONG ulUnicodeRange1;
1997 ULONG ulUnicodeRange2;
1998 ULONG ulUnicodeRange3;
1999 ULONG ulUnicodeRange4;
2002 USHORT usFirstCharIndex;
2003 USHORT usLastCharIndex;
2004 /* According to the Apple spec, original version didn't have the below fields,
2005 * version numbers were taked from the OpenType spec.
2007 /* version 0 (TrueType 1.5) */
2008 USHORT sTypoAscender;
2009 USHORT sTypoDescender;
2010 USHORT sTypoLineGap;
2012 USHORT usWinDescent;
2013 /* version 1 (TrueType 1.66) */
2014 ULONG ulCodePageRange1;
2015 ULONG ulCodePageRange2;
2016 /* version 2 (OpenType 1.2) */
2019 USHORT usDefaultChar;
2021 USHORT usMaxContext;
2023 #include "poppack.h"
2025 #ifdef WORDS_BIGENDIAN
2026 #define GET_BE_WORD(x) (x)
2027 #define GET_BE_DWORD(x) (x)
2029 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2030 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2033 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2034 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2035 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2036 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2037 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2050 } cmap_encoding_record;
2058 BYTE glyph_ids[256];
2068 USHORT search_range;
2069 USHORT entry_selector;
2072 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2075 USHORT start_count[seg_countx2 / 2];
2076 USHORT id_delta[seg_countx2 / 2];
2077 USHORT id_range_offset[seg_countx2 / 2];
2087 USHORT id_range_offset;
2088 } cmap_format_4_seg;
2090 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2092 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2093 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2094 os2->panose.bWeight, os2->panose.bProportion);
2097 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2100 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2104 for(i = 0; i < 256; i++)
2106 if(cmap->glyph_ids[i] == 0) continue;
2108 if(*first == 256) *first = i;
2110 if(*first == 256) return FALSE;
2114 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2116 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2117 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2118 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2119 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2120 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2123 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last)
2126 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2127 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2128 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2132 for(i = 0; i < seg_count; i++)
2135 cmap_format_4_seg seg;
2137 get_seg4(cmap, i, &seg);
2138 for(code = seg.start_count; code <= seg.end_count; code++)
2140 if(seg.id_range_offset == 0)
2141 index = (seg.id_delta + code) & 0xffff;
2144 index = seg.id_range_offset / 2
2145 + code - seg.start_count
2148 index = GET_BE_WORD(glyph_ids[index]);
2149 if(index) index += seg.id_delta;
2151 if(*first == 0x10000)
2152 *last = *first = code;
2158 if(*first == 0x10000) return FALSE;
2162 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2165 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2167 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2169 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2170 return (BYTE *)header + GET_BE_DWORD(record->offset);
2183 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2186 cmap_header *header;
2191 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2192 ok(size != GDI_ERROR, "no cmap table found\n");
2193 if(size == GDI_ERROR) return FALSE;
2195 header = HeapAlloc(GetProcessHeap(), 0, size);
2196 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2197 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2198 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2200 cmap = get_cmap(header, 3, 1);
2202 *cmap_type = cmap_ms_unicode;
2205 cmap = get_cmap(header, 3, 0);
2206 if(cmap) *cmap_type = cmap_ms_symbol;
2210 *cmap_type = cmap_none;
2214 format = GET_BE_WORD(*(WORD *)cmap);
2218 r = get_first_last_from_cmap0(cmap, first, last);
2221 r = get_first_last_from_cmap4(cmap, first, last);
2224 trace("unhandled cmap format %d\n", format);
2229 HeapFree(GetProcessHeap(), 0, header);
2233 static void test_text_metrics(const LOGFONTA *lf)
2236 HFONT hfont, hfont_old;
2240 const char *font_name = lf->lfFaceName;
2241 DWORD cmap_first = 0, cmap_last = 0;
2242 cmap_type cmap_type;
2246 SetLastError(0xdeadbeef);
2247 hfont = CreateFontIndirectA(lf);
2248 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2250 hfont_old = SelectObject(hdc, hfont);
2252 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2253 if (size == GDI_ERROR)
2255 trace("OS/2 chunk was not found\n");
2258 if (size > sizeof(tt_os2))
2260 trace("got too large OS/2 chunk of size %u\n", size);
2261 size = sizeof(tt_os2);
2264 memset(&tt_os2, 0, sizeof(tt_os2));
2265 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2266 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2268 SetLastError(0xdeadbeef);
2269 ret = GetTextMetricsA(hdc, &tmA);
2270 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2272 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2274 skip("Unable to retrieve first and last glyphs from cmap\n");
2278 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2279 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2280 UINT os2_first_char, os2_last_char, default_char, break_char;
2284 version = GET_BE_WORD(tt_os2.version);
2286 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2287 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2288 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2289 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2291 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2292 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2293 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2295 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2300 case 1257: /* Baltic */
2301 expect_last_W = 0xf8fd;
2304 expect_last_W = 0xf0ff;
2306 expect_break_W = 0x20;
2307 expect_default_W = expect_break_W - 1;
2308 expect_first_A = 0x1e;
2309 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2313 expect_first_W = cmap_first;
2314 expect_last_W = min(cmap_last, os2_last_char);
2315 if(os2_first_char <= 1)
2316 expect_break_W = os2_first_char + 2;
2317 else if(os2_first_char > 0xff)
2318 expect_break_W = 0x20;
2320 expect_break_W = os2_first_char;
2321 expect_default_W = expect_break_W - 1;
2322 expect_first_A = expect_default_W - 1;
2323 expect_last_A = min(expect_last_W, 0xff);
2325 expect_break_A = expect_break_W;
2326 expect_default_A = expect_default_W;
2328 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2329 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2330 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2331 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2332 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2334 ok(tmA.tmFirstChar == expect_first_A ||
2335 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2336 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2337 ok(tmA.tmLastChar == expect_last_A ||
2338 tmA.tmLastChar == 0xff /* win9x */,
2339 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2340 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2341 font_name, tmA.tmBreakChar, expect_break_A);
2342 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2343 font_name, tmA.tmDefaultChar, expect_default_A);
2346 SetLastError(0xdeadbeef);
2347 ret = GetTextMetricsW(hdc, &tmW);
2348 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2349 "GetTextMetricsW error %u\n", GetLastError());
2352 /* Wine uses the os2 first char */
2353 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2354 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2355 font_name, tmW.tmFirstChar, expect_first_W);
2357 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2358 font_name, tmW.tmFirstChar, expect_first_W);
2360 /* Wine uses the os2 last char */
2361 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2362 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2363 font_name, tmW.tmLastChar, expect_last_W);
2365 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2366 font_name, tmW.tmLastChar, expect_last_W);
2367 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2368 font_name, tmW.tmBreakChar, expect_break_W);
2369 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2370 font_name, tmW.tmDefaultChar, expect_default_W);
2372 /* Test the aspect ratio while we have tmW */
2373 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2374 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2375 tmW.tmDigitizedAspectX, ret);
2376 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2377 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2378 tmW.tmDigitizedAspectX, ret);
2382 /* test FF_ values */
2383 switch(tt_os2.panose.bFamilyType)
2387 case PAN_FAMILY_TEXT_DISPLAY:
2388 case PAN_FAMILY_PICTORIAL:
2390 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2391 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2393 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2396 switch(tt_os2.panose.bSerifStyle)
2401 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2404 case PAN_SERIF_COVE:
2405 case PAN_SERIF_OBTUSE_COVE:
2406 case PAN_SERIF_SQUARE_COVE:
2407 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2408 case PAN_SERIF_SQUARE:
2409 case PAN_SERIF_THIN:
2410 case PAN_SERIF_BONE:
2411 case PAN_SERIF_EXAGGERATED:
2412 case PAN_SERIF_TRIANGLE:
2413 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2416 case PAN_SERIF_NORMAL_SANS:
2417 case PAN_SERIF_OBTUSE_SANS:
2418 case PAN_SERIF_PERP_SANS:
2419 case PAN_SERIF_FLARED:
2420 case PAN_SERIF_ROUNDED:
2421 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2426 case PAN_FAMILY_SCRIPT:
2427 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2430 case PAN_FAMILY_DECORATIVE:
2431 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2435 test_negative_width(hdc, lf);
2438 SelectObject(hdc, hfont_old);
2439 DeleteObject(hfont);
2444 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2446 INT *enumed = (INT *)lParam;
2448 if (type == TRUETYPE_FONTTYPE)
2451 test_text_metrics(lf);
2456 static void test_GetTextMetrics(void)
2464 memset(&lf, 0, sizeof(lf));
2465 lf.lfCharSet = DEFAULT_CHARSET;
2467 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2468 trace("Tested metrics of %d truetype fonts\n", enumed);
2473 static void test_nonexistent_font(void)
2481 { "Times New Roman Baltic", 186 },
2482 { "Times New Roman CE", 238 },
2483 { "Times New Roman CYR", 204 },
2484 { "Times New Roman Greek", 161 },
2485 { "Times New Roman TUR", 162 }
2491 INT cs, expected_cs, i;
2492 char buf[LF_FACESIZE];
2494 if (!is_truetype_font_installed("Arial") ||
2495 !is_truetype_font_installed("Times New Roman"))
2497 skip("Arial or Times New Roman not installed\n");
2501 expected_cs = GetACP();
2502 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2504 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2507 expected_cs = csi.ciCharset;
2508 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2512 memset(&lf, 0, sizeof(lf));
2514 lf.lfWeight = FW_REGULAR;
2515 lf.lfCharSet = ANSI_CHARSET;
2516 lf.lfPitchAndFamily = FF_SWISS;
2517 strcpy(lf.lfFaceName, "Nonexistent font");
2518 hfont = CreateFontIndirectA(&lf);
2519 hfont = SelectObject(hdc, hfont);
2520 GetTextFaceA(hdc, sizeof(buf), buf);
2521 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2522 cs = GetTextCharset(hdc);
2523 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2524 DeleteObject(SelectObject(hdc, hfont));
2526 memset(&lf, 0, sizeof(lf));
2528 lf.lfWeight = FW_DONTCARE;
2529 strcpy(lf.lfFaceName, "Nonexistent font");
2530 hfont = CreateFontIndirectA(&lf);
2531 hfont = SelectObject(hdc, hfont);
2532 GetTextFaceA(hdc, sizeof(buf), buf);
2533 todo_wine /* Wine uses Arial for all substitutions */
2534 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2535 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2536 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2538 cs = GetTextCharset(hdc);
2539 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2540 DeleteObject(SelectObject(hdc, hfont));
2542 memset(&lf, 0, sizeof(lf));
2544 lf.lfWeight = FW_REGULAR;
2545 strcpy(lf.lfFaceName, "Nonexistent font");
2546 hfont = CreateFontIndirectA(&lf);
2547 hfont = SelectObject(hdc, hfont);
2548 GetTextFaceA(hdc, sizeof(buf), buf);
2549 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2550 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2551 cs = GetTextCharset(hdc);
2552 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2553 DeleteObject(SelectObject(hdc, hfont));
2555 memset(&lf, 0, sizeof(lf));
2557 lf.lfWeight = FW_DONTCARE;
2558 strcpy(lf.lfFaceName, "Times New Roman");
2559 hfont = CreateFontIndirectA(&lf);
2560 hfont = SelectObject(hdc, hfont);
2561 GetTextFaceA(hdc, sizeof(buf), buf);
2562 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2563 cs = GetTextCharset(hdc);
2564 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2565 DeleteObject(SelectObject(hdc, hfont));
2567 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2569 memset(&lf, 0, sizeof(lf));
2571 lf.lfWeight = FW_REGULAR;
2572 strcpy(lf.lfFaceName, font_subst[i].name);
2573 hfont = CreateFontIndirectA(&lf);
2574 hfont = SelectObject(hdc, hfont);
2575 cs = GetTextCharset(hdc);
2576 if (font_subst[i].charset == expected_cs)
2578 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2579 GetTextFaceA(hdc, sizeof(buf), buf);
2580 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2584 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2585 GetTextFaceA(hdc, sizeof(buf), buf);
2586 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2587 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2589 DeleteObject(SelectObject(hdc, hfont));
2591 memset(&lf, 0, sizeof(lf));
2593 lf.lfWeight = FW_DONTCARE;
2594 strcpy(lf.lfFaceName, font_subst[i].name);
2595 hfont = CreateFontIndirectA(&lf);
2596 hfont = SelectObject(hdc, hfont);
2597 GetTextFaceA(hdc, sizeof(buf), buf);
2598 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2599 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2600 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2601 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2602 "got %s for font %s\n", buf, font_subst[i].name);
2603 cs = GetTextCharset(hdc);
2604 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2605 DeleteObject(SelectObject(hdc, hfont));
2611 static void test_GdiRealizationInfo(void)
2616 HFONT hfont, hfont_old;
2619 if(!pGdiRealizationInfo)
2621 skip("GdiRealizationInfo not available\n");
2627 memset(info, 0xcc, sizeof(info));
2628 r = pGdiRealizationInfo(hdc, info);
2629 ok(r != 0, "ret 0\n");
2630 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2631 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2633 if (!is_truetype_font_installed("Arial"))
2635 skip("skipping GdiRealizationInfo with truetype font\n");
2639 memset(&lf, 0, sizeof(lf));
2640 strcpy(lf.lfFaceName, "Arial");
2642 lf.lfWeight = FW_NORMAL;
2643 hfont = CreateFontIndirectA(&lf);
2644 hfont_old = SelectObject(hdc, hfont);
2646 memset(info, 0xcc, sizeof(info));
2647 r = pGdiRealizationInfo(hdc, info);
2648 ok(r != 0, "ret 0\n");
2649 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2650 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2652 DeleteObject(SelectObject(hdc, hfont_old));
2658 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2659 the nul in the count of characters copied when the face name buffer is not
2660 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2661 always includes it. */
2662 static void test_GetTextFace(void)
2664 static const char faceA[] = "Tahoma";
2665 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2668 char bufA[LF_FACESIZE];
2669 WCHAR bufW[LF_FACESIZE];
2674 if(!is_font_installed("Tahoma"))
2676 skip("Tahoma is not installed so skipping this test\n");
2681 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2682 f = CreateFontIndirectA(&fA);
2683 ok(f != NULL, "CreateFontIndirectA failed\n");
2686 g = SelectObject(dc, f);
2687 n = GetTextFaceA(dc, sizeof bufA, bufA);
2688 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2689 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2691 /* Play with the count arg. */
2693 n = GetTextFaceA(dc, 0, bufA);
2694 ok(n == 0, "GetTextFaceA returned %d\n", n);
2695 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2698 n = GetTextFaceA(dc, 1, bufA);
2699 ok(n == 0, "GetTextFaceA returned %d\n", n);
2700 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2702 bufA[0] = 'x'; bufA[1] = 'y';
2703 n = GetTextFaceA(dc, 2, bufA);
2704 ok(n == 1, "GetTextFaceA returned %d\n", n);
2705 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2707 n = GetTextFaceA(dc, 0, NULL);
2708 ok(n == sizeof faceA ||
2709 broken(n == 0), /* win98, winMe */
2710 "GetTextFaceA returned %d\n", n);
2712 DeleteObject(SelectObject(dc, g));
2713 ReleaseDC(NULL, dc);
2716 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2717 SetLastError(0xdeadbeef);
2718 f = CreateFontIndirectW(&fW);
2719 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2721 win_skip("CreateFontIndirectW is not implemented\n");
2724 ok(f != NULL, "CreateFontIndirectW failed\n");
2727 g = SelectObject(dc, f);
2728 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2729 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2730 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2732 /* Play with the count arg. */
2734 n = GetTextFaceW(dc, 0, bufW);
2735 ok(n == 0, "GetTextFaceW returned %d\n", n);
2736 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2739 n = GetTextFaceW(dc, 1, bufW);
2740 ok(n == 1, "GetTextFaceW returned %d\n", n);
2741 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2743 bufW[0] = 'x'; bufW[1] = 'y';
2744 n = GetTextFaceW(dc, 2, bufW);
2745 ok(n == 2, "GetTextFaceW returned %d\n", n);
2746 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2748 n = GetTextFaceW(dc, 0, NULL);
2749 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2751 DeleteObject(SelectObject(dc, g));
2752 ReleaseDC(NULL, dc);
2755 static void test_orientation(void)
2757 static const char test_str[11] = "Test String";
2760 HFONT hfont, old_hfont;
2763 if (!is_truetype_font_installed("Arial"))
2765 skip("Arial is not installed\n");
2769 hdc = CreateCompatibleDC(0);
2770 memset(&lf, 0, sizeof(lf));
2771 lstrcpyA(lf.lfFaceName, "Arial");
2773 lf.lfOrientation = lf.lfEscapement = 900;
2774 hfont = create_font("orientation", &lf);
2775 old_hfont = SelectObject(hdc, hfont);
2776 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2777 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2778 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2779 SelectObject(hdc, old_hfont);
2780 DeleteObject(hfont);
2784 static void test_GetGlyphOutline(void)
2786 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2790 HFONT hfont, old_hfont;
2793 if (!is_truetype_font_installed("Tahoma"))
2795 skip("Tahoma is not installed\n");
2799 hdc = CreateCompatibleDC(0);
2800 memset(&lf, 0, sizeof(lf));
2802 lstrcpyA(lf.lfFaceName, "Tahoma");
2803 SetLastError(0xdeadbeef);
2804 hfont = CreateFontIndirectA(&lf);
2805 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2806 old_hfont = SelectObject(hdc, hfont);
2808 memset(&gm, 0, sizeof(gm));
2809 SetLastError(0xdeadbeef);
2810 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2811 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2813 memset(&gm, 0, sizeof(gm));
2814 SetLastError(0xdeadbeef);
2815 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2816 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2817 ok(GetLastError() == 0xdeadbeef ||
2818 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2819 "expected 0xdeadbeef, got %u\n", GetLastError());
2821 memset(&gm, 0, sizeof(gm));
2822 SetLastError(0xdeadbeef);
2823 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2824 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2825 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
2827 memset(&gm, 0, sizeof(gm));
2828 SetLastError(0xdeadbeef);
2829 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2830 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2832 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
2833 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2836 SelectObject(hdc, old_hfont);
2837 DeleteObject(hfont);
2847 test_outline_font();
2848 test_bitmap_font_metrics();
2849 test_GdiGetCharDimensions();
2850 test_GetCharABCWidths();
2851 test_text_extents();
2852 test_GetGlyphIndices();
2853 test_GetKerningPairs();
2854 test_GetOutlineTextMetrics();
2855 test_SetTextJustification();
2856 test_font_charset();
2857 test_GetFontUnicodeRanges();
2858 test_nonexistent_font();
2861 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2862 * I'd like to avoid them in this test.
2864 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2865 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2866 if (is_truetype_font_installed("Arial Black") &&
2867 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2869 test_EnumFontFamilies("", ANSI_CHARSET);
2870 test_EnumFontFamilies("", SYMBOL_CHARSET);
2871 test_EnumFontFamilies("", DEFAULT_CHARSET);
2874 skip("Arial Black or Symbol/Wingdings is not installed\n");
2875 test_GetTextMetrics();
2876 test_GdiRealizationInfo();
2878 test_GetGlyphOutline();