wininet: Support the Cache-Control max-age directive for setting url cache entry...
[wine/testsucceed.git] / dlls / gdi32 / tests / font.c
bloba9a8755380212f488064576323c236b037e4f24c
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 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 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
45 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
46 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
48 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
49 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
50 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static HMODULE hgdi32 = 0;
53 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
55 static void init(void)
57 hgdi32 = GetModuleHandleA("gdi32.dll");
59 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
60 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
61 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
62 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
63 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
64 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
65 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
66 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
67 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
68 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
69 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
70 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
73 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
75 if (type != TRUETYPE_FONTTYPE) return 1;
77 return 0;
80 static BOOL is_truetype_font_installed(const char *name)
82 HDC hdc = GetDC(0);
83 BOOL ret = FALSE;
85 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
86 ret = TRUE;
88 ReleaseDC(0, hdc);
89 return ret;
92 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
94 return 0;
97 static BOOL is_font_installed(const char *name)
99 HDC hdc = GetDC(0);
100 BOOL ret = FALSE;
102 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
103 ret = TRUE;
105 ReleaseDC(0, hdc);
106 return ret;
109 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
111 LOGFONTA getobj_lf;
112 int ret, minlen = 0;
114 if (!hfont)
115 return;
117 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
118 /* NT4 tries to be clever and only returns the minimum length */
119 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
120 minlen++;
121 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
122 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
123 ok(lf->lfHeight == getobj_lf.lfHeight ||
124 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
125 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
126 ok(lf->lfWidth == getobj_lf.lfWidth ||
127 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
128 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
129 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
130 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
131 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
132 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
133 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
134 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
135 ok(lf->lfWeight == getobj_lf.lfWeight ||
136 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
137 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
138 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
139 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
140 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
141 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
142 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
143 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
144 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
145 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
146 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
147 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
148 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
151 static HFONT create_font(const char* test, const LOGFONTA* lf)
153 HFONT hfont = CreateFontIndirectA(lf);
154 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
155 if (hfont)
156 check_font(test, lf, hfont);
157 return hfont;
160 static void test_logfont(void)
162 LOGFONTA lf;
163 HFONT hfont;
165 memset(&lf, 0, sizeof lf);
167 lf.lfCharSet = ANSI_CHARSET;
168 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
169 lf.lfWeight = FW_DONTCARE;
170 lf.lfHeight = 16;
171 lf.lfWidth = 16;
172 lf.lfQuality = DEFAULT_QUALITY;
174 lstrcpyA(lf.lfFaceName, "Arial");
175 hfont = create_font("Arial", &lf);
176 DeleteObject(hfont);
178 memset(&lf, 'A', sizeof(lf));
179 hfont = CreateFontIndirectA(&lf);
180 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
182 lf.lfFaceName[LF_FACESIZE - 1] = 0;
183 check_font("AAA...", &lf, hfont);
184 DeleteObject(hfont);
187 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
189 if (type & RASTER_FONTTYPE)
191 LOGFONT *lf = (LOGFONT *)lParam;
192 *lf = *elf;
193 return 0; /* stop enumeration */
196 return 1; /* continue enumeration */
199 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
201 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
202 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
203 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
204 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
205 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
206 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
207 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
208 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
209 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
210 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
211 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
212 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
213 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
214 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
215 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
216 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
217 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
218 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
219 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
220 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
223 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
224 LONG lfWidth, const char *test_str,
225 INT test_str_len, const TEXTMETRICA *tm_orig,
226 const SIZE *size_orig, INT width_of_A_orig,
227 INT scale_x, INT scale_y)
229 LOGFONTA lf;
230 OUTLINETEXTMETRIC otm;
231 TEXTMETRICA tm;
232 SIZE size;
233 INT width_of_A, cx, cy;
234 UINT ret;
236 if (!hfont)
237 return;
239 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
241 GetObjectA(hfont, sizeof(lf), &lf);
243 if (GetOutlineTextMetricsA(hdc, 0, NULL))
245 otm.otmSize = sizeof(otm) / 2;
246 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
247 ok(ret == sizeof(otm)/2 /* XP */ ||
248 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
250 memset(&otm, 0x1, sizeof(otm));
251 otm.otmSize = sizeof(otm);
252 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253 ok(ret == sizeof(otm) /* XP */ ||
254 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
256 memset(&tm, 0x2, sizeof(tm));
257 ret = GetTextMetricsA(hdc, &tm);
258 ok(ret, "GetTextMetricsA failed\n");
259 /* the structure size is aligned */
260 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
262 ok(0, "tm != otm\n");
263 compare_tm(&tm, &otm.otmTextMetrics);
266 tm = otm.otmTextMetrics;
267 if (0) /* these metrics are scaled too, but with rounding errors */
269 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
270 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
272 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
273 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
274 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
275 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
276 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
277 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
279 else
281 ret = GetTextMetricsA(hdc, &tm);
282 ok(ret, "GetTextMetricsA failed\n");
285 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
286 cy = tm.tmHeight / tm_orig->tmHeight;
287 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
288 lfHeight, scale_x, scale_y, cx, cy);
289 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
290 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
291 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
292 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
293 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
295 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
296 if (lf.lfHeight)
298 if (lf.lfWidth)
299 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
301 else
302 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
304 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
306 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
307 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
309 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
311 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);
314 /* Test how GDI scales bitmap font metrics */
315 static void test_bitmap_font(void)
317 static const char test_str[11] = "Test String";
318 HDC hdc;
319 LOGFONTA bitmap_lf;
320 HFONT hfont, old_hfont;
321 TEXTMETRICA tm_orig;
322 SIZE size_orig;
323 INT ret, i, width_orig, height_orig, scale, lfWidth;
325 hdc = GetDC(0);
327 /* "System" has only 1 pixel size defined, otherwise the test breaks */
328 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
329 if (ret)
331 ReleaseDC(0, hdc);
332 trace("no bitmap fonts were found, skipping the test\n");
333 return;
336 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
338 height_orig = bitmap_lf.lfHeight;
339 lfWidth = bitmap_lf.lfWidth;
341 hfont = create_font("bitmap", &bitmap_lf);
342 old_hfont = SelectObject(hdc, hfont);
343 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
344 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
345 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
346 SelectObject(hdc, old_hfont);
347 DeleteObject(hfont);
349 bitmap_lf.lfHeight = 0;
350 bitmap_lf.lfWidth = 4;
351 hfont = create_font("bitmap", &bitmap_lf);
352 old_hfont = SelectObject(hdc, hfont);
353 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
354 SelectObject(hdc, old_hfont);
355 DeleteObject(hfont);
357 bitmap_lf.lfHeight = height_orig;
358 bitmap_lf.lfWidth = lfWidth;
360 /* test fractional scaling */
361 for (i = 1; i <= height_orig * 6; i++)
363 INT nearest_height;
365 bitmap_lf.lfHeight = i;
366 hfont = create_font("fractional", &bitmap_lf);
367 scale = (i + height_orig - 1) / height_orig;
368 nearest_height = scale * height_orig;
369 /* Only jump to the next height if the difference <= 25% original height */
370 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
371 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
372 so we'll not test this particular height. */
373 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
374 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
375 old_hfont = SelectObject(hdc, hfont);
376 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
377 SelectObject(hdc, old_hfont);
378 DeleteObject(hfont);
381 /* test integer scaling 3x2 */
382 bitmap_lf.lfHeight = height_orig * 2;
383 bitmap_lf.lfWidth *= 3;
384 hfont = create_font("3x2", &bitmap_lf);
385 old_hfont = SelectObject(hdc, hfont);
386 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
387 SelectObject(hdc, old_hfont);
388 DeleteObject(hfont);
390 /* test integer scaling 3x3 */
391 bitmap_lf.lfHeight = height_orig * 3;
392 bitmap_lf.lfWidth = 0;
393 hfont = create_font("3x3", &bitmap_lf);
394 old_hfont = SelectObject(hdc, hfont);
395 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
396 SelectObject(hdc, old_hfont);
397 DeleteObject(hfont);
399 ReleaseDC(0, hdc);
402 /* Test how GDI scales outline font metrics */
403 static void test_outline_font(void)
405 static const char test_str[11] = "Test String";
406 HDC hdc, hdc_2;
407 LOGFONTA lf;
408 HFONT hfont, old_hfont, old_hfont_2;
409 OUTLINETEXTMETRICA otm;
410 SIZE size_orig;
411 INT width_orig, height_orig, lfWidth;
412 XFORM xform;
413 GLYPHMETRICS gm;
414 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
415 POINT pt;
416 INT ret;
418 if (!is_truetype_font_installed("Arial"))
420 skip("Arial is not installed\n");
421 return;
424 hdc = CreateCompatibleDC(0);
426 memset(&lf, 0, sizeof(lf));
427 strcpy(lf.lfFaceName, "Arial");
428 lf.lfHeight = 72;
429 hfont = create_font("outline", &lf);
430 old_hfont = SelectObject(hdc, hfont);
431 otm.otmSize = sizeof(otm);
432 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
433 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
434 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
436 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
437 SelectObject(hdc, old_hfont);
438 DeleteObject(hfont);
440 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
441 lf.lfHeight = otm.otmEMSquare;
442 lf.lfHeight = -lf.lfHeight;
443 hfont = create_font("outline", &lf);
444 old_hfont = SelectObject(hdc, hfont);
445 otm.otmSize = sizeof(otm);
446 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
447 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
448 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
449 SelectObject(hdc, old_hfont);
450 DeleteObject(hfont);
452 height_orig = otm.otmTextMetrics.tmHeight;
453 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
455 /* test integer scaling 3x2 */
456 lf.lfHeight = height_orig * 2;
457 lf.lfWidth = lfWidth * 3;
458 hfont = create_font("3x2", &lf);
459 old_hfont = SelectObject(hdc, hfont);
460 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
461 SelectObject(hdc, old_hfont);
462 DeleteObject(hfont);
464 /* test integer scaling 3x3 */
465 lf.lfHeight = height_orig * 3;
466 lf.lfWidth = lfWidth * 3;
467 hfont = create_font("3x3", &lf);
468 old_hfont = SelectObject(hdc, hfont);
469 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
470 SelectObject(hdc, old_hfont);
471 DeleteObject(hfont);
473 /* test integer scaling 1x1 */
474 lf.lfHeight = height_orig * 1;
475 lf.lfWidth = lfWidth * 1;
476 hfont = create_font("1x1", &lf);
477 old_hfont = SelectObject(hdc, hfont);
478 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
479 SelectObject(hdc, old_hfont);
480 DeleteObject(hfont);
482 /* test integer scaling 1x1 */
483 lf.lfHeight = height_orig;
484 lf.lfWidth = 0;
485 hfont = create_font("1x1", &lf);
486 old_hfont = SelectObject(hdc, hfont);
487 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
489 /* with an identity matrix */
490 memset(&gm, 0, sizeof(gm));
491 SetLastError(0xdeadbeef);
492 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
493 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
495 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
496 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
497 /* with a custom matrix */
498 memset(&gm, 0, sizeof(gm));
499 SetLastError(0xdeadbeef);
500 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
501 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
502 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
503 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
504 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
506 /* Test that changing the DC transformation affects only the font
507 * selected on this DC and doesn't affect the same font selected on
508 * another DC.
510 hdc_2 = CreateCompatibleDC(0);
511 old_hfont_2 = SelectObject(hdc_2, hfont);
512 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
514 SetMapMode(hdc, MM_ANISOTROPIC);
516 /* font metrics on another DC should be unchanged */
517 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
519 /* test restrictions of compatibility mode GM_COMPATIBLE */
520 /* part 1: rescaling only X should not change font scaling on screen.
521 So compressing the X axis by 2 is not done, and this
522 appears as X scaling of 2 that no one requested. */
523 SetWindowExtEx(hdc, 100, 100, NULL);
524 SetViewportExtEx(hdc, 50, 100, NULL);
525 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
526 /* font metrics on another DC should be unchanged */
527 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
529 /* part 2: rescaling only Y should change font scaling.
530 As also X is scaled by a factor of 2, but this is not
531 requested by the DC transformation, we get a scaling factor
532 of 2 in the X coordinate. */
533 SetViewportExtEx(hdc, 100, 200, NULL);
534 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
535 /* font metrics on another DC should be unchanged */
536 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
538 /* restore scaling */
539 SetMapMode(hdc, MM_TEXT);
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 SelectObject(hdc_2, old_hfont_2);
545 DeleteDC(hdc_2);
547 if (!SetGraphicsMode(hdc, GM_ADVANCED))
549 SelectObject(hdc, old_hfont);
550 DeleteObject(hfont);
551 DeleteDC(hdc);
552 skip("GM_ADVANCED is not supported on this platform\n");
553 return;
556 xform.eM11 = 20.0f;
557 xform.eM12 = 0.0f;
558 xform.eM21 = 0.0f;
559 xform.eM22 = 20.0f;
560 xform.eDx = 0.0f;
561 xform.eDy = 0.0f;
563 SetLastError(0xdeadbeef);
564 ret = SetWorldTransform(hdc, &xform);
565 ok(ret, "SetWorldTransform error %u\n", GetLastError());
567 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
569 /* with an identity matrix */
570 memset(&gm, 0, sizeof(gm));
571 SetLastError(0xdeadbeef);
572 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
573 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
574 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
575 pt.x = width_orig; pt.y = 0;
576 LPtoDP(hdc, &pt, 1);
577 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
578 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
579 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
580 /* with a custom matrix */
581 memset(&gm, 0, sizeof(gm));
582 SetLastError(0xdeadbeef);
583 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
584 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
585 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
586 pt.x = width_orig; pt.y = 0;
587 LPtoDP(hdc, &pt, 1);
588 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
589 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
590 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
592 SetLastError(0xdeadbeef);
593 ret = SetMapMode(hdc, MM_LOMETRIC);
594 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
596 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
598 /* with an identity matrix */
599 memset(&gm, 0, sizeof(gm));
600 SetLastError(0xdeadbeef);
601 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
602 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
604 pt.x = width_orig; pt.y = 0;
605 LPtoDP(hdc, &pt, 1);
606 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
607 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
608 /* with a custom matrix */
609 memset(&gm, 0, sizeof(gm));
610 SetLastError(0xdeadbeef);
611 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
612 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
613 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
614 pt.x = width_orig; pt.y = 0;
615 LPtoDP(hdc, &pt, 1);
616 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
617 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
619 SetLastError(0xdeadbeef);
620 ret = SetMapMode(hdc, MM_TEXT);
621 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
623 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
625 /* with an identity matrix */
626 memset(&gm, 0, sizeof(gm));
627 SetLastError(0xdeadbeef);
628 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
629 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
630 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
631 pt.x = width_orig; pt.y = 0;
632 LPtoDP(hdc, &pt, 1);
633 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
634 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
635 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
636 /* with a custom matrix */
637 memset(&gm, 0, sizeof(gm));
638 SetLastError(0xdeadbeef);
639 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
640 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
641 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
642 pt.x = width_orig; pt.y = 0;
643 LPtoDP(hdc, &pt, 1);
644 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
645 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
646 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
648 SelectObject(hdc, old_hfont);
649 DeleteObject(hfont);
650 DeleteDC(hdc);
653 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
655 LOGFONT *lf = (LOGFONT *)lParam;
657 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
659 *lf = *elf;
660 return 0; /* stop enumeration */
662 return 1; /* continue enumeration */
665 static void test_bitmap_font_metrics(void)
667 static const struct font_data
669 const char face_name[LF_FACESIZE];
670 int weight, height, ascent, descent, int_leading, ext_leading;
671 int ave_char_width, max_char_width, dpi;
672 DWORD ansi_bitfield;
673 WORD skip_lang_id;
674 } fd[] =
676 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
677 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
679 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
680 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
681 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
682 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
684 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
685 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
688 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
689 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
690 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
691 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
693 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
694 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
695 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
697 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
698 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
699 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
700 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
701 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
702 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
703 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
705 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
706 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
707 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
709 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
710 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
711 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
712 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
713 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
717 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
719 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
721 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
722 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
723 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
724 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
725 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
727 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
728 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
729 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
731 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
732 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
733 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
735 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
736 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
737 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
739 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
740 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
742 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
743 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
744 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
745 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1, LANG_ARABIC },
746 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
747 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
748 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1, LANG_ARABIC },
749 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
750 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_ARABIC },
751 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
752 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1, LANG_ARABIC },
753 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
754 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_ARABIC },
755 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
757 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, FS_ARABIC },
759 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
761 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, FS_ARABIC },
762 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
765 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
766 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
767 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
768 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
769 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
770 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
771 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
772 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
773 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
774 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
775 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
777 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
778 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
779 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
781 /* The 120dpi version still has its dpi marked as 96 */
782 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
784 /* FIXME: add "Terminal" */
786 HDC hdc;
787 LOGFONT lf;
788 HFONT hfont, old_hfont;
789 TEXTMETRIC tm;
790 INT ret, i;
791 WORD system_lang_id;
793 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
795 hdc = CreateCompatibleDC(0);
796 assert(hdc);
798 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
800 int bit;
802 memset(&lf, 0, sizeof(lf));
804 lf.lfHeight = fd[i].height;
805 strcpy(lf.lfFaceName, fd[i].face_name);
807 for(bit = 0; bit < 32; bit++)
809 DWORD fs[2];
810 CHARSETINFO csi;
811 BOOL bRet;
813 fs[0] = 1L << bit;
814 fs[1] = 0;
815 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
816 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
818 lf.lfCharSet = csi.ciCharset;
819 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
820 if (ret) continue;
822 hfont = create_font(lf.lfFaceName, &lf);
823 old_hfont = SelectObject(hdc, hfont);
824 bRet = GetTextMetrics(hdc, &tm);
825 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
826 if(fd[i].dpi == tm.tmDigitizedAspectX)
828 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
829 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
831 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);
832 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);
833 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);
834 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);
835 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);
836 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);
837 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);
839 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
840 that make the max width bigger */
841 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
842 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);
844 else
845 skip("Skipping font metrics test for system langid 0x%x\n",
846 system_lang_id);
848 SelectObject(hdc, old_hfont);
849 DeleteObject(hfont);
853 DeleteDC(hdc);
856 static void test_GdiGetCharDimensions(void)
858 HDC hdc;
859 TEXTMETRICW tm;
860 LONG ret;
861 SIZE size;
862 LONG avgwidth, height;
863 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
865 if (!pGdiGetCharDimensions)
867 win_skip("GdiGetCharDimensions not available on this platform\n");
868 return;
871 hdc = CreateCompatibleDC(NULL);
873 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
874 avgwidth = ((size.cx / 26) + 1) / 2;
876 ret = pGdiGetCharDimensions(hdc, &tm, &height);
877 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
878 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
880 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
881 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
883 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
884 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
886 height = 0;
887 ret = pGdiGetCharDimensions(hdc, NULL, &height);
888 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
889 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
891 DeleteDC(hdc);
894 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
895 const TEXTMETRIC *lpntme,
896 DWORD FontType, LPARAM lParam)
898 if (FontType & TRUETYPE_FONTTYPE)
900 HFONT hfont;
902 hfont = CreateFontIndirect(lpelfe);
903 if (hfont)
905 *(HFONT *)lParam = hfont;
906 return 0;
910 return 1;
913 static void test_GetCharABCWidths(void)
915 static const WCHAR str[] = {'a',0};
916 BOOL ret;
917 HDC hdc;
918 LOGFONTA lf;
919 HFONT hfont;
920 ABC abc[1];
921 WORD glyphs[1];
922 DWORD nb;
923 static const struct
925 UINT first;
926 UINT last;
927 } range[] =
929 {0xff, 0xff},
930 {0x100, 0x100},
931 {0xff, 0x100},
932 {0x1ff, 0xff00},
933 {0xffff, 0xffff},
934 {0x10000, 0x10000},
935 {0xffff, 0x10000},
936 {0xffffff, 0xffffff},
937 {0x1000000, 0x1000000},
938 {0xffffff, 0x1000000},
939 {0xffffffff, 0xffffffff}
941 static const struct
943 UINT cs;
944 UINT a;
945 UINT w;
946 BOOL r[sizeof range / sizeof range[0]];
947 } c[] =
949 {ANSI_CHARSET, 0x30, 0x30, {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
950 {SHIFTJIS_CHARSET, 0x82a0, 0x3042, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
951 {HANGEUL_CHARSET, 0x8141, 0xac02, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
952 {JOHAB_CHARSET, 0x8446, 0x3135, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
953 {GB2312_CHARSET, 0x8141, 0x4e04, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
954 {CHINESEBIG5_CHARSET, 0xa142, 0x3001, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}}
956 UINT i;
958 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsI)
960 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
961 return;
964 memset(&lf, 0, sizeof(lf));
965 strcpy(lf.lfFaceName, "System");
966 lf.lfHeight = 20;
968 hfont = CreateFontIndirectA(&lf);
969 hdc = GetDC(0);
970 hfont = SelectObject(hdc, hfont);
972 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
973 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
975 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
976 ok(!ret, "GetCharABCWidthsI should have failed\n");
978 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
979 ok(!ret, "GetCharABCWidthsI should have failed\n");
981 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
982 ok(ret, "GetCharABCWidthsI should have succeeded\n");
984 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
985 ok(!ret, "GetCharABCWidthsW should have failed\n");
987 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
988 ok(!ret, "GetCharABCWidthsW should have failed\n");
990 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
991 ok(!ret, "GetCharABCWidthsW should have failed\n");
993 hfont = SelectObject(hdc, hfont);
994 DeleteObject(hfont);
996 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
998 ABC a[2], w[2];
999 ABC full[256];
1000 UINT code = 0x41, j;
1002 lf.lfFaceName[0] = '\0';
1003 lf.lfCharSet = c[i].cs;
1004 lf.lfPitchAndFamily = 0;
1005 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1007 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1008 continue;
1011 memset(a, 0, sizeof a);
1012 memset(w, 0, sizeof w);
1013 hfont = SelectObject(hdc, hfont);
1014 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1015 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1016 memcmp(a, w, sizeof a) == 0,
1017 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1019 memset(a, 0xbb, sizeof a);
1020 ret = pGetCharABCWidthsA(hdc, code, code, a);
1021 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1022 memset(full, 0xcc, sizeof full);
1023 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1024 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1025 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1026 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1028 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1030 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1031 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1032 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1035 hfont = SelectObject(hdc, hfont);
1036 DeleteObject(hfont);
1039 ReleaseDC(NULL, hdc);
1042 static void test_text_extents(void)
1044 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1045 LPINT extents;
1046 INT i, len, fit1, fit2;
1047 LOGFONTA lf;
1048 TEXTMETRICA tm;
1049 HDC hdc;
1050 HFONT hfont;
1051 SIZE sz;
1052 SIZE sz1, sz2;
1054 memset(&lf, 0, sizeof(lf));
1055 strcpy(lf.lfFaceName, "Arial");
1056 lf.lfHeight = 20;
1058 hfont = CreateFontIndirectA(&lf);
1059 hdc = GetDC(0);
1060 hfont = SelectObject(hdc, hfont);
1061 GetTextMetricsA(hdc, &tm);
1062 GetTextExtentPointA(hdc, "o", 1, &sz);
1063 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1065 SetLastError(0xdeadbeef);
1066 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1067 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1069 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1070 hfont = SelectObject(hdc, hfont);
1071 DeleteObject(hfont);
1072 ReleaseDC(0, hdc);
1073 return;
1076 len = lstrlenW(wt);
1077 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1078 extents[0] = 1; /* So that the increasing sequence test will fail
1079 if the extents array is untouched. */
1080 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1081 GetTextExtentPointW(hdc, wt, len, &sz2);
1082 ok(sz1.cy == sz2.cy,
1083 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1084 /* Because of the '\n' in the string GetTextExtentExPoint and
1085 GetTextExtentPoint return different widths under Win2k, but
1086 under WinXP they return the same width. So we don't test that
1087 here. */
1089 for (i = 1; i < len; ++i)
1090 ok(extents[i-1] <= extents[i],
1091 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1093 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1094 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1095 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1096 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1097 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1098 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1099 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1100 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1101 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1102 ok(extents[0] == extents[2] && extents[1] == extents[3],
1103 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1104 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1105 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1106 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1107 HeapFree(GetProcessHeap(), 0, extents);
1109 hfont = SelectObject(hdc, hfont);
1110 DeleteObject(hfont);
1111 ReleaseDC(NULL, hdc);
1114 static void test_GetGlyphIndices(void)
1116 HDC hdc;
1117 HFONT hfont;
1118 DWORD charcount;
1119 LOGFONTA lf;
1120 DWORD flags = 0;
1121 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1122 WORD glyphs[(sizeof(testtext)/2)-1];
1123 TEXTMETRIC textm;
1124 HFONT hOldFont;
1126 if (!pGetGlyphIndicesW) {
1127 win_skip("GetGlyphIndicesW not available on platform\n");
1128 return;
1131 hdc = GetDC(0);
1133 memset(&lf, 0, sizeof(lf));
1134 strcpy(lf.lfFaceName, "System");
1135 lf.lfHeight = 16;
1136 lf.lfCharSet = ANSI_CHARSET;
1138 hfont = CreateFontIndirectA(&lf);
1139 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1140 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1141 if (textm.tmCharSet == ANSI_CHARSET)
1143 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1144 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1145 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1146 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1147 flags = 0;
1148 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1149 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1150 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1151 textm.tmDefaultChar, glyphs[4]);
1153 else
1154 /* FIXME: Write tests for non-ANSI charsets. */
1155 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1157 if(!is_font_installed("Tahoma"))
1159 skip("Tahoma is not installed so skipping this test\n");
1160 return;
1162 memset(&lf, 0, sizeof(lf));
1163 strcpy(lf.lfFaceName, "Tahoma");
1164 lf.lfHeight = 20;
1166 hfont = CreateFontIndirectA(&lf);
1167 hOldFont = SelectObject(hdc, hfont);
1168 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1169 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1170 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1171 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1172 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1173 flags = 0;
1174 testtext[0] = textm.tmDefaultChar;
1175 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1176 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1177 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1178 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1179 DeleteObject(SelectObject(hdc, hOldFont));
1182 static void test_GetKerningPairs(void)
1184 static const struct kerning_data
1186 const char face_name[LF_FACESIZE];
1187 LONG height;
1188 /* some interesting fields from OUTLINETEXTMETRIC */
1189 LONG tmHeight, tmAscent, tmDescent;
1190 UINT otmEMSquare;
1191 INT otmAscent;
1192 INT otmDescent;
1193 UINT otmLineGap;
1194 UINT otmsCapEmHeight;
1195 UINT otmsXHeight;
1196 INT otmMacAscent;
1197 INT otmMacDescent;
1198 UINT otmMacLineGap;
1199 UINT otmusMinimumPPEM;
1200 /* small subset of kerning pairs to test */
1201 DWORD total_kern_pairs;
1202 const KERNINGPAIR kern_pair[26];
1203 } kd[] =
1205 {"Arial", 12, 12, 9, 3,
1206 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1209 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1210 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1211 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1212 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1213 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1214 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1215 {933,970,+1},{933,972,-1}
1218 {"Arial", -34, 39, 32, 7,
1219 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1222 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1223 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1224 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1225 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1226 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1227 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1228 {933,970,+2},{933,972,-3}
1231 { "Arial", 120, 120, 97, 23,
1232 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1235 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1236 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1237 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1238 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1239 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1240 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1241 {933,970,+6},{933,972,-10}
1244 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1245 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1246 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1249 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1250 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1251 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1252 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1253 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1254 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1255 {933,970,+54},{933,972,-83}
1258 #endif
1260 LOGFONT lf;
1261 HFONT hfont, hfont_old;
1262 KERNINGPAIR *kern_pair;
1263 HDC hdc;
1264 DWORD total_kern_pairs, ret, i, n, matches;
1266 hdc = GetDC(0);
1268 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1269 * which may render this test unusable, so we're trying to avoid that.
1271 SetLastError(0xdeadbeef);
1272 GetKerningPairsW(hdc, 0, NULL);
1273 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1275 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1276 ReleaseDC(0, hdc);
1277 return;
1280 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1282 OUTLINETEXTMETRICW otm;
1283 UINT uiRet;
1285 if (!is_font_installed(kd[i].face_name))
1287 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1288 continue;
1291 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1293 memset(&lf, 0, sizeof(lf));
1294 strcpy(lf.lfFaceName, kd[i].face_name);
1295 lf.lfHeight = kd[i].height;
1296 hfont = CreateFontIndirect(&lf);
1297 assert(hfont != 0);
1299 hfont_old = SelectObject(hdc, hfont);
1301 SetLastError(0xdeadbeef);
1302 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1303 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1304 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1306 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1307 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1308 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1309 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1310 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1311 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1313 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1314 kd[i].otmEMSquare, otm.otmEMSquare);
1315 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1316 kd[i].otmAscent, otm.otmAscent);
1317 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1318 kd[i].otmDescent, otm.otmDescent);
1319 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1320 kd[i].otmLineGap, otm.otmLineGap);
1321 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1322 kd[i].otmMacDescent, otm.otmMacDescent);
1323 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1324 kd[i].otmMacAscent, otm.otmMacAscent);
1325 todo_wine {
1326 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1327 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1328 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1329 kd[i].otmsXHeight, otm.otmsXHeight);
1330 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1331 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1332 kd[i].otmMacLineGap, otm.otmMacLineGap);
1333 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1334 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1337 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1338 trace("total_kern_pairs %u\n", total_kern_pairs);
1339 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1341 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1342 SetLastError(0xdeadbeef);
1343 ret = GetKerningPairsW(hdc, 0, kern_pair);
1344 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1345 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1346 ok(ret == 0, "got %lu, expected 0\n", ret);
1347 #endif
1349 ret = GetKerningPairsW(hdc, 100, NULL);
1350 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1352 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1353 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1355 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1356 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1358 matches = 0;
1360 for (n = 0; n < ret; n++)
1362 DWORD j;
1363 #if 0
1364 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1365 trace("{'%c','%c',%d},\n",
1366 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1367 #endif
1368 for (j = 0; j < kd[i].total_kern_pairs; j++)
1370 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1371 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1373 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1374 "pair %d:%d got %d, expected %d\n",
1375 kern_pair[n].wFirst, kern_pair[n].wSecond,
1376 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1377 matches++;
1382 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1383 matches, kd[i].total_kern_pairs);
1385 HeapFree(GetProcessHeap(), 0, kern_pair);
1387 SelectObject(hdc, hfont_old);
1388 DeleteObject(hfont);
1391 ReleaseDC(0, hdc);
1394 static void test_height_selection(void)
1396 static const struct font_data
1398 const char face_name[LF_FACESIZE];
1399 int requested_height;
1400 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1401 } fd[] =
1403 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1404 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1405 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1406 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1407 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1408 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1409 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1410 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1411 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1412 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1414 HDC hdc;
1415 LOGFONT lf;
1416 HFONT hfont, old_hfont;
1417 TEXTMETRIC tm;
1418 INT ret, i;
1420 hdc = CreateCompatibleDC(0);
1421 assert(hdc);
1423 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1425 if (!is_truetype_font_installed(fd[i].face_name))
1427 skip("%s is not installed\n", fd[i].face_name);
1428 continue;
1431 memset(&lf, 0, sizeof(lf));
1432 lf.lfHeight = fd[i].requested_height;
1433 lf.lfWeight = fd[i].weight;
1434 strcpy(lf.lfFaceName, fd[i].face_name);
1436 hfont = CreateFontIndirect(&lf);
1437 assert(hfont);
1439 old_hfont = SelectObject(hdc, hfont);
1440 ret = GetTextMetrics(hdc, &tm);
1441 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1442 if(fd[i].dpi == tm.tmDigitizedAspectX)
1444 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1445 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);
1446 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);
1447 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);
1448 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);
1449 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1450 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);
1451 #endif
1452 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);
1455 SelectObject(hdc, old_hfont);
1456 DeleteObject(hfont);
1459 DeleteDC(hdc);
1462 static void test_GetOutlineTextMetrics(void)
1464 OUTLINETEXTMETRIC *otm;
1465 LOGFONT lf;
1466 HFONT hfont, hfont_old;
1467 HDC hdc;
1468 DWORD ret, otm_size;
1469 LPSTR unset_ptr;
1471 if (!is_font_installed("Arial"))
1473 skip("Arial is not installed\n");
1474 return;
1477 hdc = GetDC(0);
1479 memset(&lf, 0, sizeof(lf));
1480 strcpy(lf.lfFaceName, "Arial");
1481 lf.lfHeight = -13;
1482 lf.lfWeight = FW_NORMAL;
1483 lf.lfPitchAndFamily = DEFAULT_PITCH;
1484 lf.lfQuality = PROOF_QUALITY;
1485 hfont = CreateFontIndirect(&lf);
1486 assert(hfont != 0);
1488 hfont_old = SelectObject(hdc, hfont);
1489 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1490 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1492 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1494 memset(otm, 0xAA, otm_size);
1495 SetLastError(0xdeadbeef);
1496 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1497 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1498 ok(ret == 1 /* Win9x */ ||
1499 ret == otm->otmSize /* XP*/,
1500 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1501 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1503 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1504 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1505 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1506 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1509 memset(otm, 0xAA, otm_size);
1510 SetLastError(0xdeadbeef);
1511 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1512 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1513 ok(ret == 1 /* Win9x */ ||
1514 ret == otm->otmSize /* XP*/,
1515 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1516 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1518 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1519 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1520 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1521 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1524 /* ask about truncated data */
1525 memset(otm, 0xAA, otm_size);
1526 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1527 SetLastError(0xdeadbeef);
1528 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1529 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1530 ok(ret == 1 /* Win9x */ ||
1531 ret == otm->otmSize /* XP*/,
1532 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1533 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1535 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1536 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1537 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1539 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1541 HeapFree(GetProcessHeap(), 0, otm);
1543 SelectObject(hdc, hfont_old);
1544 DeleteObject(hfont);
1546 ReleaseDC(0, hdc);
1549 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1551 INT y,
1552 breakCount,
1553 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1554 areaWidth = clientArea->right - clientArea->left,
1555 nErrors = 0, e;
1556 BOOL lastExtent = FALSE;
1557 PSTR pFirstChar, pLastChar;
1558 SIZE size;
1559 TEXTMETRICA tm;
1560 struct err
1562 char extent[100];
1563 int GetTextExtentExPointWWidth;
1564 } error[10];
1566 GetTextMetricsA(hdc, &tm);
1567 y = clientArea->top;
1568 do {
1569 breakCount = 0;
1570 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1571 pFirstChar = str;
1573 do {
1574 pLastChar = str;
1576 /* if not at the end of the string, ... */
1577 if (*str == '\0') break;
1578 /* ... add the next word to the current extent */
1579 while (*str != '\0' && *str++ != tm.tmBreakChar);
1580 breakCount++;
1581 SetTextJustification(hdc, 0, 0);
1582 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1583 } while ((int) size.cx < areaWidth);
1585 /* ignore trailing break chars */
1586 breakCount--;
1587 while (*(pLastChar - 1) == tm.tmBreakChar)
1589 pLastChar--;
1590 breakCount--;
1593 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1595 SetTextJustification(hdc, 0, 0);
1596 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1598 /* do not justify the last extent */
1599 if (*str != '\0' && breakCount > 0)
1601 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1602 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1603 justifiedWidth = size.cx;
1605 else lastExtent = TRUE;
1607 /* catch errors and report them */
1608 if (!lastExtent && (justifiedWidth != areaWidth))
1610 memset(error[nErrors].extent, 0, 100);
1611 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1612 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1613 nErrors++;
1616 y += size.cy;
1617 str = pLastChar;
1618 } while (*str && y < clientArea->bottom);
1620 for (e = 0; e < nErrors; e++)
1622 /* The width returned by GetTextExtentPoint32() is exactly the same
1623 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1624 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1625 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1626 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1630 static void test_SetTextJustification(void)
1632 HDC hdc;
1633 RECT clientArea;
1634 LOGFONTA lf;
1635 HFONT hfont;
1636 HWND hwnd;
1637 static char testText[] =
1638 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1639 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1640 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1641 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1642 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1643 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1644 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1646 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1647 GetClientRect( hwnd, &clientArea );
1648 hdc = GetDC( hwnd );
1650 memset(&lf, 0, sizeof lf);
1651 lf.lfCharSet = ANSI_CHARSET;
1652 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1653 lf.lfWeight = FW_DONTCARE;
1654 lf.lfHeight = 20;
1655 lf.lfQuality = DEFAULT_QUALITY;
1656 lstrcpyA(lf.lfFaceName, "Times New Roman");
1657 hfont = create_font("Times New Roman", &lf);
1658 SelectObject(hdc, hfont);
1660 testJustification(hdc, testText, &clientArea);
1662 DeleteObject(hfont);
1663 ReleaseDC(hwnd, hdc);
1664 DestroyWindow(hwnd);
1667 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1669 HDC hdc;
1670 LOGFONTA lf;
1671 HFONT hfont, hfont_old;
1672 CHARSETINFO csi;
1673 FONTSIGNATURE fs;
1674 INT cs;
1675 DWORD i, ret;
1676 char name[64];
1678 assert(count <= 128);
1680 memset(&lf, 0, sizeof(lf));
1682 lf.lfCharSet = charset;
1683 lf.lfHeight = 10;
1684 lstrcpyA(lf.lfFaceName, "Arial");
1685 SetLastError(0xdeadbeef);
1686 hfont = CreateFontIndirectA(&lf);
1687 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1689 hdc = GetDC(0);
1690 hfont_old = SelectObject(hdc, hfont);
1692 cs = GetTextCharsetInfo(hdc, &fs, 0);
1693 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1695 SetLastError(0xdeadbeef);
1696 ret = GetTextFaceA(hdc, sizeof(name), name);
1697 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1699 if (charset == SYMBOL_CHARSET)
1701 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1702 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1704 else
1706 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1707 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1710 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1712 trace("Can't find codepage for charset %d\n", cs);
1713 ReleaseDC(0, hdc);
1714 return FALSE;
1716 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1718 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1720 skip("Font code page %d, looking for code page %d\n",
1721 pGdiGetCodePage(hdc), code_page);
1722 ReleaseDC(0, hdc);
1723 return FALSE;
1726 if (unicode)
1728 char ansi_buf[128];
1729 WCHAR unicode_buf[128];
1731 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1733 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1735 SetLastError(0xdeadbeef);
1736 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1737 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1738 count, ret, GetLastError());
1740 else
1742 char ansi_buf[128];
1744 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1746 SetLastError(0xdeadbeef);
1747 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1748 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1749 count, ret, GetLastError());
1752 SelectObject(hdc, hfont_old);
1753 DeleteObject(hfont);
1755 ReleaseDC(0, hdc);
1757 return TRUE;
1760 static void test_font_charset(void)
1762 static struct charset_data
1764 INT charset;
1765 UINT code_page;
1766 WORD font_idxA[128], font_idxW[128];
1767 } cd[] =
1769 { ANSI_CHARSET, 1252 },
1770 { RUSSIAN_CHARSET, 1251 },
1771 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1773 int i;
1775 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1777 win_skip("Skipping the font charset test on a Win9x platform\n");
1778 return;
1781 if (!is_font_installed("Arial"))
1783 skip("Arial is not installed\n");
1784 return;
1787 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1789 if (cd[i].charset == SYMBOL_CHARSET)
1791 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1793 skip("Symbol or Wingdings is not installed\n");
1794 break;
1797 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1798 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1799 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1802 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1803 if (i > 2)
1805 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1806 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1808 else
1809 skip("Symbol or Wingdings is not installed\n");
1812 static void test_GetFontUnicodeRanges(void)
1814 LOGFONTA lf;
1815 HDC hdc;
1816 HFONT hfont, hfont_old;
1817 DWORD size;
1818 GLYPHSET *gs;
1820 if (!pGetFontUnicodeRanges)
1822 win_skip("GetFontUnicodeRanges not available before W2K\n");
1823 return;
1826 memset(&lf, 0, sizeof(lf));
1827 lstrcpyA(lf.lfFaceName, "Arial");
1828 hfont = create_font("Arial", &lf);
1830 hdc = GetDC(0);
1831 hfont_old = SelectObject(hdc, hfont);
1833 size = pGetFontUnicodeRanges(NULL, NULL);
1834 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1836 size = pGetFontUnicodeRanges(hdc, NULL);
1837 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1839 gs = HeapAlloc(GetProcessHeap(), 0, size);
1841 size = pGetFontUnicodeRanges(hdc, gs);
1842 ok(size, "GetFontUnicodeRanges failed\n");
1843 #if 0
1844 for (i = 0; i < gs->cRanges; i++)
1845 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1846 #endif
1847 trace("found %u ranges\n", gs->cRanges);
1849 HeapFree(GetProcessHeap(), 0, gs);
1851 SelectObject(hdc, hfont_old);
1852 DeleteObject(hfont);
1853 ReleaseDC(NULL, hdc);
1856 #define MAX_ENUM_FONTS 4096
1858 struct enum_font_data
1860 int total;
1861 LOGFONT lf[MAX_ENUM_FONTS];
1864 struct enum_font_dataW
1866 int total;
1867 LOGFONTW lf[MAX_ENUM_FONTS];
1870 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1872 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1874 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1876 if (type != TRUETYPE_FONTTYPE) return 1;
1877 #if 0
1878 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1879 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1880 #endif
1881 if (efd->total < MAX_ENUM_FONTS)
1882 efd->lf[efd->total++] = *lf;
1883 else
1884 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1886 return 1;
1889 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1891 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1893 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1895 if (type != TRUETYPE_FONTTYPE) return 1;
1896 #if 0
1897 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1898 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1899 #endif
1900 if (efd->total < MAX_ENUM_FONTS)
1901 efd->lf[efd->total++] = *lf;
1902 else
1903 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1905 return 1;
1908 static void get_charset_stats(struct enum_font_data *efd,
1909 int *ansi_charset, int *symbol_charset,
1910 int *russian_charset)
1912 int i;
1914 *ansi_charset = 0;
1915 *symbol_charset = 0;
1916 *russian_charset = 0;
1918 for (i = 0; i < efd->total; i++)
1920 switch (efd->lf[i].lfCharSet)
1922 case ANSI_CHARSET:
1923 (*ansi_charset)++;
1924 break;
1925 case SYMBOL_CHARSET:
1926 (*symbol_charset)++;
1927 break;
1928 case RUSSIAN_CHARSET:
1929 (*russian_charset)++;
1930 break;
1935 static void get_charset_statsW(struct enum_font_dataW *efd,
1936 int *ansi_charset, int *symbol_charset,
1937 int *russian_charset)
1939 int i;
1941 *ansi_charset = 0;
1942 *symbol_charset = 0;
1943 *russian_charset = 0;
1945 for (i = 0; i < efd->total; i++)
1947 switch (efd->lf[i].lfCharSet)
1949 case ANSI_CHARSET:
1950 (*ansi_charset)++;
1951 break;
1952 case SYMBOL_CHARSET:
1953 (*symbol_charset)++;
1954 break;
1955 case RUSSIAN_CHARSET:
1956 (*russian_charset)++;
1957 break;
1962 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1964 struct enum_font_data efd;
1965 struct enum_font_dataW efdw;
1966 LOGFONT lf;
1967 HDC hdc;
1968 int i, ret, ansi_charset, symbol_charset, russian_charset;
1970 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1972 if (*font_name && !is_truetype_font_installed(font_name))
1974 skip("%s is not installed\n", font_name);
1975 return;
1978 hdc = GetDC(0);
1980 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1981 * while EnumFontFamiliesEx doesn't.
1983 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1986 * Use EnumFontFamiliesW since win98 crashes when the
1987 * second parameter is NULL using EnumFontFamilies
1989 efdw.total = 0;
1990 SetLastError(0xdeadbeef);
1991 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1992 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1993 if(ret)
1995 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1996 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1997 ansi_charset, symbol_charset, russian_charset);
1998 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1999 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2000 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2001 ok(russian_charset > 0 ||
2002 broken(russian_charset == 0), /* NT4 */
2003 "NULL family should enumerate RUSSIAN_CHARSET\n");
2006 efdw.total = 0;
2007 SetLastError(0xdeadbeef);
2008 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2009 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2010 if(ret)
2012 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2013 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2014 ansi_charset, symbol_charset, russian_charset);
2015 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2016 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2017 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2018 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2022 efd.total = 0;
2023 SetLastError(0xdeadbeef);
2024 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2025 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2026 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2027 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2028 ansi_charset, symbol_charset, russian_charset,
2029 *font_name ? font_name : "<empty>");
2030 if (*font_name)
2031 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2032 else
2033 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2034 for (i = 0; i < efd.total; i++)
2036 /* FIXME: remove completely once Wine is fixed */
2037 if (efd.lf[i].lfCharSet != font_charset)
2039 todo_wine
2040 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2042 else
2043 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2044 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2045 font_name, efd.lf[i].lfFaceName);
2048 memset(&lf, 0, sizeof(lf));
2049 lf.lfCharSet = ANSI_CHARSET;
2050 lstrcpy(lf.lfFaceName, font_name);
2051 efd.total = 0;
2052 SetLastError(0xdeadbeef);
2053 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2054 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2055 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2056 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2057 ansi_charset, symbol_charset, russian_charset,
2058 *font_name ? font_name : "<empty>");
2059 if (font_charset == SYMBOL_CHARSET)
2061 if (*font_name)
2062 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2063 else
2064 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2066 else
2068 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2069 for (i = 0; i < efd.total; i++)
2071 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2072 if (*font_name)
2073 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2074 font_name, efd.lf[i].lfFaceName);
2078 /* DEFAULT_CHARSET should enumerate all available charsets */
2079 memset(&lf, 0, sizeof(lf));
2080 lf.lfCharSet = DEFAULT_CHARSET;
2081 lstrcpy(lf.lfFaceName, font_name);
2082 efd.total = 0;
2083 SetLastError(0xdeadbeef);
2084 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2085 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2086 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2087 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2088 ansi_charset, symbol_charset, russian_charset,
2089 *font_name ? font_name : "<empty>");
2090 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2091 for (i = 0; i < efd.total; i++)
2093 if (*font_name)
2094 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2095 font_name, efd.lf[i].lfFaceName);
2097 if (*font_name)
2099 switch (font_charset)
2101 case ANSI_CHARSET:
2102 ok(ansi_charset > 0,
2103 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2104 ok(!symbol_charset,
2105 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2106 ok(russian_charset > 0,
2107 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2108 break;
2109 case SYMBOL_CHARSET:
2110 ok(!ansi_charset,
2111 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2112 ok(symbol_charset,
2113 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2114 ok(!russian_charset,
2115 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2116 break;
2117 case DEFAULT_CHARSET:
2118 ok(ansi_charset > 0,
2119 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2120 ok(symbol_charset > 0,
2121 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2122 ok(russian_charset > 0,
2123 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2124 break;
2127 else
2129 ok(ansi_charset > 0,
2130 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2131 ok(symbol_charset > 0,
2132 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2133 ok(russian_charset > 0,
2134 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2137 memset(&lf, 0, sizeof(lf));
2138 lf.lfCharSet = SYMBOL_CHARSET;
2139 lstrcpy(lf.lfFaceName, font_name);
2140 efd.total = 0;
2141 SetLastError(0xdeadbeef);
2142 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2143 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2144 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2145 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2146 ansi_charset, symbol_charset, russian_charset,
2147 *font_name ? font_name : "<empty>");
2148 if (*font_name && font_charset == ANSI_CHARSET)
2149 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2150 else
2152 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2153 for (i = 0; i < efd.total; i++)
2155 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2156 if (*font_name)
2157 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2158 font_name, efd.lf[i].lfFaceName);
2161 ok(!ansi_charset,
2162 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2163 ok(symbol_charset > 0,
2164 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2165 ok(!russian_charset,
2166 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2169 ReleaseDC(0, hdc);
2172 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2174 HFONT hfont, hfont_prev;
2175 DWORD ret;
2176 GLYPHMETRICS gm1, gm2;
2177 LOGFONTA lf2 = *lf;
2178 WORD idx;
2180 if(!pGetGlyphIndicesA)
2181 return;
2183 /* negative widths are handled just as positive ones */
2184 lf2.lfWidth = -lf->lfWidth;
2186 SetLastError(0xdeadbeef);
2187 hfont = CreateFontIndirectA(lf);
2188 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2189 check_font("original", lf, hfont);
2191 hfont_prev = SelectObject(hdc, hfont);
2193 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2194 if (ret == GDI_ERROR || idx == 0xffff)
2196 SelectObject(hdc, hfont_prev);
2197 DeleteObject(hfont);
2198 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2199 return;
2202 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2203 memset(&gm1, 0xab, sizeof(gm1));
2204 SetLastError(0xdeadbeef);
2205 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2206 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2208 SelectObject(hdc, hfont_prev);
2209 DeleteObject(hfont);
2211 SetLastError(0xdeadbeef);
2212 hfont = CreateFontIndirectA(&lf2);
2213 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2214 check_font("negative width", &lf2, hfont);
2216 hfont_prev = SelectObject(hdc, hfont);
2218 memset(&gm2, 0xbb, sizeof(gm2));
2219 SetLastError(0xdeadbeef);
2220 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2221 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2223 SelectObject(hdc, hfont_prev);
2224 DeleteObject(hfont);
2226 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2227 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2228 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2229 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2230 gm1.gmCellIncX == gm2.gmCellIncX &&
2231 gm1.gmCellIncY == gm2.gmCellIncY,
2232 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2233 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2234 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2235 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2236 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2239 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2240 #include "pshpack2.h"
2241 typedef struct
2243 USHORT version;
2244 SHORT xAvgCharWidth;
2245 USHORT usWeightClass;
2246 USHORT usWidthClass;
2247 SHORT fsType;
2248 SHORT ySubscriptXSize;
2249 SHORT ySubscriptYSize;
2250 SHORT ySubscriptXOffset;
2251 SHORT ySubscriptYOffset;
2252 SHORT ySuperscriptXSize;
2253 SHORT ySuperscriptYSize;
2254 SHORT ySuperscriptXOffset;
2255 SHORT ySuperscriptYOffset;
2256 SHORT yStrikeoutSize;
2257 SHORT yStrikeoutPosition;
2258 SHORT sFamilyClass;
2259 PANOSE panose;
2260 ULONG ulUnicodeRange1;
2261 ULONG ulUnicodeRange2;
2262 ULONG ulUnicodeRange3;
2263 ULONG ulUnicodeRange4;
2264 CHAR achVendID[4];
2265 USHORT fsSelection;
2266 USHORT usFirstCharIndex;
2267 USHORT usLastCharIndex;
2268 /* According to the Apple spec, original version didn't have the below fields,
2269 * version numbers were taked from the OpenType spec.
2271 /* version 0 (TrueType 1.5) */
2272 USHORT sTypoAscender;
2273 USHORT sTypoDescender;
2274 USHORT sTypoLineGap;
2275 USHORT usWinAscent;
2276 USHORT usWinDescent;
2277 /* version 1 (TrueType 1.66) */
2278 ULONG ulCodePageRange1;
2279 ULONG ulCodePageRange2;
2280 /* version 2 (OpenType 1.2) */
2281 SHORT sxHeight;
2282 SHORT sCapHeight;
2283 USHORT usDefaultChar;
2284 USHORT usBreakChar;
2285 USHORT usMaxContext;
2286 } TT_OS2_V2;
2287 #include "poppack.h"
2289 #ifdef WORDS_BIGENDIAN
2290 #define GET_BE_WORD(x) (x)
2291 #define GET_BE_DWORD(x) (x)
2292 #else
2293 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2294 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2295 #endif
2297 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2298 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2299 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2300 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2301 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2303 typedef struct
2305 USHORT version;
2306 USHORT num_tables;
2307 } cmap_header;
2309 typedef struct
2311 USHORT plat_id;
2312 USHORT enc_id;
2313 ULONG offset;
2314 } cmap_encoding_record;
2316 typedef struct
2318 USHORT format;
2319 USHORT length;
2320 USHORT language;
2322 BYTE glyph_ids[256];
2323 } cmap_format_0;
2325 typedef struct
2327 USHORT format;
2328 USHORT length;
2329 USHORT language;
2331 USHORT seg_countx2;
2332 USHORT search_range;
2333 USHORT entry_selector;
2334 USHORT range_shift;
2336 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2337 /* Then follows:
2338 USHORT pad;
2339 USHORT start_count[seg_countx2 / 2];
2340 USHORT id_delta[seg_countx2 / 2];
2341 USHORT id_range_offset[seg_countx2 / 2];
2342 USHORT glyph_ids[];
2344 } cmap_format_4;
2346 typedef struct
2348 USHORT end_count;
2349 USHORT start_count;
2350 USHORT id_delta;
2351 USHORT id_range_offset;
2352 } cmap_format_4_seg;
2354 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2356 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2357 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2358 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2359 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2360 os2->panose.bWeight, os2->panose.bProportion);
2363 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2365 int i;
2366 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2368 *first = 256;
2370 for(i = 0; i < 256; i++)
2372 if(cmap->glyph_ids[i] == 0) continue;
2373 *last = i;
2374 if(*first == 256) *first = i;
2376 if(*first == 256) return FALSE;
2377 return TRUE;
2380 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2382 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2383 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2384 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2385 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2386 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2389 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2391 int i;
2392 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2393 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2394 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2396 *first = 0x10000;
2398 for(i = 0; i < seg_count; i++)
2400 DWORD code, index;
2401 cmap_format_4_seg seg;
2403 get_seg4(cmap, i, &seg);
2404 for(code = seg.start_count; code <= seg.end_count; code++)
2406 if(seg.id_range_offset == 0)
2407 index = (seg.id_delta + code) & 0xffff;
2408 else
2410 index = seg.id_range_offset / 2
2411 + code - seg.start_count
2412 + i - seg_count;
2414 /* some fonts have broken last segment */
2415 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2416 index = GET_BE_WORD(glyph_ids[index]);
2417 else
2419 trace("segment %04x/%04x index %04x points to nowhere\n",
2420 seg.start_count, seg.end_count, index);
2421 index = 0;
2423 if(index) index += seg.id_delta;
2425 if(*first == 0x10000)
2426 *last = *first = code;
2427 else if(index)
2428 *last = code;
2432 if(*first == 0x10000) return FALSE;
2433 return TRUE;
2436 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2438 USHORT i;
2439 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2441 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2443 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2444 return (BYTE *)header + GET_BE_DWORD(record->offset);
2445 record++;
2447 return NULL;
2450 typedef enum
2452 cmap_none,
2453 cmap_ms_unicode,
2454 cmap_ms_symbol
2455 } cmap_type;
2457 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2459 LONG size, ret;
2460 cmap_header *header;
2461 void *cmap;
2462 BOOL r = FALSE;
2463 WORD format;
2465 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2466 ok(size != GDI_ERROR, "no cmap table found\n");
2467 if(size == GDI_ERROR) return FALSE;
2469 header = HeapAlloc(GetProcessHeap(), 0, size);
2470 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2471 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2472 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2474 cmap = get_cmap(header, 3, 1);
2475 if(cmap)
2476 *cmap_type = cmap_ms_unicode;
2477 else
2479 cmap = get_cmap(header, 3, 0);
2480 if(cmap) *cmap_type = cmap_ms_symbol;
2482 if(!cmap)
2484 *cmap_type = cmap_none;
2485 goto end;
2488 format = GET_BE_WORD(*(WORD *)cmap);
2489 switch(format)
2491 case 0:
2492 r = get_first_last_from_cmap0(cmap, first, last);
2493 break;
2494 case 4:
2495 r = get_first_last_from_cmap4(cmap, first, last, size);
2496 break;
2497 default:
2498 trace("unhandled cmap format %d\n", format);
2499 break;
2502 end:
2503 HeapFree(GetProcessHeap(), 0, header);
2504 return r;
2507 static void test_text_metrics(const LOGFONTA *lf)
2509 HDC hdc;
2510 HFONT hfont, hfont_old;
2511 TEXTMETRICA tmA;
2512 TT_OS2_V2 tt_os2;
2513 LONG size, ret;
2514 const char *font_name = lf->lfFaceName;
2515 DWORD cmap_first = 0, cmap_last = 0;
2516 cmap_type cmap_type;
2517 BOOL sys_lang_non_english;
2519 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2520 hdc = GetDC(0);
2522 SetLastError(0xdeadbeef);
2523 hfont = CreateFontIndirectA(lf);
2524 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2526 hfont_old = SelectObject(hdc, hfont);
2528 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2529 if (size == GDI_ERROR)
2531 trace("OS/2 chunk was not found\n");
2532 goto end_of_test;
2534 if (size > sizeof(tt_os2))
2536 trace("got too large OS/2 chunk of size %u\n", size);
2537 size = sizeof(tt_os2);
2540 memset(&tt_os2, 0, sizeof(tt_os2));
2541 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2542 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2544 SetLastError(0xdeadbeef);
2545 ret = GetTextMetricsA(hdc, &tmA);
2546 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2548 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2550 skip("Unable to retrieve first and last glyphs from cmap\n");
2552 else
2554 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2555 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2556 UINT os2_first_char, os2_last_char, default_char, break_char;
2557 USHORT version;
2558 TEXTMETRICW tmW;
2560 version = GET_BE_WORD(tt_os2.version);
2562 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2563 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2564 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2565 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2567 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2568 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2569 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2571 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2573 expect_first_W = 0;
2574 switch(GetACP())
2576 case 1257: /* Baltic */
2577 expect_last_W = 0xf8fd;
2578 break;
2579 default:
2580 expect_last_W = 0xf0ff;
2582 expect_break_W = 0x20;
2583 expect_default_W = expect_break_W - 1;
2584 expect_first_A = 0x1e;
2585 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2587 else
2589 expect_first_W = cmap_first;
2590 expect_last_W = min(cmap_last, os2_last_char);
2591 if(os2_first_char <= 1)
2592 expect_break_W = os2_first_char + 2;
2593 else if(os2_first_char > 0xff)
2594 expect_break_W = 0x20;
2595 else
2596 expect_break_W = os2_first_char;
2597 expect_default_W = expect_break_W - 1;
2598 expect_first_A = expect_default_W - 1;
2599 expect_last_A = min(expect_last_W, 0xff);
2601 expect_break_A = expect_break_W;
2602 expect_default_A = expect_default_W;
2604 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2605 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2606 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2607 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2608 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2609 else
2610 ok(tmA.tmFirstChar == expect_first_A ||
2611 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2612 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2613 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2614 ok(tmA.tmLastChar == expect_last_A ||
2615 tmA.tmLastChar == 0xff /* win9x */,
2616 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2617 else
2618 skip("tmLastChar is DBCS lead byte\n");
2619 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2620 font_name, tmA.tmBreakChar, expect_break_A);
2621 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2622 "A: tmDefaultChar for %s got %02x expected %02x\n",
2623 font_name, tmA.tmDefaultChar, expect_default_A);
2626 SetLastError(0xdeadbeef);
2627 ret = GetTextMetricsW(hdc, &tmW);
2628 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2629 "GetTextMetricsW error %u\n", GetLastError());
2630 if (ret)
2632 /* Wine uses the os2 first char */
2633 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2634 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2635 font_name, tmW.tmFirstChar, expect_first_W);
2636 else
2637 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2638 font_name, tmW.tmFirstChar, expect_first_W);
2640 /* Wine uses the os2 last char */
2641 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2642 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2643 font_name, tmW.tmLastChar, expect_last_W);
2644 else
2645 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2646 font_name, tmW.tmLastChar, expect_last_W);
2647 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2648 font_name, tmW.tmBreakChar, expect_break_W);
2649 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2650 "W: tmDefaultChar for %s got %02x expected %02x\n",
2651 font_name, tmW.tmDefaultChar, expect_default_W);
2653 /* Test the aspect ratio while we have tmW */
2654 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2655 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2656 tmW.tmDigitizedAspectX, ret);
2657 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2658 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2659 tmW.tmDigitizedAspectX, ret);
2663 /* test FF_ values */
2664 switch(tt_os2.panose.bFamilyType)
2666 case PAN_ANY:
2667 case PAN_NO_FIT:
2668 case PAN_FAMILY_TEXT_DISPLAY:
2669 case PAN_FAMILY_PICTORIAL:
2670 default:
2671 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2672 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2674 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2675 break;
2677 switch(tt_os2.panose.bSerifStyle)
2679 case PAN_ANY:
2680 case PAN_NO_FIT:
2681 default:
2682 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2683 break;
2685 case PAN_SERIF_COVE:
2686 case PAN_SERIF_OBTUSE_COVE:
2687 case PAN_SERIF_SQUARE_COVE:
2688 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2689 case PAN_SERIF_SQUARE:
2690 case PAN_SERIF_THIN:
2691 case PAN_SERIF_BONE:
2692 case PAN_SERIF_EXAGGERATED:
2693 case PAN_SERIF_TRIANGLE:
2694 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2695 break;
2697 case PAN_SERIF_NORMAL_SANS:
2698 case PAN_SERIF_OBTUSE_SANS:
2699 case PAN_SERIF_PERP_SANS:
2700 case PAN_SERIF_FLARED:
2701 case PAN_SERIF_ROUNDED:
2702 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2703 break;
2705 break;
2707 case PAN_FAMILY_SCRIPT:
2708 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2709 break;
2711 case PAN_FAMILY_DECORATIVE:
2712 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2713 break;
2716 test_negative_width(hdc, lf);
2718 end_of_test:
2719 SelectObject(hdc, hfont_old);
2720 DeleteObject(hfont);
2722 ReleaseDC(0, hdc);
2725 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2727 INT *enumed = (INT *)lParam;
2729 if (type == TRUETYPE_FONTTYPE)
2731 (*enumed)++;
2732 test_text_metrics(lf);
2734 return 1;
2737 static void test_GetTextMetrics(void)
2739 LOGFONTA lf;
2740 HDC hdc;
2741 INT enumed;
2743 /* Report only once */
2744 if(!pGetGlyphIndicesA)
2745 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2747 hdc = GetDC(0);
2749 memset(&lf, 0, sizeof(lf));
2750 lf.lfCharSet = DEFAULT_CHARSET;
2751 enumed = 0;
2752 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2753 trace("Tested metrics of %d truetype fonts\n", enumed);
2755 ReleaseDC(0, hdc);
2758 static void test_nonexistent_font(void)
2760 static const struct
2762 const char *name;
2763 int charset;
2764 } font_subst[] =
2766 { "Times New Roman Baltic", 186 },
2767 { "Times New Roman CE", 238 },
2768 { "Times New Roman CYR", 204 },
2769 { "Times New Roman Greek", 161 },
2770 { "Times New Roman TUR", 162 }
2772 LOGFONTA lf;
2773 HDC hdc;
2774 HFONT hfont;
2775 CHARSETINFO csi;
2776 INT cs, expected_cs, i;
2777 char buf[LF_FACESIZE];
2779 if (!is_truetype_font_installed("Arial") ||
2780 !is_truetype_font_installed("Times New Roman"))
2782 skip("Arial or Times New Roman not installed\n");
2783 return;
2786 expected_cs = GetACP();
2787 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2789 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2790 return;
2792 expected_cs = csi.ciCharset;
2793 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2795 hdc = GetDC(0);
2797 memset(&lf, 0, sizeof(lf));
2798 lf.lfHeight = 100;
2799 lf.lfWeight = FW_REGULAR;
2800 lf.lfCharSet = ANSI_CHARSET;
2801 lf.lfPitchAndFamily = FF_SWISS;
2802 strcpy(lf.lfFaceName, "Nonexistent font");
2803 hfont = CreateFontIndirectA(&lf);
2804 hfont = SelectObject(hdc, hfont);
2805 GetTextFaceA(hdc, sizeof(buf), buf);
2806 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2807 cs = GetTextCharset(hdc);
2808 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2809 DeleteObject(SelectObject(hdc, hfont));
2811 memset(&lf, 0, sizeof(lf));
2812 lf.lfHeight = -13;
2813 lf.lfWeight = FW_DONTCARE;
2814 strcpy(lf.lfFaceName, "Nonexistent font");
2815 hfont = CreateFontIndirectA(&lf);
2816 hfont = SelectObject(hdc, hfont);
2817 GetTextFaceA(hdc, sizeof(buf), buf);
2818 todo_wine /* Wine uses Arial for all substitutions */
2819 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2820 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2821 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2822 "Got %s\n", buf);
2823 cs = GetTextCharset(hdc);
2824 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2825 DeleteObject(SelectObject(hdc, hfont));
2827 memset(&lf, 0, sizeof(lf));
2828 lf.lfHeight = -13;
2829 lf.lfWeight = FW_REGULAR;
2830 strcpy(lf.lfFaceName, "Nonexistent font");
2831 hfont = CreateFontIndirectA(&lf);
2832 hfont = SelectObject(hdc, hfont);
2833 GetTextFaceA(hdc, sizeof(buf), buf);
2834 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2835 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2836 cs = GetTextCharset(hdc);
2837 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2838 DeleteObject(SelectObject(hdc, hfont));
2840 memset(&lf, 0, sizeof(lf));
2841 lf.lfHeight = -13;
2842 lf.lfWeight = FW_DONTCARE;
2843 strcpy(lf.lfFaceName, "Times New Roman");
2844 hfont = CreateFontIndirectA(&lf);
2845 hfont = SelectObject(hdc, hfont);
2846 GetTextFaceA(hdc, sizeof(buf), buf);
2847 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2848 cs = GetTextCharset(hdc);
2849 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2850 DeleteObject(SelectObject(hdc, hfont));
2852 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2854 memset(&lf, 0, sizeof(lf));
2855 lf.lfHeight = -13;
2856 lf.lfWeight = FW_REGULAR;
2857 strcpy(lf.lfFaceName, font_subst[i].name);
2858 hfont = CreateFontIndirectA(&lf);
2859 hfont = SelectObject(hdc, hfont);
2860 cs = GetTextCharset(hdc);
2861 if (font_subst[i].charset == expected_cs)
2863 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2864 GetTextFaceA(hdc, sizeof(buf), buf);
2865 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2867 else
2869 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2870 GetTextFaceA(hdc, sizeof(buf), buf);
2871 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2872 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2874 DeleteObject(SelectObject(hdc, hfont));
2876 memset(&lf, 0, sizeof(lf));
2877 lf.lfHeight = -13;
2878 lf.lfWeight = FW_DONTCARE;
2879 strcpy(lf.lfFaceName, font_subst[i].name);
2880 hfont = CreateFontIndirectA(&lf);
2881 hfont = SelectObject(hdc, hfont);
2882 GetTextFaceA(hdc, sizeof(buf), buf);
2883 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2884 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2885 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2886 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2887 "got %s for font %s\n", buf, font_subst[i].name);
2888 cs = GetTextCharset(hdc);
2889 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2890 DeleteObject(SelectObject(hdc, hfont));
2893 ReleaseDC(0, hdc);
2896 static void test_GdiRealizationInfo(void)
2898 HDC hdc;
2899 DWORD info[4];
2900 BOOL r;
2901 HFONT hfont, hfont_old;
2902 LOGFONTA lf;
2904 if(!pGdiRealizationInfo)
2906 win_skip("GdiRealizationInfo not available\n");
2907 return;
2910 hdc = GetDC(0);
2912 memset(info, 0xcc, sizeof(info));
2913 r = pGdiRealizationInfo(hdc, info);
2914 ok(r != 0, "ret 0\n");
2915 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2916 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2918 if (!is_truetype_font_installed("Arial"))
2920 skip("skipping GdiRealizationInfo with truetype font\n");
2921 goto end;
2924 memset(&lf, 0, sizeof(lf));
2925 strcpy(lf.lfFaceName, "Arial");
2926 lf.lfHeight = 20;
2927 lf.lfWeight = FW_NORMAL;
2928 hfont = CreateFontIndirectA(&lf);
2929 hfont_old = SelectObject(hdc, hfont);
2931 memset(info, 0xcc, sizeof(info));
2932 r = pGdiRealizationInfo(hdc, info);
2933 ok(r != 0, "ret 0\n");
2934 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2935 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2937 DeleteObject(SelectObject(hdc, hfont_old));
2939 end:
2940 ReleaseDC(0, hdc);
2943 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2944 the nul in the count of characters copied when the face name buffer is not
2945 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2946 always includes it. */
2947 static void test_GetTextFace(void)
2949 static const char faceA[] = "Tahoma";
2950 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2951 LOGFONTA fA = {0};
2952 LOGFONTW fW = {0};
2953 char bufA[LF_FACESIZE];
2954 WCHAR bufW[LF_FACESIZE];
2955 HFONT f, g;
2956 HDC dc;
2957 int n;
2959 if(!is_font_installed("Tahoma"))
2961 skip("Tahoma is not installed so skipping this test\n");
2962 return;
2965 /* 'A' case. */
2966 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2967 f = CreateFontIndirectA(&fA);
2968 ok(f != NULL, "CreateFontIndirectA failed\n");
2970 dc = GetDC(NULL);
2971 g = SelectObject(dc, f);
2972 n = GetTextFaceA(dc, sizeof bufA, bufA);
2973 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2974 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2976 /* Play with the count arg. */
2977 bufA[0] = 'x';
2978 n = GetTextFaceA(dc, 0, bufA);
2979 ok(n == 0, "GetTextFaceA returned %d\n", n);
2980 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2982 bufA[0] = 'x';
2983 n = GetTextFaceA(dc, 1, bufA);
2984 ok(n == 0, "GetTextFaceA returned %d\n", n);
2985 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2987 bufA[0] = 'x'; bufA[1] = 'y';
2988 n = GetTextFaceA(dc, 2, bufA);
2989 ok(n == 1, "GetTextFaceA returned %d\n", n);
2990 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2992 n = GetTextFaceA(dc, 0, NULL);
2993 ok(n == sizeof faceA ||
2994 broken(n == 0), /* win98, winMe */
2995 "GetTextFaceA returned %d\n", n);
2997 DeleteObject(SelectObject(dc, g));
2998 ReleaseDC(NULL, dc);
3000 /* 'W' case. */
3001 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3002 SetLastError(0xdeadbeef);
3003 f = CreateFontIndirectW(&fW);
3004 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3006 win_skip("CreateFontIndirectW is not implemented\n");
3007 return;
3009 ok(f != NULL, "CreateFontIndirectW failed\n");
3011 dc = GetDC(NULL);
3012 g = SelectObject(dc, f);
3013 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3014 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3015 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3017 /* Play with the count arg. */
3018 bufW[0] = 'x';
3019 n = GetTextFaceW(dc, 0, bufW);
3020 ok(n == 0, "GetTextFaceW returned %d\n", n);
3021 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3023 bufW[0] = 'x';
3024 n = GetTextFaceW(dc, 1, bufW);
3025 ok(n == 1, "GetTextFaceW returned %d\n", n);
3026 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3028 bufW[0] = 'x'; bufW[1] = 'y';
3029 n = GetTextFaceW(dc, 2, bufW);
3030 ok(n == 2, "GetTextFaceW returned %d\n", n);
3031 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3033 n = GetTextFaceW(dc, 0, NULL);
3034 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3036 DeleteObject(SelectObject(dc, g));
3037 ReleaseDC(NULL, dc);
3040 static void test_orientation(void)
3042 static const char test_str[11] = "Test String";
3043 HDC hdc;
3044 LOGFONTA lf;
3045 HFONT hfont, old_hfont;
3046 SIZE size;
3048 if (!is_truetype_font_installed("Arial"))
3050 skip("Arial is not installed\n");
3051 return;
3054 hdc = CreateCompatibleDC(0);
3055 memset(&lf, 0, sizeof(lf));
3056 lstrcpyA(lf.lfFaceName, "Arial");
3057 lf.lfHeight = 72;
3058 lf.lfOrientation = lf.lfEscapement = 900;
3059 hfont = create_font("orientation", &lf);
3060 old_hfont = SelectObject(hdc, hfont);
3061 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3062 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3063 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3064 SelectObject(hdc, old_hfont);
3065 DeleteObject(hfont);
3066 DeleteDC(hdc);
3069 static void test_oemcharset(void)
3071 HDC hdc;
3072 LOGFONTA lf, clf;
3073 HFONT hfont, old_hfont;
3074 int charset;
3076 hdc = CreateCompatibleDC(0);
3077 ZeroMemory(&lf, sizeof(lf));
3078 lf.lfHeight = 12;
3079 lf.lfCharSet = OEM_CHARSET;
3080 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3081 lstrcpyA(lf.lfFaceName, "Terminal");
3082 hfont = CreateFontIndirectA(&lf);
3083 old_hfont = SelectObject(hdc, hfont);
3084 charset = GetTextCharset(hdc);
3085 todo_wine
3086 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3087 hfont = SelectObject(hdc, old_hfont);
3088 GetObjectA(hfont, sizeof(clf), &clf);
3089 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3090 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3091 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3092 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3093 DeleteObject(hfont);
3094 DeleteDC(hdc);
3097 static void test_GetGlyphOutline(void)
3099 HDC hdc;
3100 GLYPHMETRICS gm, gm2;
3101 LOGFONTA lf;
3102 HFONT hfont, old_hfont;
3103 INT ret, ret2;
3104 static const struct
3106 UINT cs;
3107 UINT a;
3108 UINT w;
3109 } c[] =
3111 {ANSI_CHARSET, 0x30, 0x30},
3112 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3113 {HANGEUL_CHARSET, 0x8141, 0xac02},
3114 {JOHAB_CHARSET, 0x8446, 0x3135},
3115 {GB2312_CHARSET, 0x8141, 0x4e04},
3116 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3118 UINT i;
3120 if (!is_truetype_font_installed("Tahoma"))
3122 skip("Tahoma is not installed\n");
3123 return;
3126 hdc = CreateCompatibleDC(0);
3127 memset(&lf, 0, sizeof(lf));
3128 lf.lfHeight = 72;
3129 lstrcpyA(lf.lfFaceName, "Tahoma");
3130 SetLastError(0xdeadbeef);
3131 hfont = CreateFontIndirectA(&lf);
3132 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3133 old_hfont = SelectObject(hdc, hfont);
3135 memset(&gm, 0, sizeof(gm));
3136 SetLastError(0xdeadbeef);
3137 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3138 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3140 memset(&gm, 0, sizeof(gm));
3141 SetLastError(0xdeadbeef);
3142 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3143 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3144 ok(GetLastError() == 0xdeadbeef ||
3145 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3146 "expected 0xdeadbeef, got %u\n", GetLastError());
3148 memset(&gm, 0, sizeof(gm));
3149 SetLastError(0xdeadbeef);
3150 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3151 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3152 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3154 memset(&gm, 0, sizeof(gm));
3155 SetLastError(0xdeadbeef);
3156 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3157 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3159 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3160 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3163 /* test for needed buffer size request on space char */
3164 memset(&gm, 0, sizeof(gm));
3165 SetLastError(0xdeadbeef);
3166 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3167 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3168 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3170 /* requesting buffer size for space char + error */
3171 memset(&gm, 0, sizeof(gm));
3172 SetLastError(0xdeadbeef);
3173 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3174 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3176 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3177 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3180 SelectObject(hdc, old_hfont);
3181 DeleteObject(hfont);
3183 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3185 lf.lfFaceName[0] = '\0';
3186 lf.lfCharSet = c[i].cs;
3187 lf.lfPitchAndFamily = 0;
3188 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3190 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3191 continue;
3194 old_hfont = SelectObject(hdc, hfont);
3196 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3197 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3198 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3200 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3201 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3202 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3204 hfont = SelectObject(hdc, old_hfont);
3205 DeleteObject(hfont);
3208 DeleteDC(hdc);
3211 /* bug #9995: there is a limit to the character width that can be specified */
3212 static void test_GetTextMetrics2(const char *fontname, int font_height)
3214 HFONT of, hf;
3215 HDC hdc;
3216 TEXTMETRICA tm;
3217 BOOL ret;
3218 int ave_width, height, width, ratio, scale;
3220 if (!is_truetype_font_installed( fontname)) {
3221 skip("%s is not installed\n", fontname);
3222 return;
3224 hdc = CreateCompatibleDC(0);
3225 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3226 /* select width = 0 */
3227 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3228 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3229 DEFAULT_QUALITY, VARIABLE_PITCH,
3230 fontname);
3231 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3232 of = SelectObject( hdc, hf);
3233 ret = GetTextMetricsA( hdc, &tm);
3234 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3235 height = tm.tmHeight;
3236 ave_width = tm.tmAveCharWidth;
3237 SelectObject( hdc, of);
3238 DeleteObject( hf);
3240 trace("height %d, ave width %d\n", height, ave_width);
3242 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3244 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3245 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3246 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3247 ok(hf != 0, "CreateFont failed\n");
3248 of = SelectObject(hdc, hf);
3249 ret = GetTextMetrics(hdc, &tm);
3250 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3251 SelectObject(hdc, of);
3252 DeleteObject(hf);
3254 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3255 break;
3258 DeleteDC(hdc);
3260 ratio = width / height;
3261 scale = width / ave_width;
3263 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3264 width, height, ratio, width, ave_width, scale);
3266 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3269 static void test_CreateFontIndirect(void)
3271 LOGFONTA lf, getobj_lf;
3272 int ret, i;
3273 HFONT hfont;
3274 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3276 memset(&lf, 0, sizeof(lf));
3277 lf.lfCharSet = ANSI_CHARSET;
3278 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3279 lf.lfHeight = 16;
3280 lf.lfWidth = 16;
3281 lf.lfQuality = DEFAULT_QUALITY;
3282 lf.lfItalic = FALSE;
3283 lf.lfWeight = FW_DONTCARE;
3285 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3287 lstrcpyA(lf.lfFaceName, TestName[i]);
3288 hfont = CreateFontIndirectA(&lf);
3289 ok(hfont != 0, "CreateFontIndirectA failed\n");
3290 SetLastError(0xdeadbeef);
3291 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3292 ok(ret, "GetObject failed: %d\n", GetLastError());
3293 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3294 ok(lf.lfWeight == getobj_lf.lfWeight ||
3295 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3296 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3297 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3298 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3299 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3300 DeleteObject(hfont);
3304 static void test_CreateFontIndirectEx(void)
3306 ENUMLOGFONTEXDVA lfex;
3307 HFONT hfont;
3309 if (!pCreateFontIndirectExA)
3311 win_skip("CreateFontIndirectExA is not available\n");
3312 return;
3315 if (!is_truetype_font_installed("Arial"))
3317 skip("Arial is not installed\n");
3318 return;
3321 SetLastError(0xdeadbeef);
3322 hfont = pCreateFontIndirectExA(NULL);
3323 ok(hfont == NULL, "got %p\n", hfont);
3324 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3326 memset(&lfex, 0, sizeof(lfex));
3327 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3328 hfont = pCreateFontIndirectExA(&lfex);
3329 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3330 if (hfont)
3331 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3332 DeleteObject(hfont);
3335 static void free_font(void *font)
3337 UnmapViewOfFile(font);
3340 static void *load_font(const char *font_name, DWORD *font_size)
3342 char file_name[MAX_PATH];
3343 HANDLE file, mapping;
3344 void *font;
3346 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3347 strcat(file_name, "\\fonts\\");
3348 strcat(file_name, font_name);
3350 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3351 if (file == INVALID_HANDLE_VALUE) return NULL;
3353 *font_size = GetFileSize(file, NULL);
3355 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3356 if (!mapping)
3358 CloseHandle(file);
3359 return NULL;
3362 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3364 CloseHandle(file);
3365 CloseHandle(mapping);
3366 return font;
3369 static void test_AddFontMemResource(void)
3371 void *font;
3372 DWORD font_size, num_fonts;
3373 HANDLE ret;
3374 BOOL bRet;
3376 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3378 win_skip("AddFontMemResourceEx is not available on this platform\n");
3379 return;
3382 font = load_font("sserife.fon", &font_size);
3383 if (!font)
3385 skip("Unable to locate and load font sserife.fon\n");
3386 return;
3389 SetLastError(0xdeadbeef);
3390 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3391 ok(!ret, "AddFontMemResourceEx should fail\n");
3392 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3393 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3394 GetLastError());
3396 SetLastError(0xdeadbeef);
3397 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3398 ok(!ret, "AddFontMemResourceEx should fail\n");
3399 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3400 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3401 GetLastError());
3403 SetLastError(0xdeadbeef);
3404 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3405 ok(!ret, "AddFontMemResourceEx should fail\n");
3406 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3407 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3408 GetLastError());
3410 SetLastError(0xdeadbeef);
3411 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3412 ok(!ret, "AddFontMemResourceEx should fail\n");
3413 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3414 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3415 GetLastError());
3417 SetLastError(0xdeadbeef);
3418 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3419 ok(!ret, "AddFontMemResourceEx should fail\n");
3420 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3421 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3422 GetLastError());
3424 SetLastError(0xdeadbeef);
3425 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3426 ok(!ret, "AddFontMemResourceEx should fail\n");
3427 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3428 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3429 GetLastError());
3431 num_fonts = 0xdeadbeef;
3432 SetLastError(0xdeadbeef);
3433 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3434 ok(!ret, "AddFontMemResourceEx should fail\n");
3435 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3436 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3437 GetLastError());
3438 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3440 if (0) /* hangs under windows 2000 */
3442 num_fonts = 0xdeadbeef;
3443 SetLastError(0xdeadbeef);
3444 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3445 ok(!ret, "AddFontMemResourceEx should fail\n");
3446 ok(GetLastError() == 0xdeadbeef,
3447 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3448 GetLastError());
3449 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3452 num_fonts = 0xdeadbeef;
3453 SetLastError(0xdeadbeef);
3454 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3455 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3456 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3457 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3459 free_font(font);
3461 SetLastError(0xdeadbeef);
3462 bRet = pRemoveFontMemResourceEx(ret);
3463 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3465 /* test invalid pointer to number of loaded fonts */
3466 font = load_font("sserife.fon", &font_size);
3467 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3469 SetLastError(0xdeadbeef);
3470 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3471 ok(!ret, "AddFontMemResourceEx should fail\n");
3472 ok(GetLastError() == 0xdeadbeef,
3473 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3474 GetLastError());
3476 SetLastError(0xdeadbeef);
3477 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3478 ok(!ret, "AddFontMemResourceEx should fail\n");
3479 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3480 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3481 GetLastError());
3483 free_font(font);
3486 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3488 LOGFONT *lf;
3490 if (type != TRUETYPE_FONTTYPE) return 1;
3492 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3494 lf = (LOGFONT *)lparam;
3495 *lf = *elf;
3496 return 0;
3499 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3501 int ret;
3502 LOGFONT *lf;
3504 if (type != TRUETYPE_FONTTYPE) return 1;
3506 lf = (LOGFONT *)lparam;
3507 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3508 if(ret == 0)
3510 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3511 *lf = *elf;
3512 return 0;
3514 return 1;
3517 static void test_EnumFonts(void)
3519 int ret;
3520 LOGFONT lf;
3521 HDC hdc;
3523 if (!is_truetype_font_installed("Arial"))
3525 skip("Arial is not installed\n");
3526 return;
3529 /* Windows uses localized font face names, so Arial Bold won't be found */
3530 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3532 skip("User locale is not English, skipping the test\n");
3533 return;
3536 hdc = CreateCompatibleDC(0);
3538 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3539 ok(!ret, "font Arial is not enumerated\n");
3540 ret = strcmp(lf.lfFaceName, "Arial");
3541 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3542 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3544 lstrcpy(lf.lfFaceName, "Arial");
3545 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3546 ok(!ret, "font Arial is not enumerated\n");
3547 ret = strcmp(lf.lfFaceName, "Arial");
3548 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3549 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3551 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3552 ok(!ret, "font Arial Bold is not enumerated\n");
3553 ret = strcmp(lf.lfFaceName, "Arial");
3554 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3555 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3557 lstrcpy(lf.lfFaceName, "Arial Bold");
3558 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3559 ok(ret, "font Arial Bold should not be enumerated\n");
3561 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3562 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3563 ret = strcmp(lf.lfFaceName, "Arial");
3564 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3565 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3567 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3568 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3569 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3571 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3572 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3574 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3575 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3576 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3578 DeleteDC(hdc);
3581 START_TEST(font)
3583 init();
3585 test_logfont();
3586 test_bitmap_font();
3587 test_outline_font();
3588 test_bitmap_font_metrics();
3589 test_GdiGetCharDimensions();
3590 test_GetCharABCWidths();
3591 test_text_extents();
3592 test_GetGlyphIndices();
3593 test_GetKerningPairs();
3594 test_GetOutlineTextMetrics();
3595 test_SetTextJustification();
3596 test_font_charset();
3597 test_GetFontUnicodeRanges();
3598 test_nonexistent_font();
3599 test_orientation();
3600 test_height_selection();
3601 test_AddFontMemResource();
3602 test_EnumFonts();
3604 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3605 * I'd like to avoid them in this test.
3607 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3608 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3609 if (is_truetype_font_installed("Arial Black") &&
3610 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3612 test_EnumFontFamilies("", ANSI_CHARSET);
3613 test_EnumFontFamilies("", SYMBOL_CHARSET);
3614 test_EnumFontFamilies("", DEFAULT_CHARSET);
3616 else
3617 skip("Arial Black or Symbol/Wingdings is not installed\n");
3618 test_GetTextMetrics();
3619 test_GdiRealizationInfo();
3620 test_GetTextFace();
3621 test_GetGlyphOutline();
3622 test_GetTextMetrics2("Tahoma", -11);
3623 test_GetTextMetrics2("Tahoma", -55);
3624 test_GetTextMetrics2("Tahoma", -110);
3625 test_GetTextMetrics2("Arial", -11);
3626 test_GetTextMetrics2("Arial", -55);
3627 test_GetTextMetrics2("Arial", -110);
3628 test_CreateFontIndirect();
3629 test_CreateFontIndirectEx();
3630 test_oemcharset();