2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
46 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
48 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
49 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
50 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
51 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
53 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
55 static HMODULE hgdi32 = 0;
56 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
58 static void init(void)
60 hgdi32 = GetModuleHandleA("gdi32.dll");
62 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
63 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
64 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
65 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
66 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
67 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
68 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
69 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
70 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
71 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
72 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
73 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
74 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
75 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
76 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
79 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
81 if (type != TRUETYPE_FONTTYPE) return 1;
86 static BOOL is_truetype_font_installed(const char *name)
91 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
98 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
103 static BOOL is_font_installed(const char *name)
108 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
115 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
123 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
124 /* NT4 tries to be clever and only returns the minimum length */
125 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
127 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
128 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
129 ok(lf->lfHeight == getobj_lf.lfHeight ||
130 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
131 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
132 ok(lf->lfWidth == getobj_lf.lfWidth ||
133 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
134 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
135 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
136 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
137 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
138 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
139 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
140 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
141 ok(lf->lfWeight == getobj_lf.lfWeight ||
142 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
143 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
144 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
145 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
146 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
147 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
148 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
149 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
150 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
151 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
152 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
153 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
154 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
157 static HFONT create_font(const char* test, const LOGFONTA* lf)
159 HFONT hfont = CreateFontIndirectA(lf);
160 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
162 check_font(test, lf, hfont);
166 static void test_logfont(void)
171 memset(&lf, 0, sizeof lf);
173 lf.lfCharSet = ANSI_CHARSET;
174 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
175 lf.lfWeight = FW_DONTCARE;
178 lf.lfQuality = DEFAULT_QUALITY;
180 lstrcpyA(lf.lfFaceName, "Arial");
181 hfont = create_font("Arial", &lf);
184 memset(&lf, 'A', sizeof(lf));
185 hfont = CreateFontIndirectA(&lf);
186 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
188 lf.lfFaceName[LF_FACESIZE - 1] = 0;
189 check_font("AAA...", &lf, hfont);
193 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
195 if (type & RASTER_FONTTYPE)
197 LOGFONT *lf = (LOGFONT *)lParam;
199 return 0; /* stop enumeration */
202 return 1; /* continue enumeration */
205 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
207 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
208 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
209 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
210 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
211 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
212 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
213 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
214 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
215 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
216 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
217 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
218 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
219 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
220 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
221 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
222 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
223 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
224 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
225 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
226 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
229 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
230 LONG lfWidth, const char *test_str,
231 INT test_str_len, const TEXTMETRICA *tm_orig,
232 const SIZE *size_orig, INT width_of_A_orig,
233 INT scale_x, INT scale_y)
236 OUTLINETEXTMETRIC otm;
239 INT width_of_A, cx, cy;
245 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
247 GetObjectA(hfont, sizeof(lf), &lf);
249 if (GetOutlineTextMetricsA(hdc, 0, NULL))
251 otm.otmSize = sizeof(otm) / 2;
252 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253 ok(ret == sizeof(otm)/2 /* XP */ ||
254 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
256 memset(&otm, 0x1, sizeof(otm));
257 otm.otmSize = sizeof(otm);
258 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259 ok(ret == sizeof(otm) /* XP */ ||
260 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
262 memset(&tm, 0x2, sizeof(tm));
263 ret = GetTextMetricsA(hdc, &tm);
264 ok(ret, "GetTextMetricsA failed\n");
265 /* the structure size is aligned */
266 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
268 ok(0, "tm != otm\n");
269 compare_tm(&tm, &otm.otmTextMetrics);
272 tm = otm.otmTextMetrics;
273 if (0) /* these metrics are scaled too, but with rounding errors */
275 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
276 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
278 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
279 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
280 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
281 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
282 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
283 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
287 ret = GetTextMetricsA(hdc, &tm);
288 ok(ret, "GetTextMetricsA failed\n");
291 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
292 cy = tm.tmHeight / tm_orig->tmHeight;
293 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
294 lfHeight, scale_x, scale_y, cx, cy);
295 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
296 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
297 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
298 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
299 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
301 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
305 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
308 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
310 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
312 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
313 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
315 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
317 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
320 /* Test how GDI scales bitmap font metrics */
321 static void test_bitmap_font(void)
323 static const char test_str[11] = "Test String";
326 HFONT hfont, old_hfont;
329 INT ret, i, width_orig, height_orig, scale, lfWidth;
333 /* "System" has only 1 pixel size defined, otherwise the test breaks */
334 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
338 trace("no bitmap fonts were found, skipping the test\n");
342 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
344 height_orig = bitmap_lf.lfHeight;
345 lfWidth = bitmap_lf.lfWidth;
347 hfont = create_font("bitmap", &bitmap_lf);
348 old_hfont = SelectObject(hdc, hfont);
349 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
350 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
351 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
352 SelectObject(hdc, old_hfont);
355 bitmap_lf.lfHeight = 0;
356 bitmap_lf.lfWidth = 4;
357 hfont = create_font("bitmap", &bitmap_lf);
358 old_hfont = SelectObject(hdc, hfont);
359 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
360 SelectObject(hdc, old_hfont);
363 bitmap_lf.lfHeight = height_orig;
364 bitmap_lf.lfWidth = lfWidth;
366 /* test fractional scaling */
367 for (i = 1; i <= height_orig * 6; i++)
371 bitmap_lf.lfHeight = i;
372 hfont = create_font("fractional", &bitmap_lf);
373 scale = (i + height_orig - 1) / height_orig;
374 nearest_height = scale * height_orig;
375 /* Only jump to the next height if the difference <= 25% original height */
376 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
377 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
378 so we'll not test this particular height. */
379 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
380 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
381 old_hfont = SelectObject(hdc, hfont);
382 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
383 SelectObject(hdc, old_hfont);
387 /* test integer scaling 3x2 */
388 bitmap_lf.lfHeight = height_orig * 2;
389 bitmap_lf.lfWidth *= 3;
390 hfont = create_font("3x2", &bitmap_lf);
391 old_hfont = SelectObject(hdc, hfont);
392 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
393 SelectObject(hdc, old_hfont);
396 /* test integer scaling 3x3 */
397 bitmap_lf.lfHeight = height_orig * 3;
398 bitmap_lf.lfWidth = 0;
399 hfont = create_font("3x3", &bitmap_lf);
400 old_hfont = SelectObject(hdc, hfont);
401 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
402 SelectObject(hdc, old_hfont);
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
411 static const char test_str[11] = "Test String";
414 HFONT hfont, old_hfont, old_hfont_2;
415 OUTLINETEXTMETRICA otm;
417 INT width_orig, height_orig, lfWidth;
420 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
424 if (!is_truetype_font_installed("Arial"))
426 skip("Arial is not installed\n");
430 hdc = CreateCompatibleDC(0);
432 memset(&lf, 0, sizeof(lf));
433 strcpy(lf.lfFaceName, "Arial");
435 hfont = create_font("outline", &lf);
436 old_hfont = SelectObject(hdc, hfont);
437 otm.otmSize = sizeof(otm);
438 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
442 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
443 SelectObject(hdc, old_hfont);
446 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
447 lf.lfHeight = otm.otmEMSquare;
448 lf.lfHeight = -lf.lfHeight;
449 hfont = create_font("outline", &lf);
450 old_hfont = SelectObject(hdc, hfont);
451 otm.otmSize = sizeof(otm);
452 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
453 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
454 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
455 SelectObject(hdc, old_hfont);
458 height_orig = otm.otmTextMetrics.tmHeight;
459 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
461 /* test integer scaling 3x2 */
462 lf.lfHeight = height_orig * 2;
463 lf.lfWidth = lfWidth * 3;
464 hfont = create_font("3x2", &lf);
465 old_hfont = SelectObject(hdc, hfont);
466 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
467 SelectObject(hdc, old_hfont);
470 /* test integer scaling 3x3 */
471 lf.lfHeight = height_orig * 3;
472 lf.lfWidth = lfWidth * 3;
473 hfont = create_font("3x3", &lf);
474 old_hfont = SelectObject(hdc, hfont);
475 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
476 SelectObject(hdc, old_hfont);
479 /* test integer scaling 1x1 */
480 lf.lfHeight = height_orig * 1;
481 lf.lfWidth = lfWidth * 1;
482 hfont = create_font("1x1", &lf);
483 old_hfont = SelectObject(hdc, hfont);
484 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 SelectObject(hdc, old_hfont);
488 /* test integer scaling 1x1 */
489 lf.lfHeight = height_orig;
491 hfont = create_font("1x1", &lf);
492 old_hfont = SelectObject(hdc, hfont);
493 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
495 /* with an identity matrix */
496 memset(&gm, 0, sizeof(gm));
497 SetLastError(0xdeadbeef);
498 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
499 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
500 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
501 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
502 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
503 /* with a custom matrix */
504 memset(&gm, 0, sizeof(gm));
505 SetLastError(0xdeadbeef);
506 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
507 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
508 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
509 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
510 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
512 /* Test that changing the DC transformation affects only the font
513 * selected on this DC and doesn't affect the same font selected on
516 hdc_2 = CreateCompatibleDC(0);
517 old_hfont_2 = SelectObject(hdc_2, hfont);
518 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
520 SetMapMode(hdc, MM_ANISOTROPIC);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* test restrictions of compatibility mode GM_COMPATIBLE */
526 /* part 1: rescaling only X should not change font scaling on screen.
527 So compressing the X axis by 2 is not done, and this
528 appears as X scaling of 2 that no one requested. */
529 SetWindowExtEx(hdc, 100, 100, NULL);
530 SetViewportExtEx(hdc, 50, 100, NULL);
531 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
532 /* font metrics on another DC should be unchanged */
533 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
535 /* part 2: rescaling only Y should change font scaling.
536 As also X is scaled by a factor of 2, but this is not
537 requested by the DC transformation, we get a scaling factor
538 of 2 in the X coordinate. */
539 SetViewportExtEx(hdc, 100, 200, NULL);
540 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
541 /* font metrics on another DC should be unchanged */
542 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
544 /* restore scaling */
545 SetMapMode(hdc, MM_TEXT);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
550 SelectObject(hdc_2, old_hfont_2);
553 if (!SetGraphicsMode(hdc, GM_ADVANCED))
555 SelectObject(hdc, old_hfont);
558 skip("GM_ADVANCED is not supported on this platform\n");
569 SetLastError(0xdeadbeef);
570 ret = SetWorldTransform(hdc, &xform);
571 ok(ret, "SetWorldTransform error %u\n", GetLastError());
573 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
575 /* with an identity matrix */
576 memset(&gm, 0, sizeof(gm));
577 SetLastError(0xdeadbeef);
578 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581 pt.x = width_orig; pt.y = 0;
583 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
584 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
585 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
586 /* with a custom matrix */
587 memset(&gm, 0, sizeof(gm));
588 SetLastError(0xdeadbeef);
589 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
590 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
591 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
592 pt.x = width_orig; pt.y = 0;
594 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
595 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
596 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598 SetLastError(0xdeadbeef);
599 ret = SetMapMode(hdc, MM_LOMETRIC);
600 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
604 /* with an identity matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
612 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
614 /* with a custom matrix */
615 memset(&gm, 0, sizeof(gm));
616 SetLastError(0xdeadbeef);
617 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
618 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
619 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
620 pt.x = width_orig; pt.y = 0;
622 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
623 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
625 SetLastError(0xdeadbeef);
626 ret = SetMapMode(hdc, MM_TEXT);
627 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
629 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
631 /* with an identity matrix */
632 memset(&gm, 0, sizeof(gm));
633 SetLastError(0xdeadbeef);
634 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
635 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
636 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
637 pt.x = width_orig; pt.y = 0;
639 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
640 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
641 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
642 /* with a custom matrix */
643 memset(&gm, 0, sizeof(gm));
644 SetLastError(0xdeadbeef);
645 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
646 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
647 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
648 pt.x = width_orig; pt.y = 0;
650 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
651 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
652 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
654 SelectObject(hdc, old_hfont);
659 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
661 LOGFONT *lf = (LOGFONT *)lParam;
663 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
666 return 0; /* stop enumeration */
668 return 1; /* continue enumeration */
671 static void test_bitmap_font_metrics(void)
673 static const struct font_data
675 const char face_name[LF_FACESIZE];
676 int weight, height, ascent, descent, int_leading, ext_leading;
677 int ave_char_width, max_char_width, dpi;
678 BYTE first_char, last_char, def_char, break_char;
683 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
684 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
685 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
686 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
687 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
688 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
689 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
690 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
691 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
692 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
693 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
694 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
695 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
696 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
697 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
698 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
700 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
701 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
702 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
703 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
704 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
705 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
706 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
707 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
708 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
709 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
710 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
711 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
713 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
714 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
717 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
719 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
721 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
722 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
723 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
724 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
725 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
726 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
727 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
728 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
729 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
731 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
732 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
733 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
734 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
735 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
736 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
737 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
739 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
740 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
741 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
743 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
744 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
745 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
747 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
748 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
749 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
751 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
752 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
753 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
755 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
756 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
759 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
760 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN },
761 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
762 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
765 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
766 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC },
767 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN },
768 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
769 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
770 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC },
771 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN },
772 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
773 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
774 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC },
775 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN },
776 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
777 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC },
778 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN },
780 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
781 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
782 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
783 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
784 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
785 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
786 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
787 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
788 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
789 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
790 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
791 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
793 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
794 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
795 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
797 /* The 120dpi version still has its dpi marked as 96 */
798 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
800 /* FIXME: add "Terminal" */
804 HFONT hfont, old_hfont;
809 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
811 hdc = CreateCompatibleDC(0);
814 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
818 memset(&lf, 0, sizeof(lf));
820 lf.lfHeight = fd[i].height;
821 strcpy(lf.lfFaceName, fd[i].face_name);
823 for(bit = 0; bit < 32; bit++)
831 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
832 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
834 lf.lfCharSet = csi.ciCharset;
835 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
838 hfont = create_font(lf.lfFaceName, &lf);
839 old_hfont = SelectObject(hdc, hfont);
840 bRet = GetTextMetrics(hdc, &tm);
841 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
842 if(fd[i].dpi == tm.tmDigitizedAspectX)
844 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
845 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
847 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);
848 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);
849 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);
850 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);
851 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);
852 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);
853 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);
854 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmFirstChar);
855 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmLastChar);
856 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmDefaultChar);
857 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmBreakChar);
859 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
860 that make the max width bigger */
861 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
862 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);
865 skip("Skipping font metrics test for system langid 0x%x\n",
868 SelectObject(hdc, old_hfont);
876 static void test_GdiGetCharDimensions(void)
882 LONG avgwidth, height;
883 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
885 if (!pGdiGetCharDimensions)
887 win_skip("GdiGetCharDimensions not available on this platform\n");
891 hdc = CreateCompatibleDC(NULL);
893 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
894 avgwidth = ((size.cx / 26) + 1) / 2;
896 ret = pGdiGetCharDimensions(hdc, &tm, &height);
897 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
898 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
900 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
901 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
903 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
904 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
907 ret = pGdiGetCharDimensions(hdc, NULL, &height);
908 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
909 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
914 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
915 const TEXTMETRIC *lpntme,
916 DWORD FontType, LPARAM lParam)
918 if (FontType & TRUETYPE_FONTTYPE)
922 hfont = CreateFontIndirect(lpelfe);
925 *(HFONT *)lParam = hfont;
933 static void test_GetCharABCWidths(void)
935 static const WCHAR str[] = {'a',0};
957 {0xffffff, 0xffffff},
958 {0x1000000, 0x1000000},
959 {0xffffff, 0x1000000},
960 {0xffffffff, 0xffffffff},
968 BOOL r[sizeof range / sizeof range[0]];
971 {ANSI_CHARSET, 0x30, 0x30,
972 {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
973 {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
974 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
975 {HANGEUL_CHARSET, 0x8141, 0xac02,
976 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
977 {JOHAB_CHARSET, 0x8446, 0x3135,
978 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
979 {GB2312_CHARSET, 0x8141, 0x4e04,
980 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
981 {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
982 {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
986 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
988 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
992 memset(&lf, 0, sizeof(lf));
993 strcpy(lf.lfFaceName, "System");
996 hfont = CreateFontIndirectA(&lf);
998 hfont = SelectObject(hdc, hfont);
1000 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1001 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1003 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1004 ok(!ret, "GetCharABCWidthsI should have failed\n");
1006 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1007 ok(!ret, "GetCharABCWidthsI should have failed\n");
1009 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1010 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1012 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1013 ok(!ret, "GetCharABCWidthsW should have failed\n");
1015 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1016 ok(!ret, "GetCharABCWidthsW should have failed\n");
1018 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1019 ok(!ret, "GetCharABCWidthsW should have failed\n");
1021 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1022 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1024 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1025 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1027 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1028 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1030 hfont = SelectObject(hdc, hfont);
1031 DeleteObject(hfont);
1033 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1037 UINT code = 0x41, j;
1039 lf.lfFaceName[0] = '\0';
1040 lf.lfCharSet = c[i].cs;
1041 lf.lfPitchAndFamily = 0;
1042 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1044 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1048 memset(a, 0, sizeof a);
1049 memset(w, 0, sizeof w);
1050 hfont = SelectObject(hdc, hfont);
1051 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1052 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1053 memcmp(a, w, sizeof a) == 0,
1054 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1056 memset(a, 0xbb, sizeof a);
1057 ret = pGetCharABCWidthsA(hdc, code, code, a);
1058 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1059 memset(full, 0xcc, sizeof full);
1060 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1061 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1062 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1063 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1065 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1067 memset(full, 0xdd, sizeof full);
1068 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1069 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1070 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1073 UINT last = range[j].last - range[j].first;
1074 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1075 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1076 "GetCharABCWidthsA %x should match. codepage = %u\n",
1077 range[j].last, c[i].cs);
1081 hfont = SelectObject(hdc, hfont);
1082 DeleteObject(hfont);
1085 ReleaseDC(NULL, hdc);
1088 static void test_text_extents(void)
1090 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1092 INT i, len, fit1, fit2;
1101 memset(&lf, 0, sizeof(lf));
1102 strcpy(lf.lfFaceName, "Arial");
1105 hfont = CreateFontIndirectA(&lf);
1107 hfont = SelectObject(hdc, hfont);
1108 GetTextMetricsA(hdc, &tm);
1109 GetTextExtentPointA(hdc, "o", 1, &sz);
1110 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1112 SetLastError(0xdeadbeef);
1113 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1114 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1116 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1117 hfont = SelectObject(hdc, hfont);
1118 DeleteObject(hfont);
1124 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1125 extents[0] = 1; /* So that the increasing sequence test will fail
1126 if the extents array is untouched. */
1127 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1128 GetTextExtentPointW(hdc, wt, len, &sz2);
1129 ok(sz1.cy == sz2.cy,
1130 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1131 /* Because of the '\n' in the string GetTextExtentExPoint and
1132 GetTextExtentPoint return different widths under Win2k, but
1133 under WinXP they return the same width. So we don't test that
1136 for (i = 1; i < len; ++i)
1137 ok(extents[i-1] <= extents[i],
1138 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1140 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1141 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1142 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1143 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1144 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1145 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1146 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1147 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1148 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1149 ok(extents[0] == extents[2] && extents[1] == extents[3],
1150 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1151 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1152 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1153 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1154 HeapFree(GetProcessHeap(), 0, extents);
1156 /* extents functions fail with -ve counts (the interesting case being -1) */
1157 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1158 ok(ret == FALSE, "got %d\n", ret);
1159 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1160 ok(ret == FALSE, "got %d\n", ret);
1161 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1162 ok(ret == FALSE, "got %d\n", ret);
1164 /* max_extent = 0 succeeds and returns zero */
1166 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1168 broken(ret == FALSE), /* NT4, 2k */
1171 broken(fit1 == -215), /* NT4, 2k */
1172 "fit = %d\n", fit1);
1173 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1174 ok(ret == TRUE, "got %d\n", ret);
1175 ok(fit2 == 0, "fit = %d\n", fit2);
1177 /* max_extent = -1 is interpreted as a very large width that will
1178 * definitely fit our three characters */
1180 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1181 ok(ret == TRUE, "got %d\n", ret);
1182 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1183 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1184 ok(ret == TRUE, "got %d\n", ret);
1185 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1187 /* max_extent = -2 is interpreted similarly, but the Ansi version
1188 * rejects it while the Unicode one accepts it */
1190 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1191 todo_wine ok(ret == FALSE, "got %d\n", ret);
1192 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1193 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1194 ok(ret == TRUE, "got %d\n", ret);
1195 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1197 hfont = SelectObject(hdc, hfont);
1198 DeleteObject(hfont);
1199 ReleaseDC(NULL, hdc);
1202 static void test_GetGlyphIndices(void)
1209 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1210 WORD glyphs[(sizeof(testtext)/2)-1];
1214 if (!pGetGlyphIndicesW) {
1215 win_skip("GetGlyphIndicesW not available on platform\n");
1221 memset(&lf, 0, sizeof(lf));
1222 strcpy(lf.lfFaceName, "System");
1224 lf.lfCharSet = ANSI_CHARSET;
1226 hfont = CreateFontIndirectA(&lf);
1227 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1228 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1229 if (textm.tmCharSet == ANSI_CHARSET)
1231 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1232 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1233 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1234 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1236 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1237 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1238 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1239 textm.tmDefaultChar, glyphs[4]);
1242 /* FIXME: Write tests for non-ANSI charsets. */
1243 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1245 if(!is_font_installed("Tahoma"))
1247 skip("Tahoma is not installed so skipping this test\n");
1250 memset(&lf, 0, sizeof(lf));
1251 strcpy(lf.lfFaceName, "Tahoma");
1254 hfont = CreateFontIndirectA(&lf);
1255 hOldFont = SelectObject(hdc, hfont);
1256 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1257 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1258 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1259 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1260 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1262 testtext[0] = textm.tmDefaultChar;
1263 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1264 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1265 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1266 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1267 DeleteObject(SelectObject(hdc, hOldFont));
1270 static void test_GetKerningPairs(void)
1272 static const struct kerning_data
1274 const char face_name[LF_FACESIZE];
1276 /* some interesting fields from OUTLINETEXTMETRIC */
1277 LONG tmHeight, tmAscent, tmDescent;
1282 UINT otmsCapEmHeight;
1287 UINT otmusMinimumPPEM;
1288 /* small subset of kerning pairs to test */
1289 DWORD total_kern_pairs;
1290 const KERNINGPAIR kern_pair[26];
1293 {"Arial", 12, 12, 9, 3,
1294 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1297 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1298 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1299 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1300 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1301 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1302 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1303 {933,970,+1},{933,972,-1}
1306 {"Arial", -34, 39, 32, 7,
1307 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1310 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1311 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1312 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1313 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1314 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1315 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1316 {933,970,+2},{933,972,-3}
1319 { "Arial", 120, 120, 97, 23,
1320 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1323 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1324 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1325 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1326 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1327 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1328 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1329 {933,970,+6},{933,972,-10}
1332 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1333 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1334 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1337 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1338 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1339 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1340 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1341 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1342 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1343 {933,970,+54},{933,972,-83}
1349 HFONT hfont, hfont_old;
1350 KERNINGPAIR *kern_pair;
1352 DWORD total_kern_pairs, ret, i, n, matches;
1356 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1357 * which may render this test unusable, so we're trying to avoid that.
1359 SetLastError(0xdeadbeef);
1360 GetKerningPairsW(hdc, 0, NULL);
1361 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1363 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1368 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1370 OUTLINETEXTMETRICW otm;
1373 if (!is_font_installed(kd[i].face_name))
1375 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1379 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1381 memset(&lf, 0, sizeof(lf));
1382 strcpy(lf.lfFaceName, kd[i].face_name);
1383 lf.lfHeight = kd[i].height;
1384 hfont = CreateFontIndirect(&lf);
1387 hfont_old = SelectObject(hdc, hfont);
1389 SetLastError(0xdeadbeef);
1390 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1391 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1392 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1394 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1395 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1396 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1397 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1398 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1399 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1401 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1402 kd[i].otmEMSquare, otm.otmEMSquare);
1403 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1404 kd[i].otmAscent, otm.otmAscent);
1405 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1406 kd[i].otmDescent, otm.otmDescent);
1407 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1408 kd[i].otmLineGap, otm.otmLineGap);
1409 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1410 kd[i].otmMacDescent, otm.otmMacDescent);
1411 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1412 kd[i].otmMacAscent, otm.otmMacAscent);
1414 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1415 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1416 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1417 kd[i].otmsXHeight, otm.otmsXHeight);
1418 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1419 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1420 kd[i].otmMacLineGap, otm.otmMacLineGap);
1421 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1422 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1425 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1426 trace("total_kern_pairs %u\n", total_kern_pairs);
1427 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1429 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1432 SetLastError(0xdeadbeef);
1433 ret = GetKerningPairsW(hdc, 0, kern_pair);
1434 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1435 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1436 ok(ret == 0, "got %u, expected 0\n", ret);
1438 ret = GetKerningPairsW(hdc, 100, NULL);
1439 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1441 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1442 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1444 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1445 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1449 for (n = 0; n < ret; n++)
1452 /* Disabled to limit console spam */
1453 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1454 trace("{'%c','%c',%d},\n",
1455 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1456 for (j = 0; j < kd[i].total_kern_pairs; j++)
1458 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1459 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1461 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1462 "pair %d:%d got %d, expected %d\n",
1463 kern_pair[n].wFirst, kern_pair[n].wSecond,
1464 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1470 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1471 matches, kd[i].total_kern_pairs);
1473 HeapFree(GetProcessHeap(), 0, kern_pair);
1475 SelectObject(hdc, hfont_old);
1476 DeleteObject(hfont);
1482 static void test_height_selection(void)
1484 static const struct font_data
1486 const char face_name[LF_FACESIZE];
1487 int requested_height;
1488 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1491 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1492 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1493 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1494 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1495 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1496 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1497 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1498 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1499 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1500 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1504 HFONT hfont, old_hfont;
1508 hdc = CreateCompatibleDC(0);
1511 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1513 if (!is_truetype_font_installed(fd[i].face_name))
1515 skip("%s is not installed\n", fd[i].face_name);
1519 memset(&lf, 0, sizeof(lf));
1520 lf.lfHeight = fd[i].requested_height;
1521 lf.lfWeight = fd[i].weight;
1522 strcpy(lf.lfFaceName, fd[i].face_name);
1524 hfont = CreateFontIndirect(&lf);
1527 old_hfont = SelectObject(hdc, hfont);
1528 ret = GetTextMetrics(hdc, &tm);
1529 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1530 if(fd[i].dpi == tm.tmDigitizedAspectX)
1532 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1533 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1534 ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1535 ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1536 ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1537 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1538 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1540 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1543 SelectObject(hdc, old_hfont);
1544 DeleteObject(hfont);
1550 static void test_GetOutlineTextMetrics(void)
1552 OUTLINETEXTMETRIC *otm;
1554 HFONT hfont, hfont_old;
1556 DWORD ret, otm_size;
1559 if (!is_font_installed("Arial"))
1561 skip("Arial is not installed\n");
1567 memset(&lf, 0, sizeof(lf));
1568 strcpy(lf.lfFaceName, "Arial");
1570 lf.lfWeight = FW_NORMAL;
1571 lf.lfPitchAndFamily = DEFAULT_PITCH;
1572 lf.lfQuality = PROOF_QUALITY;
1573 hfont = CreateFontIndirect(&lf);
1576 hfont_old = SelectObject(hdc, hfont);
1577 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1578 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1580 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1582 memset(otm, 0xAA, otm_size);
1583 SetLastError(0xdeadbeef);
1584 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1585 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1586 ok(ret == 1 /* Win9x */ ||
1587 ret == otm->otmSize /* XP*/,
1588 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1589 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1591 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1592 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1593 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1594 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1597 memset(otm, 0xAA, otm_size);
1598 SetLastError(0xdeadbeef);
1599 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1600 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1601 ok(ret == 1 /* Win9x */ ||
1602 ret == otm->otmSize /* XP*/,
1603 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1604 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1606 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1607 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1608 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1609 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1612 /* ask about truncated data */
1613 memset(otm, 0xAA, otm_size);
1614 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1615 SetLastError(0xdeadbeef);
1616 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1617 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1618 ok(ret == 1 /* Win9x */ ||
1619 ret == otm->otmSize /* XP*/,
1620 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1621 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1623 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1624 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1625 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1627 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1629 HeapFree(GetProcessHeap(), 0, otm);
1631 SelectObject(hdc, hfont_old);
1632 DeleteObject(hfont);
1637 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1641 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1642 areaWidth = clientArea->right - clientArea->left,
1644 BOOL lastExtent = FALSE;
1645 PSTR pFirstChar, pLastChar;
1651 int GetTextExtentExPointWWidth;
1654 GetTextMetricsA(hdc, &tm);
1655 y = clientArea->top;
1658 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1664 /* if not at the end of the string, ... */
1665 if (*str == '\0') break;
1666 /* ... add the next word to the current extent */
1667 while (*str != '\0' && *str++ != tm.tmBreakChar);
1669 SetTextJustification(hdc, 0, 0);
1670 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1671 } while ((int) size.cx < areaWidth);
1673 /* ignore trailing break chars */
1675 while (*(pLastChar - 1) == tm.tmBreakChar)
1681 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1683 SetTextJustification(hdc, 0, 0);
1684 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1686 /* do not justify the last extent */
1687 if (*str != '\0' && breakCount > 0)
1689 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1690 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1691 justifiedWidth = size.cx;
1693 else lastExtent = TRUE;
1695 /* catch errors and report them */
1696 if (!lastExtent && (justifiedWidth != areaWidth))
1698 memset(error[nErrors].extent, 0, 100);
1699 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1700 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1706 } while (*str && y < clientArea->bottom);
1708 for (e = 0; e < nErrors; e++)
1710 /* The width returned by GetTextExtentPoint32() is exactly the same
1711 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1712 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1713 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1714 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1718 static void test_SetTextJustification(void)
1725 static char testText[] =
1726 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1727 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1728 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1729 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1730 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1731 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1732 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1734 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1735 GetClientRect( hwnd, &clientArea );
1736 hdc = GetDC( hwnd );
1738 memset(&lf, 0, sizeof lf);
1739 lf.lfCharSet = ANSI_CHARSET;
1740 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1741 lf.lfWeight = FW_DONTCARE;
1743 lf.lfQuality = DEFAULT_QUALITY;
1744 lstrcpyA(lf.lfFaceName, "Times New Roman");
1745 hfont = create_font("Times New Roman", &lf);
1746 SelectObject(hdc, hfont);
1748 testJustification(hdc, testText, &clientArea);
1750 DeleteObject(hfont);
1751 ReleaseDC(hwnd, hdc);
1752 DestroyWindow(hwnd);
1755 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1759 HFONT hfont, hfont_old;
1766 assert(count <= 128);
1768 memset(&lf, 0, sizeof(lf));
1770 lf.lfCharSet = charset;
1772 lstrcpyA(lf.lfFaceName, "Arial");
1773 SetLastError(0xdeadbeef);
1774 hfont = CreateFontIndirectA(&lf);
1775 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1778 hfont_old = SelectObject(hdc, hfont);
1780 cs = GetTextCharsetInfo(hdc, &fs, 0);
1781 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1783 SetLastError(0xdeadbeef);
1784 ret = GetTextFaceA(hdc, sizeof(name), name);
1785 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1787 if (charset == SYMBOL_CHARSET)
1789 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1790 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1794 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1795 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1798 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1800 trace("Can't find codepage for charset %d\n", cs);
1804 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1806 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1808 skip("Font code page %d, looking for code page %d\n",
1809 pGdiGetCodePage(hdc), code_page);
1817 WCHAR unicode_buf[128];
1819 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1821 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1823 SetLastError(0xdeadbeef);
1824 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1825 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1826 count, ret, GetLastError());
1832 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1834 SetLastError(0xdeadbeef);
1835 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1836 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1837 count, ret, GetLastError());
1840 SelectObject(hdc, hfont_old);
1841 DeleteObject(hfont);
1848 static void test_font_charset(void)
1850 static struct charset_data
1854 WORD font_idxA[128], font_idxW[128];
1857 { ANSI_CHARSET, 1252 },
1858 { RUSSIAN_CHARSET, 1251 },
1859 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1863 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1865 win_skip("Skipping the font charset test on a Win9x platform\n");
1869 if (!is_font_installed("Arial"))
1871 skip("Arial is not installed\n");
1875 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1877 if (cd[i].charset == SYMBOL_CHARSET)
1879 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1881 skip("Symbol or Wingdings is not installed\n");
1885 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1886 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1887 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1890 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1893 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1894 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1897 skip("Symbol or Wingdings is not installed\n");
1900 static void test_GetFontUnicodeRanges(void)
1904 HFONT hfont, hfont_old;
1909 if (!pGetFontUnicodeRanges)
1911 win_skip("GetFontUnicodeRanges not available before W2K\n");
1915 memset(&lf, 0, sizeof(lf));
1916 lstrcpyA(lf.lfFaceName, "Arial");
1917 hfont = create_font("Arial", &lf);
1920 hfont_old = SelectObject(hdc, hfont);
1922 size = pGetFontUnicodeRanges(NULL, NULL);
1923 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1925 size = pGetFontUnicodeRanges(hdc, NULL);
1926 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1928 gs = HeapAlloc(GetProcessHeap(), 0, size);
1930 size = pGetFontUnicodeRanges(hdc, gs);
1931 ok(size, "GetFontUnicodeRanges failed\n");
1933 if (0) /* Disabled to limit console spam */
1934 for (i = 0; i < gs->cRanges; i++)
1935 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1936 trace("found %u ranges\n", gs->cRanges);
1938 HeapFree(GetProcessHeap(), 0, gs);
1940 SelectObject(hdc, hfont_old);
1941 DeleteObject(hfont);
1942 ReleaseDC(NULL, hdc);
1945 #define MAX_ENUM_FONTS 4096
1947 struct enum_font_data
1950 LOGFONT lf[MAX_ENUM_FONTS];
1953 struct enum_font_dataW
1956 LOGFONTW lf[MAX_ENUM_FONTS];
1959 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1961 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1963 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1965 if (type != TRUETYPE_FONTTYPE) return 1;
1966 if (0) /* Disabled to limit console spam */
1967 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1968 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1969 if (efd->total < MAX_ENUM_FONTS)
1970 efd->lf[efd->total++] = *lf;
1972 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1977 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1979 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1981 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1983 if (type != TRUETYPE_FONTTYPE) return 1;
1984 if (0) /* Disabled to limit console spam */
1985 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1986 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1987 if (efd->total < MAX_ENUM_FONTS)
1988 efd->lf[efd->total++] = *lf;
1990 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1995 static void get_charset_stats(struct enum_font_data *efd,
1996 int *ansi_charset, int *symbol_charset,
1997 int *russian_charset)
2002 *symbol_charset = 0;
2003 *russian_charset = 0;
2005 for (i = 0; i < efd->total; i++)
2007 switch (efd->lf[i].lfCharSet)
2012 case SYMBOL_CHARSET:
2013 (*symbol_charset)++;
2015 case RUSSIAN_CHARSET:
2016 (*russian_charset)++;
2022 static void get_charset_statsW(struct enum_font_dataW *efd,
2023 int *ansi_charset, int *symbol_charset,
2024 int *russian_charset)
2029 *symbol_charset = 0;
2030 *russian_charset = 0;
2032 for (i = 0; i < efd->total; i++)
2034 switch (efd->lf[i].lfCharSet)
2039 case SYMBOL_CHARSET:
2040 (*symbol_charset)++;
2042 case RUSSIAN_CHARSET:
2043 (*russian_charset)++;
2049 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2051 struct enum_font_data efd;
2052 struct enum_font_dataW efdw;
2055 int i, ret, ansi_charset, symbol_charset, russian_charset;
2057 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2059 if (*font_name && !is_truetype_font_installed(font_name))
2061 skip("%s is not installed\n", font_name);
2067 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2068 * while EnumFontFamiliesEx doesn't.
2070 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2073 * Use EnumFontFamiliesW since win98 crashes when the
2074 * second parameter is NULL using EnumFontFamilies
2077 SetLastError(0xdeadbeef);
2078 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2079 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2082 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2083 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2084 ansi_charset, symbol_charset, russian_charset);
2085 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2086 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2087 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2088 ok(russian_charset > 0 ||
2089 broken(russian_charset == 0), /* NT4 */
2090 "NULL family should enumerate RUSSIAN_CHARSET\n");
2094 SetLastError(0xdeadbeef);
2095 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2096 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2099 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2100 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2101 ansi_charset, symbol_charset, russian_charset);
2102 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2103 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2104 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2105 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2110 SetLastError(0xdeadbeef);
2111 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2112 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2113 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2114 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2115 ansi_charset, symbol_charset, russian_charset,
2116 *font_name ? font_name : "<empty>");
2118 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2120 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2121 for (i = 0; i < efd.total; i++)
2123 /* FIXME: remove completely once Wine is fixed */
2124 if (efd.lf[i].lfCharSet != font_charset)
2127 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2130 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2131 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2132 font_name, efd.lf[i].lfFaceName);
2135 memset(&lf, 0, sizeof(lf));
2136 lf.lfCharSet = ANSI_CHARSET;
2137 lstrcpy(lf.lfFaceName, font_name);
2139 SetLastError(0xdeadbeef);
2140 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2141 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2142 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2143 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2144 ansi_charset, symbol_charset, russian_charset,
2145 *font_name ? font_name : "<empty>");
2146 if (font_charset == SYMBOL_CHARSET)
2149 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2151 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2155 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2156 for (i = 0; i < efd.total; i++)
2158 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2160 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2161 font_name, efd.lf[i].lfFaceName);
2165 /* DEFAULT_CHARSET should enumerate all available charsets */
2166 memset(&lf, 0, sizeof(lf));
2167 lf.lfCharSet = DEFAULT_CHARSET;
2168 lstrcpy(lf.lfFaceName, font_name);
2170 SetLastError(0xdeadbeef);
2171 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2172 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2173 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2174 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2175 ansi_charset, symbol_charset, russian_charset,
2176 *font_name ? font_name : "<empty>");
2177 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2178 for (i = 0; i < efd.total; i++)
2181 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2182 font_name, efd.lf[i].lfFaceName);
2186 switch (font_charset)
2189 ok(ansi_charset > 0,
2190 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2192 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2193 ok(russian_charset > 0,
2194 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2196 case SYMBOL_CHARSET:
2198 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2200 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2201 ok(!russian_charset,
2202 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2204 case DEFAULT_CHARSET:
2205 ok(ansi_charset > 0,
2206 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2207 ok(symbol_charset > 0,
2208 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2209 ok(russian_charset > 0,
2210 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2216 ok(ansi_charset > 0,
2217 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2218 ok(symbol_charset > 0,
2219 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2220 ok(russian_charset > 0,
2221 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2224 memset(&lf, 0, sizeof(lf));
2225 lf.lfCharSet = SYMBOL_CHARSET;
2226 lstrcpy(lf.lfFaceName, font_name);
2228 SetLastError(0xdeadbeef);
2229 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2230 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2231 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2232 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2233 ansi_charset, symbol_charset, russian_charset,
2234 *font_name ? font_name : "<empty>");
2235 if (*font_name && font_charset == ANSI_CHARSET)
2236 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2239 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2240 for (i = 0; i < efd.total; i++)
2242 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2244 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2245 font_name, efd.lf[i].lfFaceName);
2249 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2250 ok(symbol_charset > 0,
2251 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2252 ok(!russian_charset,
2253 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2259 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2261 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2263 if (type != TRUETYPE_FONTTYPE) return 1;
2265 if (efd->total < MAX_ENUM_FONTS)
2266 efd->lf[efd->total++] = *lf;
2268 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2273 static void test_EnumFontFamiliesEx_default_charset(void)
2275 struct enum_font_data efd;
2276 LOGFONT gui_font, enum_font;
2280 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2281 ok(ret, "GetObject failed.\n");
2288 memset(&enum_font, 0, sizeof(enum_font));
2289 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2290 enum_font.lfCharSet = DEFAULT_CHARSET;
2291 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2294 if (efd.total == 0) {
2295 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2298 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2300 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2301 "(%s) got charset %d expected %d\n",
2302 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2307 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2309 HFONT hfont, hfont_prev;
2311 GLYPHMETRICS gm1, gm2;
2315 if(!pGetGlyphIndicesA)
2318 /* negative widths are handled just as positive ones */
2319 lf2.lfWidth = -lf->lfWidth;
2321 SetLastError(0xdeadbeef);
2322 hfont = CreateFontIndirectA(lf);
2323 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2324 check_font("original", lf, hfont);
2326 hfont_prev = SelectObject(hdc, hfont);
2328 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2329 if (ret == GDI_ERROR || idx == 0xffff)
2331 SelectObject(hdc, hfont_prev);
2332 DeleteObject(hfont);
2333 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2337 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2338 memset(&gm1, 0xab, sizeof(gm1));
2339 SetLastError(0xdeadbeef);
2340 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2341 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2343 SelectObject(hdc, hfont_prev);
2344 DeleteObject(hfont);
2346 SetLastError(0xdeadbeef);
2347 hfont = CreateFontIndirectA(&lf2);
2348 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2349 check_font("negative width", &lf2, hfont);
2351 hfont_prev = SelectObject(hdc, hfont);
2353 memset(&gm2, 0xbb, sizeof(gm2));
2354 SetLastError(0xdeadbeef);
2355 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2356 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2358 SelectObject(hdc, hfont_prev);
2359 DeleteObject(hfont);
2361 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2362 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2363 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2364 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2365 gm1.gmCellIncX == gm2.gmCellIncX &&
2366 gm1.gmCellIncY == gm2.gmCellIncY,
2367 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2368 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2369 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2370 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2371 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2374 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2375 #include "pshpack2.h"
2379 SHORT xAvgCharWidth;
2380 USHORT usWeightClass;
2381 USHORT usWidthClass;
2383 SHORT ySubscriptXSize;
2384 SHORT ySubscriptYSize;
2385 SHORT ySubscriptXOffset;
2386 SHORT ySubscriptYOffset;
2387 SHORT ySuperscriptXSize;
2388 SHORT ySuperscriptYSize;
2389 SHORT ySuperscriptXOffset;
2390 SHORT ySuperscriptYOffset;
2391 SHORT yStrikeoutSize;
2392 SHORT yStrikeoutPosition;
2395 ULONG ulUnicodeRange1;
2396 ULONG ulUnicodeRange2;
2397 ULONG ulUnicodeRange3;
2398 ULONG ulUnicodeRange4;
2401 USHORT usFirstCharIndex;
2402 USHORT usLastCharIndex;
2403 /* According to the Apple spec, original version didn't have the below fields,
2404 * version numbers were taken from the OpenType spec.
2406 /* version 0 (TrueType 1.5) */
2407 USHORT sTypoAscender;
2408 USHORT sTypoDescender;
2409 USHORT sTypoLineGap;
2411 USHORT usWinDescent;
2412 /* version 1 (TrueType 1.66) */
2413 ULONG ulCodePageRange1;
2414 ULONG ulCodePageRange2;
2415 /* version 2 (OpenType 1.2) */
2418 USHORT usDefaultChar;
2420 USHORT usMaxContext;
2422 #include "poppack.h"
2424 #ifdef WORDS_BIGENDIAN
2425 #define GET_BE_WORD(x) (x)
2426 #define GET_BE_DWORD(x) (x)
2428 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2429 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2432 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2433 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2434 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2435 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2436 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2437 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2450 } cmap_encoding_record;
2458 BYTE glyph_ids[256];
2468 USHORT search_range;
2469 USHORT entry_selector;
2472 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2475 USHORT start_count[seg_countx2 / 2];
2476 USHORT id_delta[seg_countx2 / 2];
2477 USHORT id_range_offset[seg_countx2 / 2];
2487 USHORT id_range_offset;
2488 } cmap_format_4_seg;
2490 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2492 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2493 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2494 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2495 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2496 os2->panose.bWeight, os2->panose.bProportion);
2499 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2502 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2506 for(i = 0; i < 256; i++)
2508 if(cmap->glyph_ids[i] == 0) continue;
2510 if(*first == 256) *first = i;
2512 if(*first == 256) return FALSE;
2516 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2518 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2519 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2520 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2521 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2522 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2525 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2528 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2529 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2530 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2534 for(i = 0; i < seg_count; i++)
2537 cmap_format_4_seg seg;
2539 get_seg4(cmap, i, &seg);
2540 for(code = seg.start_count; code <= seg.end_count; code++)
2542 if(seg.id_range_offset == 0)
2543 index = (seg.id_delta + code) & 0xffff;
2546 index = seg.id_range_offset / 2
2547 + code - seg.start_count
2550 /* some fonts have broken last segment */
2551 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2552 index = GET_BE_WORD(glyph_ids[index]);
2555 trace("segment %04x/%04x index %04x points to nowhere\n",
2556 seg.start_count, seg.end_count, index);
2559 if(index) index += seg.id_delta;
2561 if(*first == 0x10000)
2562 *last = *first = code;
2568 if(*first == 0x10000) return FALSE;
2572 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2575 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2577 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2579 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2580 return (BYTE *)header + GET_BE_DWORD(record->offset);
2593 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2596 cmap_header *header;
2601 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2602 ok(size != GDI_ERROR, "no cmap table found\n");
2603 if(size == GDI_ERROR) return FALSE;
2605 header = HeapAlloc(GetProcessHeap(), 0, size);
2606 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2607 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2608 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2610 cmap = get_cmap(header, 3, 1);
2612 *cmap_type = cmap_ms_unicode;
2615 cmap = get_cmap(header, 3, 0);
2616 if(cmap) *cmap_type = cmap_ms_symbol;
2620 *cmap_type = cmap_none;
2624 format = GET_BE_WORD(*(WORD *)cmap);
2628 r = get_first_last_from_cmap0(cmap, first, last);
2631 r = get_first_last_from_cmap4(cmap, first, last, size);
2634 trace("unhandled cmap format %d\n", format);
2639 HeapFree(GetProcessHeap(), 0, header);
2643 #define TT_PLATFORM_MICROSOFT 3
2644 #define TT_MS_ID_UNICODE_CS 1
2645 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2646 #define TT_NAME_ID_FULL_NAME 4
2648 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2650 struct sfnt_name_header
2653 USHORT number_of_record;
2654 USHORT storage_offset;
2666 LONG size, offset, length;
2672 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2673 ok(size != GDI_ERROR, "no name table found\n");
2674 if(size == GDI_ERROR) return FALSE;
2676 data = HeapAlloc(GetProcessHeap(), 0, size);
2677 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2678 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2680 header = (void *)data;
2681 header->format = GET_BE_WORD(header->format);
2682 header->number_of_record = GET_BE_WORD(header->number_of_record);
2683 header->storage_offset = GET_BE_WORD(header->storage_offset);
2684 if (header->format != 0)
2686 trace("got format %u\n", header->format);
2689 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2691 trace("number records out of range: %d\n", header->number_of_record);
2694 if (header->storage_offset >= size)
2696 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2700 entry = (void *)&header[1];
2701 for (i = 0; i < header->number_of_record; i++)
2703 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2704 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2705 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2706 GET_BE_WORD(entry[i].name_id) != name_id)
2711 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2712 length = GET_BE_WORD(entry[i].length);
2713 if (offset + length > size)
2715 trace("entry %d is out of range\n", i);
2718 if (length >= out_size)
2720 trace("buffer too small for entry %d\n", i);
2724 name = (WCHAR *)(data + offset);
2725 for (c = 0; c < length / 2; c++)
2726 out_buf[c] = GET_BE_WORD(name[c]);
2734 HeapFree(GetProcessHeap(), 0, data);
2738 static void test_text_metrics(const LOGFONTA *lf)
2741 HFONT hfont, hfont_old;
2745 const char *font_name = lf->lfFaceName;
2746 DWORD cmap_first = 0, cmap_last = 0;
2747 cmap_type cmap_type;
2748 BOOL sys_lang_non_english;
2750 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2753 SetLastError(0xdeadbeef);
2754 hfont = CreateFontIndirectA(lf);
2755 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2757 hfont_old = SelectObject(hdc, hfont);
2759 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2760 if (size == GDI_ERROR)
2762 trace("OS/2 chunk was not found\n");
2765 if (size > sizeof(tt_os2))
2767 trace("got too large OS/2 chunk of size %u\n", size);
2768 size = sizeof(tt_os2);
2771 memset(&tt_os2, 0, sizeof(tt_os2));
2772 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2773 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2775 SetLastError(0xdeadbeef);
2776 ret = GetTextMetricsA(hdc, &tmA);
2777 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2779 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2781 skip("Unable to retrieve first and last glyphs from cmap\n");
2785 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2786 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2787 UINT os2_first_char, os2_last_char, default_char, break_char;
2791 version = GET_BE_WORD(tt_os2.version);
2793 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2794 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2795 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2796 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2798 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2799 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2800 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2802 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2807 case 1257: /* Baltic */
2808 expect_last_W = 0xf8fd;
2811 expect_last_W = 0xf0ff;
2813 expect_break_W = 0x20;
2814 expect_default_W = expect_break_W - 1;
2815 expect_first_A = 0x1e;
2816 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2820 expect_first_W = cmap_first;
2821 expect_last_W = min(cmap_last, os2_last_char);
2822 if(os2_first_char <= 1)
2823 expect_break_W = os2_first_char + 2;
2824 else if(os2_first_char > 0xff)
2825 expect_break_W = 0x20;
2827 expect_break_W = os2_first_char;
2828 expect_default_W = expect_break_W - 1;
2829 expect_first_A = expect_default_W - 1;
2830 expect_last_A = min(expect_last_W, 0xff);
2832 expect_break_A = expect_break_W;
2833 expect_default_A = expect_default_W;
2835 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2836 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2837 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2838 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2839 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2841 ok(tmA.tmFirstChar == expect_first_A ||
2842 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2843 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2844 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2845 ok(tmA.tmLastChar == expect_last_A ||
2846 tmA.tmLastChar == 0xff /* win9x */,
2847 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2849 skip("tmLastChar is DBCS lead byte\n");
2850 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2851 font_name, tmA.tmBreakChar, expect_break_A);
2852 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2853 "A: tmDefaultChar for %s got %02x expected %02x\n",
2854 font_name, tmA.tmDefaultChar, expect_default_A);
2857 SetLastError(0xdeadbeef);
2858 ret = GetTextMetricsW(hdc, &tmW);
2859 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2860 "GetTextMetricsW error %u\n", GetLastError());
2863 /* Wine uses the os2 first char */
2864 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2865 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2866 font_name, tmW.tmFirstChar, expect_first_W);
2868 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2869 font_name, tmW.tmFirstChar, expect_first_W);
2871 /* Wine uses the os2 last char */
2872 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2873 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2874 font_name, tmW.tmLastChar, expect_last_W);
2876 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2877 font_name, tmW.tmLastChar, expect_last_W);
2878 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2879 font_name, tmW.tmBreakChar, expect_break_W);
2880 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2881 "W: tmDefaultChar for %s got %02x expected %02x\n",
2882 font_name, tmW.tmDefaultChar, expect_default_W);
2884 /* Test the aspect ratio while we have tmW */
2885 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2886 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2887 tmW.tmDigitizedAspectX, ret);
2888 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2889 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2890 tmW.tmDigitizedAspectX, ret);
2894 /* test FF_ values */
2895 switch(tt_os2.panose.bFamilyType)
2899 case PAN_FAMILY_TEXT_DISPLAY:
2900 case PAN_FAMILY_PICTORIAL:
2902 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2903 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2905 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2908 switch(tt_os2.panose.bSerifStyle)
2913 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2916 case PAN_SERIF_COVE:
2917 case PAN_SERIF_OBTUSE_COVE:
2918 case PAN_SERIF_SQUARE_COVE:
2919 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2920 case PAN_SERIF_SQUARE:
2921 case PAN_SERIF_THIN:
2922 case PAN_SERIF_BONE:
2923 case PAN_SERIF_EXAGGERATED:
2924 case PAN_SERIF_TRIANGLE:
2925 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2928 case PAN_SERIF_NORMAL_SANS:
2929 case PAN_SERIF_OBTUSE_SANS:
2930 case PAN_SERIF_PERP_SANS:
2931 case PAN_SERIF_FLARED:
2932 case PAN_SERIF_ROUNDED:
2933 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2938 case PAN_FAMILY_SCRIPT:
2939 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2942 case PAN_FAMILY_DECORATIVE:
2943 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2947 test_negative_width(hdc, lf);
2950 SelectObject(hdc, hfont_old);
2951 DeleteObject(hfont);
2956 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2958 INT *enumed = (INT *)lParam;
2960 if (type == TRUETYPE_FONTTYPE)
2963 test_text_metrics(lf);
2968 static void test_GetTextMetrics(void)
2974 /* Report only once */
2975 if(!pGetGlyphIndicesA)
2976 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2980 memset(&lf, 0, sizeof(lf));
2981 lf.lfCharSet = DEFAULT_CHARSET;
2983 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2984 trace("Tested metrics of %d truetype fonts\n", enumed);
2989 static void test_nonexistent_font(void)
2997 { "Times New Roman Baltic", 186 },
2998 { "Times New Roman CE", 238 },
2999 { "Times New Roman CYR", 204 },
3000 { "Times New Roman Greek", 161 },
3001 { "Times New Roman TUR", 162 }
3007 INT cs, expected_cs, i;
3008 char buf[LF_FACESIZE];
3010 if (!is_truetype_font_installed("Arial") ||
3011 !is_truetype_font_installed("Times New Roman"))
3013 skip("Arial or Times New Roman not installed\n");
3017 expected_cs = GetACP();
3018 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3020 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3023 expected_cs = csi.ciCharset;
3024 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3028 memset(&lf, 0, sizeof(lf));
3030 lf.lfWeight = FW_REGULAR;
3031 lf.lfCharSet = ANSI_CHARSET;
3032 lf.lfPitchAndFamily = FF_SWISS;
3033 strcpy(lf.lfFaceName, "Nonexistent font");
3034 hfont = CreateFontIndirectA(&lf);
3035 hfont = SelectObject(hdc, hfont);
3036 GetTextFaceA(hdc, sizeof(buf), buf);
3037 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3038 cs = GetTextCharset(hdc);
3039 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3040 DeleteObject(SelectObject(hdc, hfont));
3042 memset(&lf, 0, sizeof(lf));
3044 lf.lfWeight = FW_DONTCARE;
3045 strcpy(lf.lfFaceName, "Nonexistent font");
3046 hfont = CreateFontIndirectA(&lf);
3047 hfont = SelectObject(hdc, hfont);
3048 GetTextFaceA(hdc, sizeof(buf), buf);
3049 todo_wine /* Wine uses Arial for all substitutions */
3050 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3051 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3052 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3054 cs = GetTextCharset(hdc);
3055 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3056 DeleteObject(SelectObject(hdc, hfont));
3058 memset(&lf, 0, sizeof(lf));
3060 lf.lfWeight = FW_REGULAR;
3061 strcpy(lf.lfFaceName, "Nonexistent font");
3062 hfont = CreateFontIndirectA(&lf);
3063 hfont = SelectObject(hdc, hfont);
3064 GetTextFaceA(hdc, sizeof(buf), buf);
3065 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3066 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3067 cs = GetTextCharset(hdc);
3068 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3069 DeleteObject(SelectObject(hdc, hfont));
3071 memset(&lf, 0, sizeof(lf));
3073 lf.lfWeight = FW_DONTCARE;
3074 strcpy(lf.lfFaceName, "Times New Roman");
3075 hfont = CreateFontIndirectA(&lf);
3076 hfont = SelectObject(hdc, hfont);
3077 GetTextFaceA(hdc, sizeof(buf), buf);
3078 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3079 cs = GetTextCharset(hdc);
3080 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3081 DeleteObject(SelectObject(hdc, hfont));
3083 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3085 memset(&lf, 0, sizeof(lf));
3087 lf.lfWeight = FW_REGULAR;
3088 strcpy(lf.lfFaceName, font_subst[i].name);
3089 hfont = CreateFontIndirectA(&lf);
3090 hfont = SelectObject(hdc, hfont);
3091 cs = GetTextCharset(hdc);
3092 if (font_subst[i].charset == expected_cs)
3094 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3095 GetTextFaceA(hdc, sizeof(buf), buf);
3096 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3100 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3101 GetTextFaceA(hdc, sizeof(buf), buf);
3102 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3103 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3105 DeleteObject(SelectObject(hdc, hfont));
3107 memset(&lf, 0, sizeof(lf));
3109 lf.lfWeight = FW_DONTCARE;
3110 strcpy(lf.lfFaceName, font_subst[i].name);
3111 hfont = CreateFontIndirectA(&lf);
3112 hfont = SelectObject(hdc, hfont);
3113 GetTextFaceA(hdc, sizeof(buf), buf);
3114 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3115 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3116 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3117 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3118 "got %s for font %s\n", buf, font_subst[i].name);
3119 cs = GetTextCharset(hdc);
3120 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3121 DeleteObject(SelectObject(hdc, hfont));
3127 static void test_GdiRealizationInfo(void)
3132 HFONT hfont, hfont_old;
3135 if(!pGdiRealizationInfo)
3137 win_skip("GdiRealizationInfo not available\n");
3143 memset(info, 0xcc, sizeof(info));
3144 r = pGdiRealizationInfo(hdc, info);
3145 ok(r != 0, "ret 0\n");
3146 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3147 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3149 if (!is_truetype_font_installed("Arial"))
3151 skip("skipping GdiRealizationInfo with truetype font\n");
3155 memset(&lf, 0, sizeof(lf));
3156 strcpy(lf.lfFaceName, "Arial");
3158 lf.lfWeight = FW_NORMAL;
3159 hfont = CreateFontIndirectA(&lf);
3160 hfont_old = SelectObject(hdc, hfont);
3162 memset(info, 0xcc, sizeof(info));
3163 r = pGdiRealizationInfo(hdc, info);
3164 ok(r != 0, "ret 0\n");
3165 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3166 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3168 DeleteObject(SelectObject(hdc, hfont_old));
3174 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3175 the nul in the count of characters copied when the face name buffer is not
3176 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3177 always includes it. */
3178 static void test_GetTextFace(void)
3180 static const char faceA[] = "Tahoma";
3181 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3184 char bufA[LF_FACESIZE];
3185 WCHAR bufW[LF_FACESIZE];
3190 if(!is_font_installed("Tahoma"))
3192 skip("Tahoma is not installed so skipping this test\n");
3197 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3198 f = CreateFontIndirectA(&fA);
3199 ok(f != NULL, "CreateFontIndirectA failed\n");
3202 g = SelectObject(dc, f);
3203 n = GetTextFaceA(dc, sizeof bufA, bufA);
3204 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3205 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3207 /* Play with the count arg. */
3209 n = GetTextFaceA(dc, 0, bufA);
3210 ok(n == 0, "GetTextFaceA returned %d\n", n);
3211 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3214 n = GetTextFaceA(dc, 1, bufA);
3215 ok(n == 0, "GetTextFaceA returned %d\n", n);
3216 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3218 bufA[0] = 'x'; bufA[1] = 'y';
3219 n = GetTextFaceA(dc, 2, bufA);
3220 ok(n == 1, "GetTextFaceA returned %d\n", n);
3221 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3223 n = GetTextFaceA(dc, 0, NULL);
3224 ok(n == sizeof faceA ||
3225 broken(n == 0), /* win98, winMe */
3226 "GetTextFaceA returned %d\n", n);
3228 DeleteObject(SelectObject(dc, g));
3229 ReleaseDC(NULL, dc);
3232 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3233 SetLastError(0xdeadbeef);
3234 f = CreateFontIndirectW(&fW);
3235 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3237 win_skip("CreateFontIndirectW is not implemented\n");
3240 ok(f != NULL, "CreateFontIndirectW failed\n");
3243 g = SelectObject(dc, f);
3244 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3245 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3246 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3248 /* Play with the count arg. */
3250 n = GetTextFaceW(dc, 0, bufW);
3251 ok(n == 0, "GetTextFaceW returned %d\n", n);
3252 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3255 n = GetTextFaceW(dc, 1, bufW);
3256 ok(n == 1, "GetTextFaceW returned %d\n", n);
3257 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3259 bufW[0] = 'x'; bufW[1] = 'y';
3260 n = GetTextFaceW(dc, 2, bufW);
3261 ok(n == 2, "GetTextFaceW returned %d\n", n);
3262 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3264 n = GetTextFaceW(dc, 0, NULL);
3265 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3267 DeleteObject(SelectObject(dc, g));
3268 ReleaseDC(NULL, dc);
3271 static void test_orientation(void)
3273 static const char test_str[11] = "Test String";
3276 HFONT hfont, old_hfont;
3279 if (!is_truetype_font_installed("Arial"))
3281 skip("Arial is not installed\n");
3285 hdc = CreateCompatibleDC(0);
3286 memset(&lf, 0, sizeof(lf));
3287 lstrcpyA(lf.lfFaceName, "Arial");
3289 lf.lfOrientation = lf.lfEscapement = 900;
3290 hfont = create_font("orientation", &lf);
3291 old_hfont = SelectObject(hdc, hfont);
3292 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3293 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3294 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3295 SelectObject(hdc, old_hfont);
3296 DeleteObject(hfont);
3300 static void test_oemcharset(void)
3304 HFONT hfont, old_hfont;
3307 hdc = CreateCompatibleDC(0);
3308 ZeroMemory(&lf, sizeof(lf));
3310 lf.lfCharSet = OEM_CHARSET;
3311 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3312 lstrcpyA(lf.lfFaceName, "Terminal");
3313 hfont = CreateFontIndirectA(&lf);
3314 old_hfont = SelectObject(hdc, hfont);
3315 charset = GetTextCharset(hdc);
3317 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3318 hfont = SelectObject(hdc, old_hfont);
3319 GetObjectA(hfont, sizeof(clf), &clf);
3320 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3321 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3322 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3323 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3324 DeleteObject(hfont);
3328 static void test_GetGlyphOutline(void)
3331 GLYPHMETRICS gm, gm2;
3333 HFONT hfont, old_hfont;
3342 {ANSI_CHARSET, 0x30, 0x30},
3343 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3344 {HANGEUL_CHARSET, 0x8141, 0xac02},
3345 {JOHAB_CHARSET, 0x8446, 0x3135},
3346 {GB2312_CHARSET, 0x8141, 0x4e04},
3347 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3351 if (!is_truetype_font_installed("Tahoma"))
3353 skip("Tahoma is not installed\n");
3357 hdc = CreateCompatibleDC(0);
3358 memset(&lf, 0, sizeof(lf));
3360 lstrcpyA(lf.lfFaceName, "Tahoma");
3361 SetLastError(0xdeadbeef);
3362 hfont = CreateFontIndirectA(&lf);
3363 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3364 old_hfont = SelectObject(hdc, hfont);
3366 memset(&gm, 0, sizeof(gm));
3367 SetLastError(0xdeadbeef);
3368 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3369 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3371 memset(&gm, 0, sizeof(gm));
3372 SetLastError(0xdeadbeef);
3373 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3374 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3375 ok(GetLastError() == 0xdeadbeef ||
3376 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3377 "expected 0xdeadbeef, got %u\n", GetLastError());
3379 memset(&gm, 0, sizeof(gm));
3380 SetLastError(0xdeadbeef);
3381 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3382 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3383 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3385 memset(&gm, 0, sizeof(gm));
3386 SetLastError(0xdeadbeef);
3387 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3388 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3390 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3391 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3394 /* test for needed buffer size request on space char */
3395 memset(&gm, 0, sizeof(gm));
3396 SetLastError(0xdeadbeef);
3397 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3398 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3399 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3401 /* requesting buffer size for space char + error */
3402 memset(&gm, 0, sizeof(gm));
3403 SetLastError(0xdeadbeef);
3404 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3405 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3407 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3408 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3411 SelectObject(hdc, old_hfont);
3412 DeleteObject(hfont);
3414 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3416 lf.lfFaceName[0] = '\0';
3417 lf.lfCharSet = c[i].cs;
3418 lf.lfPitchAndFamily = 0;
3419 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3421 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3425 old_hfont = SelectObject(hdc, hfont);
3427 /* expected to ignore superfluous bytes (sigle-byte character) */
3428 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3429 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3430 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3432 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3433 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3434 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3436 /* expected to ignore superfluous bytes (double-byte character) */
3437 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3438 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3439 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3440 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3442 /* expected to match wide-char version results */
3443 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3444 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3446 hfont = SelectObject(hdc, old_hfont);
3447 DeleteObject(hfont);
3453 /* bug #9995: there is a limit to the character width that can be specified */
3454 static void test_GetTextMetrics2(const char *fontname, int font_height)
3460 int ave_width, height, width, ratio, scale;
3462 if (!is_truetype_font_installed( fontname)) {
3463 skip("%s is not installed\n", fontname);
3466 hdc = CreateCompatibleDC(0);
3467 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3468 /* select width = 0 */
3469 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3470 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3471 DEFAULT_QUALITY, VARIABLE_PITCH,
3473 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3474 of = SelectObject( hdc, hf);
3475 ret = GetTextMetricsA( hdc, &tm);
3476 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3477 height = tm.tmHeight;
3478 ave_width = tm.tmAveCharWidth;
3479 SelectObject( hdc, of);
3482 trace("height %d, ave width %d\n", height, ave_width);
3484 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3486 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3487 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3488 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3489 ok(hf != 0, "CreateFont failed\n");
3490 of = SelectObject(hdc, hf);
3491 ret = GetTextMetrics(hdc, &tm);
3492 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3493 SelectObject(hdc, of);
3496 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3502 ratio = width / height;
3503 scale = width / ave_width;
3505 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3506 width, height, ratio, width, ave_width, scale);
3508 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3511 static void test_CreateFontIndirect(void)
3513 LOGFONTA lf, getobj_lf;
3516 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3518 memset(&lf, 0, sizeof(lf));
3519 lf.lfCharSet = ANSI_CHARSET;
3520 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3523 lf.lfQuality = DEFAULT_QUALITY;
3524 lf.lfItalic = FALSE;
3525 lf.lfWeight = FW_DONTCARE;
3527 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3529 lstrcpyA(lf.lfFaceName, TestName[i]);
3530 hfont = CreateFontIndirectA(&lf);
3531 ok(hfont != 0, "CreateFontIndirectA failed\n");
3532 SetLastError(0xdeadbeef);
3533 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3534 ok(ret, "GetObject failed: %d\n", GetLastError());
3535 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3536 ok(lf.lfWeight == getobj_lf.lfWeight ||
3537 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3538 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3539 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3540 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3541 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3542 DeleteObject(hfont);
3546 static void test_CreateFontIndirectEx(void)
3548 ENUMLOGFONTEXDVA lfex;
3551 if (!pCreateFontIndirectExA)
3553 win_skip("CreateFontIndirectExA is not available\n");
3557 if (!is_truetype_font_installed("Arial"))
3559 skip("Arial is not installed\n");
3563 SetLastError(0xdeadbeef);
3564 hfont = pCreateFontIndirectExA(NULL);
3565 ok(hfont == NULL, "got %p\n", hfont);
3566 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3568 memset(&lfex, 0, sizeof(lfex));
3569 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3570 hfont = pCreateFontIndirectExA(&lfex);
3571 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3573 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3574 DeleteObject(hfont);
3577 static void free_font(void *font)
3579 UnmapViewOfFile(font);
3582 static void *load_font(const char *font_name, DWORD *font_size)
3584 char file_name[MAX_PATH];
3585 HANDLE file, mapping;
3588 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3589 strcat(file_name, "\\fonts\\");
3590 strcat(file_name, font_name);
3592 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3593 if (file == INVALID_HANDLE_VALUE) return NULL;
3595 *font_size = GetFileSize(file, NULL);
3597 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3604 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3607 CloseHandle(mapping);
3611 static void test_AddFontMemResource(void)
3614 DWORD font_size, num_fonts;
3618 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3620 win_skip("AddFontMemResourceEx is not available on this platform\n");
3624 font = load_font("sserife.fon", &font_size);
3627 skip("Unable to locate and load font sserife.fon\n");
3631 SetLastError(0xdeadbeef);
3632 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3633 ok(!ret, "AddFontMemResourceEx should fail\n");
3634 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3635 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3638 SetLastError(0xdeadbeef);
3639 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3640 ok(!ret, "AddFontMemResourceEx should fail\n");
3641 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3642 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3645 SetLastError(0xdeadbeef);
3646 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3647 ok(!ret, "AddFontMemResourceEx should fail\n");
3648 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3649 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3652 SetLastError(0xdeadbeef);
3653 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3654 ok(!ret, "AddFontMemResourceEx should fail\n");
3655 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3656 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3659 SetLastError(0xdeadbeef);
3660 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3661 ok(!ret, "AddFontMemResourceEx should fail\n");
3662 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3663 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3666 SetLastError(0xdeadbeef);
3667 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3668 ok(!ret, "AddFontMemResourceEx should fail\n");
3669 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3670 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3673 num_fonts = 0xdeadbeef;
3674 SetLastError(0xdeadbeef);
3675 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3676 ok(!ret, "AddFontMemResourceEx should fail\n");
3677 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3678 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3680 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3682 if (0) /* hangs under windows 2000 */
3684 num_fonts = 0xdeadbeef;
3685 SetLastError(0xdeadbeef);
3686 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3687 ok(!ret, "AddFontMemResourceEx should fail\n");
3688 ok(GetLastError() == 0xdeadbeef,
3689 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3691 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3694 num_fonts = 0xdeadbeef;
3695 SetLastError(0xdeadbeef);
3696 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3697 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3698 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3699 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3703 SetLastError(0xdeadbeef);
3704 bRet = pRemoveFontMemResourceEx(ret);
3705 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3707 /* test invalid pointer to number of loaded fonts */
3708 font = load_font("sserife.fon", &font_size);
3709 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3711 SetLastError(0xdeadbeef);
3712 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3713 ok(!ret, "AddFontMemResourceEx should fail\n");
3714 ok(GetLastError() == 0xdeadbeef,
3715 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3718 SetLastError(0xdeadbeef);
3719 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3720 ok(!ret, "AddFontMemResourceEx should fail\n");
3721 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3722 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3728 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3732 if (type != TRUETYPE_FONTTYPE) return 1;
3734 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3736 lf = (LOGFONT *)lparam;
3741 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3746 if (type != TRUETYPE_FONTTYPE) return 1;
3748 lf = (LOGFONT *)lparam;
3749 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3752 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3759 static void test_EnumFonts(void)
3765 if (!is_truetype_font_installed("Arial"))
3767 skip("Arial is not installed\n");
3771 /* Windows uses localized font face names, so Arial Bold won't be found */
3772 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3774 skip("User locale is not English, skipping the test\n");
3778 hdc = CreateCompatibleDC(0);
3780 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3781 ok(!ret, "font Arial is not enumerated\n");
3782 ret = strcmp(lf.lfFaceName, "Arial");
3783 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3784 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3786 lstrcpy(lf.lfFaceName, "Arial");
3787 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3788 ok(!ret, "font Arial is not enumerated\n");
3789 ret = strcmp(lf.lfFaceName, "Arial");
3790 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3791 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3793 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3794 ok(!ret, "font Arial Bold is not enumerated\n");
3795 ret = strcmp(lf.lfFaceName, "Arial");
3796 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3797 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3799 lstrcpy(lf.lfFaceName, "Arial Bold");
3800 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3801 ok(ret, "font Arial Bold should not be enumerated\n");
3803 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3804 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3805 ret = strcmp(lf.lfFaceName, "Arial");
3806 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3807 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3809 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3810 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3811 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3813 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3814 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3816 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3817 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3818 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3823 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3825 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3826 const char *fullname = (const char *)lParam;
3828 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3833 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3838 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3845 static void test_fullname(void)
3847 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3848 char buf[LF_FULLFACESIZE];
3854 hdc = CreateCompatibleDC(0);
3855 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3857 memset(&lf, 0, sizeof(lf));
3858 lf.lfCharSet = ANSI_CHARSET;
3859 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3862 lf.lfQuality = DEFAULT_QUALITY;
3863 lf.lfItalic = FALSE;
3864 lf.lfWeight = FW_DONTCARE;
3866 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3868 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3870 skip("%s is not installed\n", TestName[i]);
3874 lstrcpyA(lf.lfFaceName, TestName[i]);
3875 hfont = CreateFontIndirectA(&lf);
3876 ok(hfont != 0, "CreateFontIndirectA failed\n");
3878 of = SelectObject(hdc, hfont);
3880 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3881 "face full name could not be read\n");
3882 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3883 SelectObject(hdc, of);
3884 DeleteObject(hfont);
3889 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
3891 char tmp_path[MAX_PATH];
3898 SetLastError(0xdeadbeef);
3899 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
3900 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
3901 if (!rsrc) return FALSE;
3902 SetLastError(0xdeadbeef);
3903 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
3904 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
3905 if (!rsrc_data) return FALSE;
3906 SetLastError(0xdeadbeef);
3907 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
3908 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
3909 if (!rsrc_size) return FALSE;
3911 SetLastError(0xdeadbeef);
3912 ret = GetTempPath(MAX_PATH, tmp_path);
3913 ok(ret, "GetTempPath() error %d\n", GetLastError());
3914 SetLastError(0xdeadbeef);
3915 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
3916 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3918 SetLastError(0xdeadbeef);
3919 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
3920 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
3921 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
3923 SetLastError(0xdeadbeef);
3924 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
3925 ok(ret, "WriteFile() error %d\n", GetLastError());
3931 static void test_CreateScalableFontResource(void)
3933 char ttf_name[MAX_PATH];
3934 char tmp_path[MAX_PATH];
3935 char fot_name[MAX_PATH];
3939 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
3941 win_skip("AddFontResourceExA is not available on this platform\n");
3945 if (!write_ttf_file("wine_test.ttf", ttf_name))
3947 skip("Failed to create ttf file for testing\n");
3951 trace("created %s\n", ttf_name);
3953 ret = is_truetype_font_installed("wine_test");
3954 ok(!ret, "font wine_test should not be enumerated\n");
3956 ret = GetTempPath(MAX_PATH, tmp_path);
3957 ok(ret, "GetTempPath() error %d\n", GetLastError());
3958 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
3959 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3961 ret = GetFileAttributes(fot_name);
3962 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
3964 SetLastError(0xdeadbeef);
3965 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3966 ok(!ret, "CreateScalableFontResource() should fail\n");
3967 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3969 SetLastError(0xdeadbeef);
3970 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
3971 ok(!ret, "CreateScalableFontResource() should fail\n");
3972 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3974 file_part = strrchr(ttf_name, '\\');
3975 SetLastError(0xdeadbeef);
3976 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
3977 ok(!ret, "CreateScalableFontResource() should fail\n");
3978 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3980 SetLastError(0xdeadbeef);
3981 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
3982 ok(!ret, "CreateScalableFontResource() should fail\n");
3984 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3986 SetLastError(0xdeadbeef);
3987 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
3988 ok(!ret, "CreateScalableFontResource() should fail\n");
3990 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3992 ret = DeleteFile(fot_name);
3993 ok(ret, "DeleteFile() error %d\n", GetLastError());
3995 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3997 ok(!ret, "RemoveFontResourceEx() should fail\n");
3999 /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
4002 /* test public font resource */
4003 SetLastError(0xdeadbeef);
4004 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4005 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4007 ret = is_truetype_font_installed("wine_test");
4008 ok(!ret, "font wine_test should not be enumerated\n");
4010 SetLastError(0xdeadbeef);
4011 ret = pAddFontResourceExA(fot_name, 0, 0);
4012 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4014 ret = is_truetype_font_installed("wine_test");
4015 ok(ret, "font wine_test should be enumerated\n");
4017 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4018 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4020 SetLastError(0xdeadbeef);
4021 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4023 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4025 ret = is_truetype_font_installed("wine_test");
4027 ok(!ret, "font wine_test should not be enumerated\n");
4029 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4032 /* remove once RemoveFontResource is implemented */
4033 DeleteFile(fot_name);
4034 DeleteFile(ttf_name);
4038 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4039 ok(!ret, "RemoveFontResourceEx() should fail\n");
4041 DeleteFile(fot_name);
4043 /* test hidden font resource */
4044 SetLastError(0xdeadbeef);
4045 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4046 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4048 ret = is_truetype_font_installed("wine_test");
4049 ok(!ret, "font wine_test should not be enumerated\n");
4051 SetLastError(0xdeadbeef);
4052 ret = pAddFontResourceExA(fot_name, 0, 0);
4053 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4055 ret = is_truetype_font_installed("wine_test");
4056 ok(!ret, "font wine_test should not be enumerated\n");
4058 /* XP allows removing a private font added with 0 flags */
4059 SetLastError(0xdeadbeef);
4060 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4061 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4063 ret = is_truetype_font_installed("wine_test");
4064 ok(!ret, "font wine_test should not be enumerated\n");
4066 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4067 ok(!ret, "RemoveFontResourceEx() should fail\n");
4069 DeleteFile(fot_name);
4070 DeleteFile(ttf_name);
4073 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4076 HFONT hfont, hfont_prev;
4080 static const WCHAR str[] = { 0x2025 };
4082 *installed = is_truetype_font_installed(name);
4086 lf.lfEscapement = 0;
4087 lf.lfOrientation = 0;
4088 lf.lfWeight = FW_DONTCARE;
4092 lf.lfCharSet = DEFAULT_CHARSET;
4093 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4094 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4095 lf.lfQuality = DEFAULT_QUALITY;
4096 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4097 strcpy(lf.lfFaceName, name);
4099 hfont = CreateFontIndirectA(&lf);
4100 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4104 hfont_prev = SelectObject(hdc, hfont);
4105 ok(hfont_prev != NULL, "SelectObject failed\n");
4107 ret = GetTextFaceA(hdc, sizeof facename, facename);
4108 ok(ret, "GetTextFaceA failed\n");
4109 *selected = !strcmp(facename, name);
4111 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4112 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4114 memset(gm, 0, sizeof *gm);
4116 ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4117 ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4119 SelectObject(hdc, hfont_prev);
4120 DeleteObject(hfont);
4121 ReleaseDC(NULL, hdc);
4124 static void test_vertical_font(void)
4126 char ttf_name[MAX_PATH];
4128 BOOL ret, installed, selected;
4132 if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4134 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4138 if (!write_ttf_file("vertical.ttf", ttf_name))
4140 skip("Failed to create ttf file for testing\n");
4144 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4145 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4147 check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4148 ok(installed, "@WineTestVertical is not installed\n");
4149 ok(selected, "@WineTestVertical is not selected\n");
4150 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4151 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4152 gm.gmBlackBoxX, gm.gmBlackBoxY);
4154 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4155 ok(installed, "@@WineTestVertical is not installed\n");
4156 ok(selected, "@@WineTestVertical is not selected\n");
4157 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4158 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4159 gm.gmBlackBoxX, gm.gmBlackBoxY);
4161 ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4163 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4164 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4166 DeleteFile(ttf_name);
4169 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4170 DWORD type, LPARAM lParam)
4172 if (lf->lfFaceName[0] == '@') {
4178 static void test_east_asian_font_selection(void)
4181 UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4182 GB2312_CHARSET, CHINESEBIG5_CHARSET };
4187 for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4191 char face_name[LF_FACESIZE];
4194 memset(&lf, 0, sizeof lf);
4195 lf.lfFaceName[0] = '\0';
4196 lf.lfCharSet = charset[i];
4198 if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4200 skip("Vertical font for charset %u is not installed\n", charset[i]);
4204 hfont = CreateFontIndirectA(&lf);
4205 hfont = SelectObject(hdc, hfont);
4206 memset(face_name, 0, sizeof face_name);
4207 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4208 ok(ret && face_name[0] != '@',
4209 "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4210 DeleteObject(SelectObject(hdc, hfont));
4212 memset(&lf, 0, sizeof lf);
4213 strcpy(lf.lfFaceName, "@");
4214 lf.lfCharSet = charset[i];
4215 hfont = CreateFontIndirectA(&lf);
4216 hfont = SelectObject(hdc, hfont);
4217 memset(face_name, 0, sizeof face_name);
4218 ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4219 ok(ret && face_name[0] == '@',
4220 "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4221 DeleteObject(SelectObject(hdc, hfont));
4223 ReleaseDC(NULL, hdc);
4232 test_outline_font();
4233 test_bitmap_font_metrics();
4234 test_GdiGetCharDimensions();
4235 test_GetCharABCWidths();
4236 test_text_extents();
4237 test_GetGlyphIndices();
4238 test_GetKerningPairs();
4239 test_GetOutlineTextMetrics();
4240 test_SetTextJustification();
4241 test_font_charset();
4242 test_GetFontUnicodeRanges();
4243 test_nonexistent_font();
4245 test_height_selection();
4246 test_AddFontMemResource();
4249 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4250 * I'd like to avoid them in this test.
4252 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4253 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4254 if (is_truetype_font_installed("Arial Black") &&
4255 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4257 test_EnumFontFamilies("", ANSI_CHARSET);
4258 test_EnumFontFamilies("", SYMBOL_CHARSET);
4259 test_EnumFontFamilies("", DEFAULT_CHARSET);
4262 skip("Arial Black or Symbol/Wingdings is not installed\n");
4263 test_EnumFontFamiliesEx_default_charset();
4264 test_GetTextMetrics();
4265 test_GdiRealizationInfo();
4267 test_GetGlyphOutline();
4268 test_GetTextMetrics2("Tahoma", -11);
4269 test_GetTextMetrics2("Tahoma", -55);
4270 test_GetTextMetrics2("Tahoma", -110);
4271 test_GetTextMetrics2("Arial", -11);
4272 test_GetTextMetrics2("Arial", -55);
4273 test_GetTextMetrics2("Arial", -110);
4274 test_CreateFontIndirect();
4275 test_CreateFontIndirectEx();
4279 test_vertical_font();
4280 test_east_asian_font_selection();
4281 /* CreateScalableFontResource should be last test until RemoveFontResource
4282 * is properly implemented.
4284 test_CreateScalableFontResource();