wer: Add new stubbed wer.dll.
[wine/hramrach.git] / dlls / gdi32 / tests / font.c
blobfa4836042a1fa847eceddfe52da780412cafb33a
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
41 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
42 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
43 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
44 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
45 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
46 HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
47 HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
48 BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
50 static HMODULE hgdi32 = 0;
52 static void init(void)
54 hgdi32 = GetModuleHandleA("gdi32.dll");
56 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
57 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
58 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
59 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
60 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
61 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
62 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
63 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
64 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
65 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
68 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
70 if (type != TRUETYPE_FONTTYPE) return 1;
72 return 0;
75 static BOOL is_truetype_font_installed(const char *name)
77 HDC hdc = GetDC(0);
78 BOOL ret = FALSE;
80 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
81 ret = TRUE;
83 ReleaseDC(0, hdc);
84 return ret;
87 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
89 return 0;
92 static BOOL is_font_installed(const char *name)
94 HDC hdc = GetDC(0);
95 BOOL ret = FALSE;
97 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
98 ret = TRUE;
100 ReleaseDC(0, hdc);
101 return ret;
104 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
106 LOGFONTA getobj_lf;
107 int ret, minlen = 0;
109 if (!hfont)
110 return;
112 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
113 /* NT4 tries to be clever and only returns the minimum length */
114 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
115 minlen++;
116 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
117 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
118 ok(lf->lfHeight == getobj_lf.lfHeight ||
119 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
120 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
121 ok(lf->lfWidth == getobj_lf.lfWidth ||
122 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
123 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
124 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
125 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
126 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
127 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
128 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
129 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
130 ok(lf->lfWeight == getobj_lf.lfWeight ||
131 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
132 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
133 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
134 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
135 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
136 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
137 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
138 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
139 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
140 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
141 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
142 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
143 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
146 static HFONT create_font(const char* test, const LOGFONTA* lf)
148 HFONT hfont = CreateFontIndirectA(lf);
149 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
150 if (hfont)
151 check_font(test, lf, hfont);
152 return hfont;
155 static void test_logfont(void)
157 LOGFONTA lf;
158 HFONT hfont;
160 memset(&lf, 0, sizeof lf);
162 lf.lfCharSet = ANSI_CHARSET;
163 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
164 lf.lfWeight = FW_DONTCARE;
165 lf.lfHeight = 16;
166 lf.lfWidth = 16;
167 lf.lfQuality = DEFAULT_QUALITY;
169 lstrcpyA(lf.lfFaceName, "Arial");
170 hfont = create_font("Arial", &lf);
171 DeleteObject(hfont);
173 memset(&lf, 'A', sizeof(lf));
174 hfont = CreateFontIndirectA(&lf);
175 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
177 lf.lfFaceName[LF_FACESIZE - 1] = 0;
178 check_font("AAA...", &lf, hfont);
179 DeleteObject(hfont);
182 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
184 if (type & RASTER_FONTTYPE)
186 LOGFONT *lf = (LOGFONT *)lParam;
187 *lf = *elf;
188 return 0; /* stop enumeration */
191 return 1; /* continue enumeration */
194 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
196 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
197 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
198 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
199 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
200 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
201 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
202 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
203 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
204 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
205 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
206 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
207 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
208 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
209 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
210 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
211 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
212 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
213 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
214 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
215 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
218 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
219 LONG lfWidth, const char *test_str,
220 INT test_str_len, const TEXTMETRICA *tm_orig,
221 const SIZE *size_orig, INT width_of_A_orig,
222 INT scale_x, INT scale_y)
224 LOGFONTA lf;
225 OUTLINETEXTMETRIC otm;
226 TEXTMETRICA tm;
227 SIZE size;
228 INT width_of_A, cx, cy;
229 UINT ret;
231 if (!hfont)
232 return;
234 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
236 GetObjectA(hfont, sizeof(lf), &lf);
238 if (GetOutlineTextMetricsA(hdc, 0, NULL))
240 otm.otmSize = sizeof(otm) / 2;
241 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
242 ok(ret == sizeof(otm)/2 /* XP */ ||
243 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
245 memset(&otm, 0x1, sizeof(otm));
246 otm.otmSize = sizeof(otm);
247 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
248 ok(ret == sizeof(otm) /* XP */ ||
249 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
251 memset(&tm, 0x2, sizeof(tm));
252 ret = GetTextMetricsA(hdc, &tm);
253 ok(ret, "GetTextMetricsA failed\n");
254 /* the structure size is aligned */
255 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
257 ok(0, "tm != otm\n");
258 compare_tm(&tm, &otm.otmTextMetrics);
261 tm = otm.otmTextMetrics;
262 if (0) /* these metrics are scaled too, but with rounding errors */
264 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
265 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
267 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
268 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
269 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
270 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
271 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
272 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
274 else
276 ret = GetTextMetricsA(hdc, &tm);
277 ok(ret, "GetTextMetricsA failed\n");
280 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
281 cy = tm.tmHeight / tm_orig->tmHeight;
282 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
283 lfHeight, scale_x, scale_y, cx, cy);
284 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
285 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
286 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
287 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
288 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
290 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
291 if (lf.lfHeight)
293 if (lf.lfWidth)
294 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
296 else
297 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
299 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
301 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
302 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
304 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
306 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);
309 /* Test how GDI scales bitmap font metrics */
310 static void test_bitmap_font(void)
312 static const char test_str[11] = "Test String";
313 HDC hdc;
314 LOGFONTA bitmap_lf;
315 HFONT hfont, old_hfont;
316 TEXTMETRICA tm_orig;
317 SIZE size_orig;
318 INT ret, i, width_orig, height_orig, scale, lfWidth;
320 hdc = GetDC(0);
322 /* "System" has only 1 pixel size defined, otherwise the test breaks */
323 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
324 if (ret)
326 ReleaseDC(0, hdc);
327 trace("no bitmap fonts were found, skipping the test\n");
328 return;
331 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
333 height_orig = bitmap_lf.lfHeight;
334 lfWidth = bitmap_lf.lfWidth;
336 hfont = create_font("bitmap", &bitmap_lf);
337 old_hfont = SelectObject(hdc, hfont);
338 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
339 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
340 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
341 SelectObject(hdc, old_hfont);
342 DeleteObject(hfont);
344 bitmap_lf.lfHeight = 0;
345 bitmap_lf.lfWidth = 4;
346 hfont = create_font("bitmap", &bitmap_lf);
347 old_hfont = SelectObject(hdc, hfont);
348 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
349 SelectObject(hdc, old_hfont);
350 DeleteObject(hfont);
352 bitmap_lf.lfHeight = height_orig;
353 bitmap_lf.lfWidth = lfWidth;
355 /* test fractional scaling */
356 for (i = 1; i <= height_orig * 6; i++)
358 INT nearest_height;
360 bitmap_lf.lfHeight = i;
361 hfont = create_font("fractional", &bitmap_lf);
362 scale = (i + height_orig - 1) / height_orig;
363 nearest_height = scale * height_orig;
364 /* Only jump to the next height if the difference <= 25% original height */
365 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
366 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
367 so we'll not test this particular height. */
368 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
369 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
370 old_hfont = SelectObject(hdc, hfont);
371 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
372 SelectObject(hdc, old_hfont);
373 DeleteObject(hfont);
376 /* test integer scaling 3x2 */
377 bitmap_lf.lfHeight = height_orig * 2;
378 bitmap_lf.lfWidth *= 3;
379 hfont = create_font("3x2", &bitmap_lf);
380 old_hfont = SelectObject(hdc, hfont);
381 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
382 SelectObject(hdc, old_hfont);
383 DeleteObject(hfont);
385 /* test integer scaling 3x3 */
386 bitmap_lf.lfHeight = height_orig * 3;
387 bitmap_lf.lfWidth = 0;
388 hfont = create_font("3x3", &bitmap_lf);
389 old_hfont = SelectObject(hdc, hfont);
390 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
391 SelectObject(hdc, old_hfont);
392 DeleteObject(hfont);
394 ReleaseDC(0, hdc);
397 /* Test how GDI scales outline font metrics */
398 static void test_outline_font(void)
400 static const char test_str[11] = "Test String";
401 HDC hdc, hdc_2;
402 LOGFONTA lf;
403 HFONT hfont, old_hfont, old_hfont_2;
404 OUTLINETEXTMETRICA otm;
405 SIZE size_orig;
406 INT width_orig, height_orig, lfWidth;
407 XFORM xform;
408 GLYPHMETRICS gm;
409 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
410 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
411 POINT pt;
412 INT ret;
414 if (!is_truetype_font_installed("Arial"))
416 skip("Arial is not installed\n");
417 return;
420 hdc = CreateCompatibleDC(0);
422 memset(&lf, 0, sizeof(lf));
423 strcpy(lf.lfFaceName, "Arial");
424 lf.lfHeight = 72;
425 hfont = create_font("outline", &lf);
426 old_hfont = SelectObject(hdc, hfont);
427 otm.otmSize = sizeof(otm);
428 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
429 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
430 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
432 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
433 SelectObject(hdc, old_hfont);
434 DeleteObject(hfont);
436 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
437 lf.lfHeight = otm.otmEMSquare;
438 lf.lfHeight = -lf.lfHeight;
439 hfont = create_font("outline", &lf);
440 old_hfont = SelectObject(hdc, hfont);
441 otm.otmSize = sizeof(otm);
442 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
443 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
444 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
445 SelectObject(hdc, old_hfont);
446 DeleteObject(hfont);
448 height_orig = otm.otmTextMetrics.tmHeight;
449 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
451 /* test integer scaling 3x2 */
452 lf.lfHeight = height_orig * 2;
453 lf.lfWidth = lfWidth * 3;
454 hfont = create_font("3x2", &lf);
455 old_hfont = SelectObject(hdc, hfont);
456 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
457 SelectObject(hdc, old_hfont);
458 DeleteObject(hfont);
460 /* test integer scaling 3x3 */
461 lf.lfHeight = height_orig * 3;
462 lf.lfWidth = lfWidth * 3;
463 hfont = create_font("3x3", &lf);
464 old_hfont = SelectObject(hdc, hfont);
465 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
466 SelectObject(hdc, old_hfont);
467 DeleteObject(hfont);
469 /* test integer scaling 1x1 */
470 lf.lfHeight = height_orig * 1;
471 lf.lfWidth = lfWidth * 1;
472 hfont = create_font("1x1", &lf);
473 old_hfont = SelectObject(hdc, hfont);
474 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
475 SelectObject(hdc, old_hfont);
476 DeleteObject(hfont);
478 /* test integer scaling 1x1 */
479 lf.lfHeight = height_orig;
480 lf.lfWidth = 0;
481 hfont = create_font("1x1", &lf);
482 old_hfont = SelectObject(hdc, hfont);
483 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 /* with an identity matrix */
486 memset(&gm, 0, sizeof(gm));
487 SetLastError(0xdeadbeef);
488 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
489 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
490 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
491 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
492 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
493 /* with a custom matrix */
494 memset(&gm, 0, sizeof(gm));
495 SetLastError(0xdeadbeef);
496 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
497 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
498 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
499 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
500 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
502 /* Test that changing the DC transformation affects only the font
503 * selected on this DC and doesn't affect the same font selected on
504 * another DC.
506 hdc_2 = CreateCompatibleDC(0);
507 old_hfont_2 = SelectObject(hdc_2, hfont);
508 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
510 SetMapMode(hdc, MM_ANISOTROPIC);
512 /* font metrics on another DC should be unchanged */
513 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
515 /* test restrictions of compatibility mode GM_COMPATIBLE */
516 /* part 1: rescaling only X should not change font scaling on screen.
517 So compressing the X axis by 2 is not done, and this
518 appears as X scaling of 2 that no one requested. */
519 SetWindowExtEx(hdc, 100, 100, NULL);
520 SetViewportExtEx(hdc, 50, 100, NULL);
521 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* part 2: rescaling only Y should change font scaling.
526 As also X is scaled by a factor of 2, but this is not
527 requested by the DC transformation, we get a scaling factor
528 of 2 in the X coordinate. */
529 SetViewportExtEx(hdc, 100, 200, NULL);
530 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
531 /* font metrics on another DC should be unchanged */
532 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
534 /* restore scaling */
535 SetMapMode(hdc, MM_TEXT);
537 /* font metrics on another DC should be unchanged */
538 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
540 SelectObject(hdc_2, old_hfont_2);
541 DeleteDC(hdc_2);
543 if (!SetGraphicsMode(hdc, GM_ADVANCED))
545 SelectObject(hdc, old_hfont);
546 DeleteObject(hfont);
547 DeleteDC(hdc);
548 skip("GM_ADVANCED is not supported on this platform\n");
549 return;
552 xform.eM11 = 20.0f;
553 xform.eM12 = 0.0f;
554 xform.eM21 = 0.0f;
555 xform.eM22 = 20.0f;
556 xform.eDx = 0.0f;
557 xform.eDy = 0.0f;
559 SetLastError(0xdeadbeef);
560 ret = SetWorldTransform(hdc, &xform);
561 ok(ret, "SetWorldTransform error %u\n", GetLastError());
563 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
565 /* with an identity matrix */
566 memset(&gm, 0, sizeof(gm));
567 SetLastError(0xdeadbeef);
568 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
569 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
570 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
571 pt.x = width_orig; pt.y = 0;
572 LPtoDP(hdc, &pt, 1);
573 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
574 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
575 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
576 /* with a custom matrix */
577 memset(&gm, 0, sizeof(gm));
578 SetLastError(0xdeadbeef);
579 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
580 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
581 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
582 pt.x = width_orig; pt.y = 0;
583 LPtoDP(hdc, &pt, 1);
584 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
585 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
586 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
588 SetLastError(0xdeadbeef);
589 ret = SetMapMode(hdc, MM_LOMETRIC);
590 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
592 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
594 /* with an identity matrix */
595 memset(&gm, 0, sizeof(gm));
596 SetLastError(0xdeadbeef);
597 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
598 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
599 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
600 pt.x = width_orig; pt.y = 0;
601 LPtoDP(hdc, &pt, 1);
602 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
603 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
604 /* with a custom matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
611 LPtoDP(hdc, &pt, 1);
612 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
615 SetLastError(0xdeadbeef);
616 ret = SetMapMode(hdc, MM_TEXT);
617 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
619 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
621 /* with an identity matrix */
622 memset(&gm, 0, sizeof(gm));
623 SetLastError(0xdeadbeef);
624 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
625 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
626 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
627 pt.x = width_orig; pt.y = 0;
628 LPtoDP(hdc, &pt, 1);
629 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
630 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
631 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
632 /* with a custom matrix */
633 memset(&gm, 0, sizeof(gm));
634 SetLastError(0xdeadbeef);
635 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
636 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
637 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
638 pt.x = width_orig; pt.y = 0;
639 LPtoDP(hdc, &pt, 1);
640 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
641 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
642 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
644 SelectObject(hdc, old_hfont);
645 DeleteObject(hfont);
646 DeleteDC(hdc);
649 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
651 LOGFONT *lf = (LOGFONT *)lParam;
653 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
655 *lf = *elf;
656 return 0; /* stop enumeration */
658 return 1; /* continue enumeration */
661 static void test_bitmap_font_metrics(void)
663 static const struct font_data
665 const char face_name[LF_FACESIZE];
666 int weight, height, ascent, descent, int_leading, ext_leading;
667 int ave_char_width, max_char_width, dpi;
668 DWORD ansi_bitfield;
669 } fd[] =
671 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
672 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
673 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
674 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
675 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
676 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
677 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
679 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
680 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
681 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
684 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
685 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
686 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
687 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
688 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
689 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
690 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
692 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
693 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
694 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
695 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
696 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
697 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
698 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
699 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
700 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
701 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
702 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
703 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
705 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
706 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
707 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
710 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
711 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
712 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
713 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
714 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
716 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
717 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
719 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
722 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
723 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
724 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
726 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
727 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
728 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
730 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
731 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
733 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
734 * require a new system.sfd for that font
736 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
738 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
739 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
741 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
742 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
743 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
744 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
745 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
746 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
747 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
748 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
749 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
750 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
751 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
752 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
753 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
754 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
755 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
757 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
759 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
761 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
762 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
765 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
766 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
767 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
768 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
769 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
770 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
772 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
773 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
774 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
776 /* The 120dpi version still has its dpi marked as 96 */
777 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
779 /* FIXME: add "Terminal" */
781 HDC hdc;
782 LOGFONT lf;
783 HFONT hfont, old_hfont;
784 TEXTMETRIC tm;
785 INT ret, i;
787 hdc = CreateCompatibleDC(0);
788 assert(hdc);
790 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
792 int bit;
794 memset(&lf, 0, sizeof(lf));
796 lf.lfHeight = fd[i].height;
797 strcpy(lf.lfFaceName, fd[i].face_name);
799 for(bit = 0; bit < 32; bit++)
801 DWORD fs[2];
802 CHARSETINFO csi;
804 fs[0] = 1L << bit;
805 fs[1] = 0;
806 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
807 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
809 lf.lfCharSet = csi.ciCharset;
810 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
811 if (ret) continue;
813 hfont = create_font(lf.lfFaceName, &lf);
814 old_hfont = SelectObject(hdc, hfont);
815 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
816 if(fd[i].dpi == tm.tmDigitizedAspectX)
818 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
819 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);
820 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);
821 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);
822 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);
823 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);
824 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);
825 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);
827 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
828 that make the max width bigger */
829 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
830 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);
832 SelectObject(hdc, old_hfont);
833 DeleteObject(hfont);
837 DeleteDC(hdc);
840 static void test_GdiGetCharDimensions(void)
842 HDC hdc;
843 TEXTMETRICW tm;
844 LONG ret;
845 SIZE size;
846 LONG avgwidth, height;
847 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
849 if (!pGdiGetCharDimensions)
851 win_skip("GdiGetCharDimensions not available on this platform\n");
852 return;
855 hdc = CreateCompatibleDC(NULL);
857 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
858 avgwidth = ((size.cx / 26) + 1) / 2;
860 ret = pGdiGetCharDimensions(hdc, &tm, &height);
861 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
862 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
864 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
865 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
867 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
868 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
870 height = 0;
871 ret = pGdiGetCharDimensions(hdc, NULL, &height);
872 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
873 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
875 DeleteDC(hdc);
878 static void test_GetCharABCWidths(void)
880 static const WCHAR str[] = {'a',0};
881 BOOL ret;
882 HDC hdc;
883 LOGFONTA lf;
884 HFONT hfont;
885 ABC abc[1];
886 WORD glyphs[1];
887 DWORD nb;
889 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
891 win_skip("GetCharABCWidthsW/I not available on this platform\n");
892 return;
895 memset(&lf, 0, sizeof(lf));
896 strcpy(lf.lfFaceName, "System");
897 lf.lfHeight = 20;
899 hfont = CreateFontIndirectA(&lf);
900 hdc = GetDC(0);
901 hfont = SelectObject(hdc, hfont);
903 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
904 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
906 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
907 ok(!ret, "GetCharABCWidthsI should have failed\n");
909 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
910 ok(!ret, "GetCharABCWidthsI should have failed\n");
912 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
913 ok(ret, "GetCharABCWidthsI should have succeeded\n");
915 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
916 ok(!ret, "GetCharABCWidthsW should have failed\n");
918 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
919 ok(!ret, "GetCharABCWidthsW should have failed\n");
921 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
922 ok(!ret, "GetCharABCWidthsW should have failed\n");
924 hfont = SelectObject(hdc, hfont);
925 DeleteObject(hfont);
926 ReleaseDC(NULL, hdc);
929 static void test_text_extents(void)
931 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
932 LPINT extents;
933 INT i, len, fit1, fit2;
934 LOGFONTA lf;
935 TEXTMETRICA tm;
936 HDC hdc;
937 HFONT hfont;
938 SIZE sz;
939 SIZE sz1, sz2;
941 memset(&lf, 0, sizeof(lf));
942 strcpy(lf.lfFaceName, "Arial");
943 lf.lfHeight = 20;
945 hfont = CreateFontIndirectA(&lf);
946 hdc = GetDC(0);
947 hfont = SelectObject(hdc, hfont);
948 GetTextMetricsA(hdc, &tm);
949 GetTextExtentPointA(hdc, "o", 1, &sz);
950 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
952 SetLastError(0xdeadbeef);
953 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
954 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
956 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
957 hfont = SelectObject(hdc, hfont);
958 DeleteObject(hfont);
959 ReleaseDC(0, hdc);
960 return;
963 len = lstrlenW(wt);
964 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
965 extents[0] = 1; /* So that the increasing sequence test will fail
966 if the extents array is untouched. */
967 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
968 GetTextExtentPointW(hdc, wt, len, &sz2);
969 ok(sz1.cy == sz2.cy,
970 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
971 /* Because of the '\n' in the string GetTextExtentExPoint and
972 GetTextExtentPoint return different widths under Win2k, but
973 under WinXP they return the same width. So we don't test that
974 here. */
976 for (i = 1; i < len; ++i)
977 ok(extents[i-1] <= extents[i],
978 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
980 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
981 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
982 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
983 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
984 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
985 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
986 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
987 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
988 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
989 ok(extents[0] == extents[2] && extents[1] == extents[3],
990 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
991 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
992 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
993 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
994 HeapFree(GetProcessHeap(), 0, extents);
996 hfont = SelectObject(hdc, hfont);
997 DeleteObject(hfont);
998 ReleaseDC(NULL, hdc);
1001 static void test_GetGlyphIndices(void)
1003 HDC hdc;
1004 HFONT hfont;
1005 DWORD charcount;
1006 LOGFONTA lf;
1007 DWORD flags = 0;
1008 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1009 WORD glyphs[(sizeof(testtext)/2)-1];
1010 TEXTMETRIC textm;
1011 HFONT hOldFont;
1013 if (!pGetGlyphIndicesW) {
1014 win_skip("GetGlyphIndicesW not available on platform\n");
1015 return;
1018 hdc = GetDC(0);
1020 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1021 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1022 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1023 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1024 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1025 flags = 0;
1026 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1027 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1028 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1029 textm.tmDefaultChar, glyphs[4]);
1031 if(!is_font_installed("Tahoma"))
1033 skip("Tahoma is not installed so skipping this test\n");
1034 return;
1036 memset(&lf, 0, sizeof(lf));
1037 strcpy(lf.lfFaceName, "Tahoma");
1038 lf.lfHeight = 20;
1040 hfont = CreateFontIndirectA(&lf);
1041 hOldFont = SelectObject(hdc, hfont);
1042 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1043 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1044 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1045 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1046 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1047 flags = 0;
1048 testtext[0] = textm.tmDefaultChar;
1049 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1050 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1051 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1052 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1053 DeleteObject(SelectObject(hdc, hOldFont));
1056 static void test_GetKerningPairs(void)
1058 static const struct kerning_data
1060 const char face_name[LF_FACESIZE];
1061 LONG height;
1062 /* some interesting fields from OUTLINETEXTMETRIC */
1063 LONG tmHeight, tmAscent, tmDescent;
1064 UINT otmEMSquare;
1065 INT otmAscent;
1066 INT otmDescent;
1067 UINT otmLineGap;
1068 UINT otmsCapEmHeight;
1069 UINT otmsXHeight;
1070 INT otmMacAscent;
1071 INT otmMacDescent;
1072 UINT otmMacLineGap;
1073 UINT otmusMinimumPPEM;
1074 /* small subset of kerning pairs to test */
1075 DWORD total_kern_pairs;
1076 const KERNINGPAIR kern_pair[26];
1077 } kd[] =
1079 {"Arial", 12, 12, 9, 3,
1080 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1083 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1084 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1085 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1086 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1087 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1088 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1089 {933,970,+1},{933,972,-1}
1092 {"Arial", -34, 39, 32, 7,
1093 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1096 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1097 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1098 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1099 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1100 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1101 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1102 {933,970,+2},{933,972,-3}
1105 { "Arial", 120, 120, 97, 23,
1106 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1109 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1110 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1111 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1112 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1113 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1114 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1115 {933,970,+6},{933,972,-10}
1118 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1119 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1120 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1123 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1124 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1125 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1126 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1127 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1128 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1129 {933,970,+54},{933,972,-83}
1132 #endif
1134 LOGFONT lf;
1135 HFONT hfont, hfont_old;
1136 KERNINGPAIR *kern_pair;
1137 HDC hdc;
1138 DWORD total_kern_pairs, ret, i, n, matches;
1140 hdc = GetDC(0);
1142 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1143 * which may render this test unusable, so we're trying to avoid that.
1145 SetLastError(0xdeadbeef);
1146 GetKerningPairsW(hdc, 0, NULL);
1147 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1149 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1150 ReleaseDC(0, hdc);
1151 return;
1154 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1156 OUTLINETEXTMETRICW otm;
1158 if (!is_font_installed(kd[i].face_name))
1160 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1161 continue;
1164 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1166 memset(&lf, 0, sizeof(lf));
1167 strcpy(lf.lfFaceName, kd[i].face_name);
1168 lf.lfHeight = kd[i].height;
1169 hfont = CreateFontIndirect(&lf);
1170 assert(hfont != 0);
1172 hfont_old = SelectObject(hdc, hfont);
1174 SetLastError(0xdeadbeef);
1175 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1176 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1178 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1179 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1180 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1181 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1182 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1183 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1185 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1186 kd[i].otmEMSquare, otm.otmEMSquare);
1187 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1188 kd[i].otmAscent, otm.otmAscent);
1189 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1190 kd[i].otmDescent, otm.otmDescent);
1191 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1192 kd[i].otmLineGap, otm.otmLineGap);
1193 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1194 kd[i].otmMacDescent, otm.otmMacDescent);
1195 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1196 kd[i].otmMacAscent, otm.otmMacAscent);
1197 todo_wine {
1198 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1199 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1200 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1201 kd[i].otmsXHeight, otm.otmsXHeight);
1202 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1203 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1204 kd[i].otmMacLineGap, otm.otmMacLineGap);
1205 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1206 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1209 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1210 trace("total_kern_pairs %u\n", total_kern_pairs);
1211 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1213 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1214 SetLastError(0xdeadbeef);
1215 ret = GetKerningPairsW(hdc, 0, kern_pair);
1216 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1217 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1218 ok(ret == 0, "got %lu, expected 0\n", ret);
1219 #endif
1221 ret = GetKerningPairsW(hdc, 100, NULL);
1222 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1224 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1225 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1227 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1228 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1230 matches = 0;
1232 for (n = 0; n < ret; n++)
1234 DWORD j;
1235 #if 0
1236 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1237 trace("{'%c','%c',%d},\n",
1238 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1239 #endif
1240 for (j = 0; j < kd[i].total_kern_pairs; j++)
1242 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1243 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1245 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1246 "pair %d:%d got %d, expected %d\n",
1247 kern_pair[n].wFirst, kern_pair[n].wSecond,
1248 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1249 matches++;
1254 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1255 matches, kd[i].total_kern_pairs);
1257 HeapFree(GetProcessHeap(), 0, kern_pair);
1259 SelectObject(hdc, hfont_old);
1260 DeleteObject(hfont);
1263 ReleaseDC(0, hdc);
1266 static void test_height_selection(void)
1268 static const struct font_data
1270 const char face_name[LF_FACESIZE];
1271 int requested_height;
1272 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1273 } fd[] =
1275 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1276 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1277 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1278 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1279 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1280 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1281 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1282 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1283 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1284 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1286 HDC hdc;
1287 LOGFONT lf;
1288 HFONT hfont, old_hfont;
1289 TEXTMETRIC tm;
1290 INT ret, i;
1292 hdc = CreateCompatibleDC(0);
1293 assert(hdc);
1295 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1297 if (!is_truetype_font_installed(fd[i].face_name))
1299 skip("%s is not installed\n", fd[i].face_name);
1300 continue;
1303 memset(&lf, 0, sizeof(lf));
1304 lf.lfHeight = fd[i].requested_height;
1305 lf.lfWeight = fd[i].weight;
1306 strcpy(lf.lfFaceName, fd[i].face_name);
1308 hfont = CreateFontIndirect(&lf);
1309 assert(hfont);
1311 old_hfont = SelectObject(hdc, hfont);
1312 ret = GetTextMetrics(hdc, &tm);
1313 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1314 if(fd[i].dpi == tm.tmDigitizedAspectX)
1316 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1317 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);
1318 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);
1319 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);
1320 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);
1321 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1322 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);
1323 #endif
1324 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);
1327 SelectObject(hdc, old_hfont);
1328 DeleteObject(hfont);
1331 DeleteDC(hdc);
1334 static void test_GetOutlineTextMetrics(void)
1336 OUTLINETEXTMETRIC *otm;
1337 LOGFONT lf;
1338 HFONT hfont, hfont_old;
1339 HDC hdc;
1340 DWORD ret, otm_size;
1341 LPSTR unset_ptr;
1343 if (!is_font_installed("Arial"))
1345 skip("Arial is not installed\n");
1346 return;
1349 hdc = GetDC(0);
1351 memset(&lf, 0, sizeof(lf));
1352 strcpy(lf.lfFaceName, "Arial");
1353 lf.lfHeight = -13;
1354 lf.lfWeight = FW_NORMAL;
1355 lf.lfPitchAndFamily = DEFAULT_PITCH;
1356 lf.lfQuality = PROOF_QUALITY;
1357 hfont = CreateFontIndirect(&lf);
1358 assert(hfont != 0);
1360 hfont_old = SelectObject(hdc, hfont);
1361 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1362 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1364 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1366 memset(otm, 0xAA, otm_size);
1367 SetLastError(0xdeadbeef);
1368 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1369 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1370 ok(ret == 1 /* Win9x */ ||
1371 ret == otm->otmSize /* XP*/,
1372 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1373 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1375 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1376 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1377 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1378 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1381 memset(otm, 0xAA, otm_size);
1382 SetLastError(0xdeadbeef);
1383 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1384 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1385 ok(ret == 1 /* Win9x */ ||
1386 ret == otm->otmSize /* XP*/,
1387 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1388 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1390 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1391 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1392 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1393 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1396 /* ask about truncated data */
1397 memset(otm, 0xAA, otm_size);
1398 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1399 SetLastError(0xdeadbeef);
1400 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1401 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1402 ok(ret == 1 /* Win9x */ ||
1403 ret == otm->otmSize /* XP*/,
1404 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1405 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1407 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1408 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1409 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1411 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1413 HeapFree(GetProcessHeap(), 0, otm);
1415 SelectObject(hdc, hfont_old);
1416 DeleteObject(hfont);
1418 ReleaseDC(0, hdc);
1421 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1423 INT y,
1424 breakCount,
1425 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1426 areaWidth = clientArea->right - clientArea->left,
1427 nErrors = 0, e;
1428 BOOL lastExtent = FALSE;
1429 PSTR pFirstChar, pLastChar;
1430 SIZE size;
1431 TEXTMETRICA tm;
1432 struct err
1434 char extent[100];
1435 int GetTextExtentExPointWWidth;
1436 } error[10];
1438 GetTextMetricsA(hdc, &tm);
1439 y = clientArea->top;
1440 do {
1441 breakCount = 0;
1442 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1443 pFirstChar = str;
1445 do {
1446 pLastChar = str;
1448 /* if not at the end of the string, ... */
1449 if (*str == '\0') break;
1450 /* ... add the next word to the current extent */
1451 while (*str != '\0' && *str++ != tm.tmBreakChar);
1452 breakCount++;
1453 SetTextJustification(hdc, 0, 0);
1454 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1455 } while ((int) size.cx < areaWidth);
1457 /* ignore trailing break chars */
1458 breakCount--;
1459 while (*(pLastChar - 1) == tm.tmBreakChar)
1461 pLastChar--;
1462 breakCount--;
1465 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1467 SetTextJustification(hdc, 0, 0);
1468 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1470 /* do not justify the last extent */
1471 if (*str != '\0' && breakCount > 0)
1473 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1474 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1475 justifiedWidth = size.cx;
1477 else lastExtent = TRUE;
1479 /* catch errors and report them */
1480 if (!lastExtent && (justifiedWidth != areaWidth))
1482 memset(error[nErrors].extent, 0, 100);
1483 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1484 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1485 nErrors++;
1488 y += size.cy;
1489 str = pLastChar;
1490 } while (*str && y < clientArea->bottom);
1492 for (e = 0; e < nErrors; e++)
1494 /* The width returned by GetTextExtentPoint32() is exactly the same
1495 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1496 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1497 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1498 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1502 static void test_SetTextJustification(void)
1504 HDC hdc;
1505 RECT clientArea;
1506 LOGFONTA lf;
1507 HFONT hfont;
1508 HWND hwnd;
1509 static char testText[] =
1510 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1511 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1512 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1513 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1514 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1515 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1516 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1518 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1519 GetClientRect( hwnd, &clientArea );
1520 hdc = GetDC( hwnd );
1522 memset(&lf, 0, sizeof lf);
1523 lf.lfCharSet = ANSI_CHARSET;
1524 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1525 lf.lfWeight = FW_DONTCARE;
1526 lf.lfHeight = 20;
1527 lf.lfQuality = DEFAULT_QUALITY;
1528 lstrcpyA(lf.lfFaceName, "Times New Roman");
1529 hfont = create_font("Times New Roman", &lf);
1530 SelectObject(hdc, hfont);
1532 testJustification(hdc, testText, &clientArea);
1534 DeleteObject(hfont);
1535 ReleaseDC(hwnd, hdc);
1536 DestroyWindow(hwnd);
1539 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1541 HDC hdc;
1542 LOGFONTA lf;
1543 HFONT hfont, hfont_old;
1544 CHARSETINFO csi;
1545 FONTSIGNATURE fs;
1546 INT cs;
1547 DWORD i, ret;
1548 char name[64];
1550 assert(count <= 128);
1552 memset(&lf, 0, sizeof(lf));
1554 lf.lfCharSet = charset;
1555 lf.lfHeight = 10;
1556 lstrcpyA(lf.lfFaceName, "Arial");
1557 SetLastError(0xdeadbeef);
1558 hfont = CreateFontIndirectA(&lf);
1559 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1561 hdc = GetDC(0);
1562 hfont_old = SelectObject(hdc, hfont);
1564 cs = GetTextCharsetInfo(hdc, &fs, 0);
1565 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1567 SetLastError(0xdeadbeef);
1568 ret = GetTextFaceA(hdc, sizeof(name), name);
1569 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1571 if (charset == SYMBOL_CHARSET)
1573 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1574 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1576 else
1578 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1579 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1582 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1584 trace("Can't find codepage for charset %d\n", cs);
1585 ReleaseDC(0, hdc);
1586 return FALSE;
1588 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1590 if (unicode)
1592 char ansi_buf[128];
1593 WCHAR unicode_buf[128];
1595 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1597 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1599 SetLastError(0xdeadbeef);
1600 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1601 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1603 else
1605 char ansi_buf[128];
1607 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1609 SetLastError(0xdeadbeef);
1610 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1611 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1614 SelectObject(hdc, hfont_old);
1615 DeleteObject(hfont);
1617 ReleaseDC(0, hdc);
1619 return TRUE;
1622 static void test_font_charset(void)
1624 static struct charset_data
1626 INT charset;
1627 UINT code_page;
1628 WORD font_idxA[128], font_idxW[128];
1629 } cd[] =
1631 { ANSI_CHARSET, 1252 },
1632 { RUSSIAN_CHARSET, 1251 },
1633 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1635 int i;
1637 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1639 win_skip("Skipping the font charset test on a Win9x platform\n");
1640 return;
1643 if (!is_font_installed("Arial"))
1645 skip("Arial is not installed\n");
1646 return;
1649 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1651 if (cd[i].charset == SYMBOL_CHARSET)
1653 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1655 skip("Symbol or Wingdings is not installed\n");
1656 break;
1659 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1660 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1661 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1664 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1665 if (i > 2)
1667 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1668 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1670 else
1671 skip("Symbol or Wingdings is not installed\n");
1674 static void test_GetFontUnicodeRanges(void)
1676 LOGFONTA lf;
1677 HDC hdc;
1678 HFONT hfont, hfont_old;
1679 DWORD size;
1680 GLYPHSET *gs;
1682 if (!pGetFontUnicodeRanges)
1684 win_skip("GetFontUnicodeRanges not available before W2K\n");
1685 return;
1688 memset(&lf, 0, sizeof(lf));
1689 lstrcpyA(lf.lfFaceName, "Arial");
1690 hfont = create_font("Arial", &lf);
1692 hdc = GetDC(0);
1693 hfont_old = SelectObject(hdc, hfont);
1695 size = pGetFontUnicodeRanges(NULL, NULL);
1696 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1698 size = pGetFontUnicodeRanges(hdc, NULL);
1699 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1701 gs = HeapAlloc(GetProcessHeap(), 0, size);
1703 size = pGetFontUnicodeRanges(hdc, gs);
1704 ok(size, "GetFontUnicodeRanges failed\n");
1705 #if 0
1706 for (i = 0; i < gs->cRanges; i++)
1707 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1708 #endif
1709 trace("found %u ranges\n", gs->cRanges);
1711 HeapFree(GetProcessHeap(), 0, gs);
1713 SelectObject(hdc, hfont_old);
1714 DeleteObject(hfont);
1715 ReleaseDC(NULL, hdc);
1718 #define MAX_ENUM_FONTS 4096
1720 struct enum_font_data
1722 int total;
1723 LOGFONT lf[MAX_ENUM_FONTS];
1726 struct enum_font_dataW
1728 int total;
1729 LOGFONTW lf[MAX_ENUM_FONTS];
1732 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1734 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1736 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1738 if (type != TRUETYPE_FONTTYPE) return 1;
1739 #if 0
1740 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1741 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1742 #endif
1743 if (efd->total < MAX_ENUM_FONTS)
1744 efd->lf[efd->total++] = *lf;
1745 else
1746 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1748 return 1;
1751 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1753 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1755 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1757 if (type != TRUETYPE_FONTTYPE) return 1;
1758 #if 0
1759 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1760 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1761 #endif
1762 if (efd->total < MAX_ENUM_FONTS)
1763 efd->lf[efd->total++] = *lf;
1764 else
1765 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1767 return 1;
1770 static void get_charset_stats(struct enum_font_data *efd,
1771 int *ansi_charset, int *symbol_charset,
1772 int *russian_charset)
1774 int i;
1776 *ansi_charset = 0;
1777 *symbol_charset = 0;
1778 *russian_charset = 0;
1780 for (i = 0; i < efd->total; i++)
1782 switch (efd->lf[i].lfCharSet)
1784 case ANSI_CHARSET:
1785 (*ansi_charset)++;
1786 break;
1787 case SYMBOL_CHARSET:
1788 (*symbol_charset)++;
1789 break;
1790 case RUSSIAN_CHARSET:
1791 (*russian_charset)++;
1792 break;
1797 static void get_charset_statsW(struct enum_font_dataW *efd,
1798 int *ansi_charset, int *symbol_charset,
1799 int *russian_charset)
1801 int i;
1803 *ansi_charset = 0;
1804 *symbol_charset = 0;
1805 *russian_charset = 0;
1807 for (i = 0; i < efd->total; i++)
1809 switch (efd->lf[i].lfCharSet)
1811 case ANSI_CHARSET:
1812 (*ansi_charset)++;
1813 break;
1814 case SYMBOL_CHARSET:
1815 (*symbol_charset)++;
1816 break;
1817 case RUSSIAN_CHARSET:
1818 (*russian_charset)++;
1819 break;
1824 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1826 struct enum_font_data efd;
1827 struct enum_font_dataW efdw;
1828 LOGFONT lf;
1829 HDC hdc;
1830 int i, ret, ansi_charset, symbol_charset, russian_charset;
1832 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1834 if (*font_name && !is_truetype_font_installed(font_name))
1836 skip("%s is not installed\n", font_name);
1837 return;
1840 hdc = GetDC(0);
1842 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1843 * while EnumFontFamiliesEx doesn't.
1845 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1848 * Use EnumFontFamiliesW since win98 crashes when the
1849 * second parameter is NULL using EnumFontFamilies
1851 efdw.total = 0;
1852 SetLastError(0xdeadbeef);
1853 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1854 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1855 if(ret)
1857 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1858 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1859 ansi_charset, symbol_charset, russian_charset);
1860 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1861 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1862 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1863 ok(russian_charset > 0 ||
1864 broken(russian_charset == 0), /* NT4 */
1865 "NULL family should enumerate RUSSIAN_CHARSET\n");
1868 efdw.total = 0;
1869 SetLastError(0xdeadbeef);
1870 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1871 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1872 if(ret)
1874 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1875 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1876 ansi_charset, symbol_charset, russian_charset);
1877 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1878 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1879 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1880 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1884 efd.total = 0;
1885 SetLastError(0xdeadbeef);
1886 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1887 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1888 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1889 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1890 ansi_charset, symbol_charset, russian_charset,
1891 *font_name ? font_name : "<empty>");
1892 if (*font_name)
1893 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1894 else
1895 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1896 for (i = 0; i < efd.total; i++)
1898 /* FIXME: remove completely once Wine is fixed */
1899 if (efd.lf[i].lfCharSet != font_charset)
1901 todo_wine
1902 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1904 else
1905 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1906 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1907 font_name, efd.lf[i].lfFaceName);
1910 memset(&lf, 0, sizeof(lf));
1911 lf.lfCharSet = ANSI_CHARSET;
1912 lstrcpy(lf.lfFaceName, font_name);
1913 efd.total = 0;
1914 SetLastError(0xdeadbeef);
1915 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1916 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1917 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1918 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1919 ansi_charset, symbol_charset, russian_charset,
1920 *font_name ? font_name : "<empty>");
1921 if (font_charset == SYMBOL_CHARSET)
1923 if (*font_name)
1924 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1925 else
1926 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1928 else
1930 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1931 for (i = 0; i < efd.total; i++)
1933 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1934 if (*font_name)
1935 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1936 font_name, efd.lf[i].lfFaceName);
1940 /* DEFAULT_CHARSET should enumerate all available charsets */
1941 memset(&lf, 0, sizeof(lf));
1942 lf.lfCharSet = DEFAULT_CHARSET;
1943 lstrcpy(lf.lfFaceName, font_name);
1944 efd.total = 0;
1945 SetLastError(0xdeadbeef);
1946 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1947 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1948 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1949 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1950 ansi_charset, symbol_charset, russian_charset,
1951 *font_name ? font_name : "<empty>");
1952 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1953 for (i = 0; i < efd.total; i++)
1955 if (*font_name)
1956 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1957 font_name, efd.lf[i].lfFaceName);
1959 if (*font_name)
1961 switch (font_charset)
1963 case ANSI_CHARSET:
1964 ok(ansi_charset > 0,
1965 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1966 ok(!symbol_charset,
1967 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1968 ok(russian_charset > 0,
1969 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1970 break;
1971 case SYMBOL_CHARSET:
1972 ok(!ansi_charset,
1973 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1974 ok(symbol_charset,
1975 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1976 ok(!russian_charset,
1977 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1978 break;
1979 case DEFAULT_CHARSET:
1980 ok(ansi_charset > 0,
1981 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1982 ok(symbol_charset > 0,
1983 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1984 ok(russian_charset > 0,
1985 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1986 break;
1989 else
1991 ok(ansi_charset > 0,
1992 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1993 ok(symbol_charset > 0,
1994 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1995 ok(russian_charset > 0,
1996 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1999 memset(&lf, 0, sizeof(lf));
2000 lf.lfCharSet = SYMBOL_CHARSET;
2001 lstrcpy(lf.lfFaceName, font_name);
2002 efd.total = 0;
2003 SetLastError(0xdeadbeef);
2004 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2005 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2006 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2007 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2008 ansi_charset, symbol_charset, russian_charset,
2009 *font_name ? font_name : "<empty>");
2010 if (*font_name && font_charset == ANSI_CHARSET)
2011 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2012 else
2014 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2015 for (i = 0; i < efd.total; i++)
2017 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2018 if (*font_name)
2019 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2020 font_name, efd.lf[i].lfFaceName);
2023 ok(!ansi_charset,
2024 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2025 ok(symbol_charset > 0,
2026 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2027 ok(!russian_charset,
2028 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2031 ReleaseDC(0, hdc);
2034 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2036 HFONT hfont, hfont_prev;
2037 DWORD ret;
2038 GLYPHMETRICS gm1, gm2;
2039 LOGFONTA lf2 = *lf;
2040 WORD idx;
2041 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2043 if(!pGetGlyphIndicesA)
2044 return;
2046 /* negative widths are handled just as positive ones */
2047 lf2.lfWidth = -lf->lfWidth;
2049 SetLastError(0xdeadbeef);
2050 hfont = CreateFontIndirectA(lf);
2051 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2052 check_font("original", lf, hfont);
2054 hfont_prev = SelectObject(hdc, hfont);
2056 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2057 if (ret == GDI_ERROR || idx == 0xffff)
2059 SelectObject(hdc, hfont_prev);
2060 DeleteObject(hfont);
2061 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2062 return;
2065 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2066 memset(&gm1, 0xab, sizeof(gm1));
2067 SetLastError(0xdeadbeef);
2068 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2069 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2071 SelectObject(hdc, hfont_prev);
2072 DeleteObject(hfont);
2074 SetLastError(0xdeadbeef);
2075 hfont = CreateFontIndirectA(&lf2);
2076 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2077 check_font("negative width", &lf2, hfont);
2079 hfont_prev = SelectObject(hdc, hfont);
2081 memset(&gm2, 0xbb, sizeof(gm2));
2082 SetLastError(0xdeadbeef);
2083 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2084 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2086 SelectObject(hdc, hfont_prev);
2087 DeleteObject(hfont);
2089 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2090 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2091 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2092 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2093 gm1.gmCellIncX == gm2.gmCellIncX &&
2094 gm1.gmCellIncY == gm2.gmCellIncY,
2095 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2096 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2097 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2098 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2099 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2102 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2103 #include "pshpack2.h"
2104 typedef struct
2106 USHORT version;
2107 SHORT xAvgCharWidth;
2108 USHORT usWeightClass;
2109 USHORT usWidthClass;
2110 SHORT fsType;
2111 SHORT ySubscriptXSize;
2112 SHORT ySubscriptYSize;
2113 SHORT ySubscriptXOffset;
2114 SHORT ySubscriptYOffset;
2115 SHORT ySuperscriptXSize;
2116 SHORT ySuperscriptYSize;
2117 SHORT ySuperscriptXOffset;
2118 SHORT ySuperscriptYOffset;
2119 SHORT yStrikeoutSize;
2120 SHORT yStrikeoutPosition;
2121 SHORT sFamilyClass;
2122 PANOSE panose;
2123 ULONG ulUnicodeRange1;
2124 ULONG ulUnicodeRange2;
2125 ULONG ulUnicodeRange3;
2126 ULONG ulUnicodeRange4;
2127 CHAR achVendID[4];
2128 USHORT fsSelection;
2129 USHORT usFirstCharIndex;
2130 USHORT usLastCharIndex;
2131 /* According to the Apple spec, original version didn't have the below fields,
2132 * version numbers were taked from the OpenType spec.
2134 /* version 0 (TrueType 1.5) */
2135 USHORT sTypoAscender;
2136 USHORT sTypoDescender;
2137 USHORT sTypoLineGap;
2138 USHORT usWinAscent;
2139 USHORT usWinDescent;
2140 /* version 1 (TrueType 1.66) */
2141 ULONG ulCodePageRange1;
2142 ULONG ulCodePageRange2;
2143 /* version 2 (OpenType 1.2) */
2144 SHORT sxHeight;
2145 SHORT sCapHeight;
2146 USHORT usDefaultChar;
2147 USHORT usBreakChar;
2148 USHORT usMaxContext;
2149 } TT_OS2_V2;
2150 #include "poppack.h"
2152 #ifdef WORDS_BIGENDIAN
2153 #define GET_BE_WORD(x) (x)
2154 #define GET_BE_DWORD(x) (x)
2155 #else
2156 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2157 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2158 #endif
2160 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2161 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2162 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2163 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2164 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2166 typedef struct
2168 USHORT version;
2169 USHORT num_tables;
2170 } cmap_header;
2172 typedef struct
2174 USHORT plat_id;
2175 USHORT enc_id;
2176 ULONG offset;
2177 } cmap_encoding_record;
2179 typedef struct
2181 USHORT format;
2182 USHORT length;
2183 USHORT language;
2185 BYTE glyph_ids[256];
2186 } cmap_format_0;
2188 typedef struct
2190 USHORT format;
2191 USHORT length;
2192 USHORT language;
2194 USHORT seg_countx2;
2195 USHORT search_range;
2196 USHORT entry_selector;
2197 USHORT range_shift;
2199 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2200 /* Then follows:
2201 USHORT pad;
2202 USHORT start_count[seg_countx2 / 2];
2203 USHORT id_delta[seg_countx2 / 2];
2204 USHORT id_range_offset[seg_countx2 / 2];
2205 USHORT glyph_ids[];
2207 } cmap_format_4;
2209 typedef struct
2211 USHORT end_count;
2212 USHORT start_count;
2213 USHORT id_delta;
2214 USHORT id_range_offset;
2215 } cmap_format_4_seg;
2217 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2219 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2220 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2221 os2->panose.bWeight, os2->panose.bProportion);
2224 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2226 int i;
2227 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2229 *first = 256;
2231 for(i = 0; i < 256; i++)
2233 if(cmap->glyph_ids[i] == 0) continue;
2234 *last = i;
2235 if(*first == 256) *first = i;
2237 if(*first == 256) return FALSE;
2238 return TRUE;
2241 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2243 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2244 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2245 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2246 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2247 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2250 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2252 int i;
2253 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2254 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2255 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2257 *first = 0x10000;
2259 for(i = 0; i < seg_count; i++)
2261 DWORD code, index;
2262 cmap_format_4_seg seg;
2264 get_seg4(cmap, i, &seg);
2265 for(code = seg.start_count; code <= seg.end_count; code++)
2267 if(seg.id_range_offset == 0)
2268 index = (seg.id_delta + code) & 0xffff;
2269 else
2271 index = seg.id_range_offset / 2
2272 + code - seg.start_count
2273 + i - seg_count;
2275 /* some fonts have broken last segment */
2276 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2277 index = GET_BE_WORD(glyph_ids[index]);
2278 else
2280 trace("segment %04x/%04x index %04x points to nowhere\n",
2281 seg.start_count, seg.end_count, index);
2282 index = 0;
2284 if(index) index += seg.id_delta;
2286 if(*first == 0x10000)
2287 *last = *first = code;
2288 else if(index)
2289 *last = code;
2293 if(*first == 0x10000) return FALSE;
2294 return TRUE;
2297 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2299 USHORT i;
2300 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2302 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2304 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2305 return (BYTE *)header + GET_BE_DWORD(record->offset);
2306 record++;
2308 return NULL;
2311 typedef enum
2313 cmap_none,
2314 cmap_ms_unicode,
2315 cmap_ms_symbol
2316 } cmap_type;
2318 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2320 LONG size, ret;
2321 cmap_header *header;
2322 void *cmap;
2323 BOOL r = FALSE;
2324 WORD format;
2326 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2327 ok(size != GDI_ERROR, "no cmap table found\n");
2328 if(size == GDI_ERROR) return FALSE;
2330 header = HeapAlloc(GetProcessHeap(), 0, size);
2331 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2332 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2333 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2335 cmap = get_cmap(header, 3, 1);
2336 if(cmap)
2337 *cmap_type = cmap_ms_unicode;
2338 else
2340 cmap = get_cmap(header, 3, 0);
2341 if(cmap) *cmap_type = cmap_ms_symbol;
2343 if(!cmap)
2345 *cmap_type = cmap_none;
2346 goto end;
2349 format = GET_BE_WORD(*(WORD *)cmap);
2350 switch(format)
2352 case 0:
2353 r = get_first_last_from_cmap0(cmap, first, last);
2354 break;
2355 case 4:
2356 r = get_first_last_from_cmap4(cmap, first, last, size);
2357 break;
2358 default:
2359 trace("unhandled cmap format %d\n", format);
2360 break;
2363 end:
2364 HeapFree(GetProcessHeap(), 0, header);
2365 return r;
2368 static void test_text_metrics(const LOGFONTA *lf)
2370 HDC hdc;
2371 HFONT hfont, hfont_old;
2372 TEXTMETRICA tmA;
2373 TT_OS2_V2 tt_os2;
2374 LONG size, ret;
2375 const char *font_name = lf->lfFaceName;
2376 DWORD cmap_first = 0, cmap_last = 0;
2377 cmap_type cmap_type;
2379 hdc = GetDC(0);
2381 SetLastError(0xdeadbeef);
2382 hfont = CreateFontIndirectA(lf);
2383 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2385 hfont_old = SelectObject(hdc, hfont);
2387 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2388 if (size == GDI_ERROR)
2390 trace("OS/2 chunk was not found\n");
2391 goto end_of_test;
2393 if (size > sizeof(tt_os2))
2395 trace("got too large OS/2 chunk of size %u\n", size);
2396 size = sizeof(tt_os2);
2399 memset(&tt_os2, 0, sizeof(tt_os2));
2400 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2401 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2403 SetLastError(0xdeadbeef);
2404 ret = GetTextMetricsA(hdc, &tmA);
2405 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2407 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2409 skip("Unable to retrieve first and last glyphs from cmap\n");
2411 else
2413 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2414 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2415 UINT os2_first_char, os2_last_char, default_char, break_char;
2416 USHORT version;
2417 TEXTMETRICW tmW;
2419 version = GET_BE_WORD(tt_os2.version);
2421 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2422 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2423 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2424 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2426 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2427 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2428 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2430 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2432 expect_first_W = 0;
2433 switch(GetACP())
2435 case 1257: /* Baltic */
2436 expect_last_W = 0xf8fd;
2437 break;
2438 default:
2439 expect_last_W = 0xf0ff;
2441 expect_break_W = 0x20;
2442 expect_default_W = expect_break_W - 1;
2443 expect_first_A = 0x1e;
2444 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2446 else
2448 expect_first_W = cmap_first;
2449 expect_last_W = min(cmap_last, os2_last_char);
2450 if(os2_first_char <= 1)
2451 expect_break_W = os2_first_char + 2;
2452 else if(os2_first_char > 0xff)
2453 expect_break_W = 0x20;
2454 else
2455 expect_break_W = os2_first_char;
2456 expect_default_W = expect_break_W - 1;
2457 expect_first_A = expect_default_W - 1;
2458 expect_last_A = min(expect_last_W, 0xff);
2460 expect_break_A = expect_break_W;
2461 expect_default_A = expect_default_W;
2463 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2464 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2465 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2466 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2467 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2468 else
2469 ok(tmA.tmFirstChar == expect_first_A ||
2470 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2471 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2472 ok(tmA.tmLastChar == expect_last_A ||
2473 tmA.tmLastChar == 0xff /* win9x */,
2474 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2475 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2476 font_name, tmA.tmBreakChar, expect_break_A);
2477 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2478 font_name, tmA.tmDefaultChar, expect_default_A);
2481 SetLastError(0xdeadbeef);
2482 ret = GetTextMetricsW(hdc, &tmW);
2483 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2484 "GetTextMetricsW error %u\n", GetLastError());
2485 if (ret)
2487 /* Wine uses the os2 first char */
2488 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2489 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2490 font_name, tmW.tmFirstChar, expect_first_W);
2491 else
2492 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2493 font_name, tmW.tmFirstChar, expect_first_W);
2495 /* Wine uses the os2 last char */
2496 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2497 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2498 font_name, tmW.tmLastChar, expect_last_W);
2499 else
2500 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2501 font_name, tmW.tmLastChar, expect_last_W);
2502 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2503 font_name, tmW.tmBreakChar, expect_break_W);
2504 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2505 font_name, tmW.tmDefaultChar, expect_default_W);
2507 /* Test the aspect ratio while we have tmW */
2508 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2509 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2510 tmW.tmDigitizedAspectX, ret);
2511 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2512 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2513 tmW.tmDigitizedAspectX, ret);
2517 /* test FF_ values */
2518 switch(tt_os2.panose.bFamilyType)
2520 case PAN_ANY:
2521 case PAN_NO_FIT:
2522 case PAN_FAMILY_TEXT_DISPLAY:
2523 case PAN_FAMILY_PICTORIAL:
2524 default:
2525 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2526 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2528 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2529 break;
2531 switch(tt_os2.panose.bSerifStyle)
2533 case PAN_ANY:
2534 case PAN_NO_FIT:
2535 default:
2536 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2537 break;
2539 case PAN_SERIF_COVE:
2540 case PAN_SERIF_OBTUSE_COVE:
2541 case PAN_SERIF_SQUARE_COVE:
2542 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2543 case PAN_SERIF_SQUARE:
2544 case PAN_SERIF_THIN:
2545 case PAN_SERIF_BONE:
2546 case PAN_SERIF_EXAGGERATED:
2547 case PAN_SERIF_TRIANGLE:
2548 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2549 break;
2551 case PAN_SERIF_NORMAL_SANS:
2552 case PAN_SERIF_OBTUSE_SANS:
2553 case PAN_SERIF_PERP_SANS:
2554 case PAN_SERIF_FLARED:
2555 case PAN_SERIF_ROUNDED:
2556 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2557 break;
2559 break;
2561 case PAN_FAMILY_SCRIPT:
2562 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2563 break;
2565 case PAN_FAMILY_DECORATIVE:
2566 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2567 break;
2570 test_negative_width(hdc, lf);
2572 end_of_test:
2573 SelectObject(hdc, hfont_old);
2574 DeleteObject(hfont);
2576 ReleaseDC(0, hdc);
2579 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2581 INT *enumed = (INT *)lParam;
2583 if (type == TRUETYPE_FONTTYPE)
2585 (*enumed)++;
2586 test_text_metrics(lf);
2588 return 1;
2591 static void test_GetTextMetrics(void)
2593 LOGFONTA lf;
2594 HDC hdc;
2595 INT enumed;
2597 /* Report only once */
2598 if(!pGetGlyphIndicesA)
2599 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2601 hdc = GetDC(0);
2603 memset(&lf, 0, sizeof(lf));
2604 lf.lfCharSet = DEFAULT_CHARSET;
2605 enumed = 0;
2606 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2607 trace("Tested metrics of %d truetype fonts\n", enumed);
2609 ReleaseDC(0, hdc);
2612 static void test_nonexistent_font(void)
2614 static const struct
2616 const char *name;
2617 int charset;
2618 } font_subst[] =
2620 { "Times New Roman Baltic", 186 },
2621 { "Times New Roman CE", 238 },
2622 { "Times New Roman CYR", 204 },
2623 { "Times New Roman Greek", 161 },
2624 { "Times New Roman TUR", 162 }
2626 LOGFONTA lf;
2627 HDC hdc;
2628 HFONT hfont;
2629 CHARSETINFO csi;
2630 INT cs, expected_cs, i;
2631 char buf[LF_FACESIZE];
2633 if (!is_truetype_font_installed("Arial") ||
2634 !is_truetype_font_installed("Times New Roman"))
2636 skip("Arial or Times New Roman not installed\n");
2637 return;
2640 expected_cs = GetACP();
2641 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2643 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2644 return;
2646 expected_cs = csi.ciCharset;
2647 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2649 hdc = GetDC(0);
2651 memset(&lf, 0, sizeof(lf));
2652 lf.lfHeight = 100;
2653 lf.lfWeight = FW_REGULAR;
2654 lf.lfCharSet = ANSI_CHARSET;
2655 lf.lfPitchAndFamily = FF_SWISS;
2656 strcpy(lf.lfFaceName, "Nonexistent font");
2657 hfont = CreateFontIndirectA(&lf);
2658 hfont = SelectObject(hdc, hfont);
2659 GetTextFaceA(hdc, sizeof(buf), buf);
2660 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2661 cs = GetTextCharset(hdc);
2662 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2663 DeleteObject(SelectObject(hdc, hfont));
2665 memset(&lf, 0, sizeof(lf));
2666 lf.lfHeight = -13;
2667 lf.lfWeight = FW_DONTCARE;
2668 strcpy(lf.lfFaceName, "Nonexistent font");
2669 hfont = CreateFontIndirectA(&lf);
2670 hfont = SelectObject(hdc, hfont);
2671 GetTextFaceA(hdc, sizeof(buf), buf);
2672 todo_wine /* Wine uses Arial for all substitutions */
2673 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2674 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2675 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2676 "Got %s\n", buf);
2677 cs = GetTextCharset(hdc);
2678 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2679 DeleteObject(SelectObject(hdc, hfont));
2681 memset(&lf, 0, sizeof(lf));
2682 lf.lfHeight = -13;
2683 lf.lfWeight = FW_REGULAR;
2684 strcpy(lf.lfFaceName, "Nonexistent font");
2685 hfont = CreateFontIndirectA(&lf);
2686 hfont = SelectObject(hdc, hfont);
2687 GetTextFaceA(hdc, sizeof(buf), buf);
2688 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2689 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2690 cs = GetTextCharset(hdc);
2691 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2692 DeleteObject(SelectObject(hdc, hfont));
2694 memset(&lf, 0, sizeof(lf));
2695 lf.lfHeight = -13;
2696 lf.lfWeight = FW_DONTCARE;
2697 strcpy(lf.lfFaceName, "Times New Roman");
2698 hfont = CreateFontIndirectA(&lf);
2699 hfont = SelectObject(hdc, hfont);
2700 GetTextFaceA(hdc, sizeof(buf), buf);
2701 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2702 cs = GetTextCharset(hdc);
2703 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2704 DeleteObject(SelectObject(hdc, hfont));
2706 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2708 memset(&lf, 0, sizeof(lf));
2709 lf.lfHeight = -13;
2710 lf.lfWeight = FW_REGULAR;
2711 strcpy(lf.lfFaceName, font_subst[i].name);
2712 hfont = CreateFontIndirectA(&lf);
2713 hfont = SelectObject(hdc, hfont);
2714 cs = GetTextCharset(hdc);
2715 if (font_subst[i].charset == expected_cs)
2717 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2718 GetTextFaceA(hdc, sizeof(buf), buf);
2719 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2721 else
2723 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2724 GetTextFaceA(hdc, sizeof(buf), buf);
2725 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2726 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2728 DeleteObject(SelectObject(hdc, hfont));
2730 memset(&lf, 0, sizeof(lf));
2731 lf.lfHeight = -13;
2732 lf.lfWeight = FW_DONTCARE;
2733 strcpy(lf.lfFaceName, font_subst[i].name);
2734 hfont = CreateFontIndirectA(&lf);
2735 hfont = SelectObject(hdc, hfont);
2736 GetTextFaceA(hdc, sizeof(buf), buf);
2737 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2738 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2739 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2740 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2741 "got %s for font %s\n", buf, font_subst[i].name);
2742 cs = GetTextCharset(hdc);
2743 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2744 DeleteObject(SelectObject(hdc, hfont));
2747 ReleaseDC(0, hdc);
2750 static void test_GdiRealizationInfo(void)
2752 HDC hdc;
2753 DWORD info[4];
2754 BOOL r;
2755 HFONT hfont, hfont_old;
2756 LOGFONTA lf;
2758 if(!pGdiRealizationInfo)
2760 win_skip("GdiRealizationInfo not available\n");
2761 return;
2764 hdc = GetDC(0);
2766 memset(info, 0xcc, sizeof(info));
2767 r = pGdiRealizationInfo(hdc, info);
2768 ok(r != 0, "ret 0\n");
2769 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2770 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2772 if (!is_truetype_font_installed("Arial"))
2774 skip("skipping GdiRealizationInfo with truetype font\n");
2775 goto end;
2778 memset(&lf, 0, sizeof(lf));
2779 strcpy(lf.lfFaceName, "Arial");
2780 lf.lfHeight = 20;
2781 lf.lfWeight = FW_NORMAL;
2782 hfont = CreateFontIndirectA(&lf);
2783 hfont_old = SelectObject(hdc, hfont);
2785 memset(info, 0xcc, sizeof(info));
2786 r = pGdiRealizationInfo(hdc, info);
2787 ok(r != 0, "ret 0\n");
2788 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2789 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2791 DeleteObject(SelectObject(hdc, hfont_old));
2793 end:
2794 ReleaseDC(0, hdc);
2797 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2798 the nul in the count of characters copied when the face name buffer is not
2799 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2800 always includes it. */
2801 static void test_GetTextFace(void)
2803 static const char faceA[] = "Tahoma";
2804 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2805 LOGFONTA fA = {0};
2806 LOGFONTW fW = {0};
2807 char bufA[LF_FACESIZE];
2808 WCHAR bufW[LF_FACESIZE];
2809 HFONT f, g;
2810 HDC dc;
2811 int n;
2813 if(!is_font_installed("Tahoma"))
2815 skip("Tahoma is not installed so skipping this test\n");
2816 return;
2819 /* 'A' case. */
2820 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2821 f = CreateFontIndirectA(&fA);
2822 ok(f != NULL, "CreateFontIndirectA failed\n");
2824 dc = GetDC(NULL);
2825 g = SelectObject(dc, f);
2826 n = GetTextFaceA(dc, sizeof bufA, bufA);
2827 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2828 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2830 /* Play with the count arg. */
2831 bufA[0] = 'x';
2832 n = GetTextFaceA(dc, 0, bufA);
2833 ok(n == 0, "GetTextFaceA returned %d\n", n);
2834 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2836 bufA[0] = 'x';
2837 n = GetTextFaceA(dc, 1, bufA);
2838 ok(n == 0, "GetTextFaceA returned %d\n", n);
2839 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2841 bufA[0] = 'x'; bufA[1] = 'y';
2842 n = GetTextFaceA(dc, 2, bufA);
2843 ok(n == 1, "GetTextFaceA returned %d\n", n);
2844 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2846 n = GetTextFaceA(dc, 0, NULL);
2847 ok(n == sizeof faceA ||
2848 broken(n == 0), /* win98, winMe */
2849 "GetTextFaceA returned %d\n", n);
2851 DeleteObject(SelectObject(dc, g));
2852 ReleaseDC(NULL, dc);
2854 /* 'W' case. */
2855 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2856 SetLastError(0xdeadbeef);
2857 f = CreateFontIndirectW(&fW);
2858 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2860 win_skip("CreateFontIndirectW is not implemented\n");
2861 return;
2863 ok(f != NULL, "CreateFontIndirectW failed\n");
2865 dc = GetDC(NULL);
2866 g = SelectObject(dc, f);
2867 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2868 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2869 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2871 /* Play with the count arg. */
2872 bufW[0] = 'x';
2873 n = GetTextFaceW(dc, 0, bufW);
2874 ok(n == 0, "GetTextFaceW returned %d\n", n);
2875 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2877 bufW[0] = 'x';
2878 n = GetTextFaceW(dc, 1, bufW);
2879 ok(n == 1, "GetTextFaceW returned %d\n", n);
2880 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2882 bufW[0] = 'x'; bufW[1] = 'y';
2883 n = GetTextFaceW(dc, 2, bufW);
2884 ok(n == 2, "GetTextFaceW returned %d\n", n);
2885 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2887 n = GetTextFaceW(dc, 0, NULL);
2888 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2890 DeleteObject(SelectObject(dc, g));
2891 ReleaseDC(NULL, dc);
2894 static void test_orientation(void)
2896 static const char test_str[11] = "Test String";
2897 HDC hdc;
2898 LOGFONTA lf;
2899 HFONT hfont, old_hfont;
2900 SIZE size;
2902 if (!is_truetype_font_installed("Arial"))
2904 skip("Arial is not installed\n");
2905 return;
2908 hdc = CreateCompatibleDC(0);
2909 memset(&lf, 0, sizeof(lf));
2910 lstrcpyA(lf.lfFaceName, "Arial");
2911 lf.lfHeight = 72;
2912 lf.lfOrientation = lf.lfEscapement = 900;
2913 hfont = create_font("orientation", &lf);
2914 old_hfont = SelectObject(hdc, hfont);
2915 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2916 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2917 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2918 SelectObject(hdc, old_hfont);
2919 DeleteObject(hfont);
2920 DeleteDC(hdc);
2923 static void test_oemcharset(void)
2925 HDC hdc;
2926 LOGFONTA lf, clf;
2927 HFONT hfont, old_hfont;
2928 int charset;
2930 hdc = CreateCompatibleDC(0);
2931 ZeroMemory(&lf, sizeof(lf));
2932 lf.lfHeight = 12;
2933 lf.lfCharSet = OEM_CHARSET;
2934 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
2935 lstrcpyA(lf.lfFaceName, "Terminal");
2936 hfont = CreateFontIndirectA(&lf);
2937 old_hfont = SelectObject(hdc, hfont);
2938 charset = GetTextCharset(hdc);
2939 todo_wine
2940 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
2941 hfont = SelectObject(hdc, old_hfont);
2942 GetObjectA(hfont, sizeof(clf), &clf);
2943 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
2944 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
2945 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
2946 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
2947 DeleteObject(hfont);
2948 DeleteDC(hdc);
2951 static void test_GetGlyphOutline(void)
2953 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2954 HDC hdc;
2955 GLYPHMETRICS gm;
2956 LOGFONTA lf;
2957 HFONT hfont, old_hfont;
2958 INT ret;
2960 if (!is_truetype_font_installed("Tahoma"))
2962 skip("Tahoma is not installed\n");
2963 return;
2966 hdc = CreateCompatibleDC(0);
2967 memset(&lf, 0, sizeof(lf));
2968 lf.lfHeight = 72;
2969 lstrcpyA(lf.lfFaceName, "Tahoma");
2970 SetLastError(0xdeadbeef);
2971 hfont = CreateFontIndirectA(&lf);
2972 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2973 old_hfont = SelectObject(hdc, hfont);
2975 memset(&gm, 0, sizeof(gm));
2976 SetLastError(0xdeadbeef);
2977 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2978 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2980 memset(&gm, 0, sizeof(gm));
2981 SetLastError(0xdeadbeef);
2982 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2983 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2984 ok(GetLastError() == 0xdeadbeef ||
2985 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2986 "expected 0xdeadbeef, got %u\n", GetLastError());
2988 memset(&gm, 0, sizeof(gm));
2989 SetLastError(0xdeadbeef);
2990 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2991 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2992 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
2994 memset(&gm, 0, sizeof(gm));
2995 SetLastError(0xdeadbeef);
2996 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2997 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2999 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3000 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3003 /* test for needed buffer size request on space char */
3004 memset(&gm, 0, sizeof(gm));
3005 SetLastError(0xdeadbeef);
3006 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3007 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3008 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3010 /* requesting buffer size for space char + error */
3011 memset(&gm, 0, sizeof(gm));
3012 SetLastError(0xdeadbeef);
3013 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3014 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3016 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3017 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3020 SelectObject(hdc, old_hfont);
3021 DeleteObject(hfont);
3022 DeleteDC(hdc);
3025 /* bug #9995: there is a limit to the character width that can be specified */
3026 static void test_GetTextMetrics2(const char *fontname, int font_height)
3028 HFONT of, hf;
3029 HDC hdc;
3030 TEXTMETRICA tm;
3031 BOOL ret;
3032 int ave_width, height, width, ratio, scale;
3034 if (!is_truetype_font_installed( fontname)) {
3035 skip("%s is not installed\n", fontname);
3036 return;
3038 hdc = CreateCompatibleDC(0);
3039 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3040 /* select width = 0 */
3041 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3042 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3043 DEFAULT_QUALITY, VARIABLE_PITCH,
3044 fontname);
3045 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3046 of = SelectObject( hdc, hf);
3047 ret = GetTextMetricsA( hdc, &tm);
3048 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3049 height = tm.tmHeight;
3050 ave_width = tm.tmAveCharWidth;
3051 SelectObject( hdc, of);
3052 DeleteObject( hf);
3054 trace("height %d, ave width %d\n", height, ave_width);
3056 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3058 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3059 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3060 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3061 ok(hf != 0, "CreateFont failed\n");
3062 of = SelectObject(hdc, hf);
3063 ret = GetTextMetrics(hdc, &tm);
3064 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3065 SelectObject(hdc, of);
3066 DeleteObject(hf);
3068 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3069 break;
3072 DeleteDC(hdc);
3074 ratio = width / height;
3075 scale = width / ave_width;
3077 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3078 width, height, ratio, width, ave_width, scale);
3080 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3083 static void test_CreateFontIndirect(void)
3085 LOGFONTA lf, getobj_lf;
3086 int ret, i;
3087 HFONT hfont;
3088 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3090 memset(&lf, 0, sizeof(lf));
3091 lf.lfCharSet = ANSI_CHARSET;
3092 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3093 lf.lfHeight = 16;
3094 lf.lfWidth = 16;
3095 lf.lfQuality = DEFAULT_QUALITY;
3096 lf.lfItalic = FALSE;
3097 lf.lfWeight = FW_DONTCARE;
3099 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3101 lstrcpyA(lf.lfFaceName, TestName[i]);
3102 hfont = CreateFontIndirectA(&lf);
3103 ok(hfont != 0, "CreateFontIndirectA failed\n");
3104 SetLastError(0xdeadbeef);
3105 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3106 ok(ret, "GetObject failed: %d\n", GetLastError());
3107 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3108 ok(lf.lfWeight == getobj_lf.lfWeight ||
3109 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3110 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3111 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3112 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3113 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3114 DeleteObject(hfont);
3118 static void test_CreateFontIndirectEx(void)
3120 ENUMLOGFONTEXDVA lfex;
3121 HFONT hfont;
3123 if (!pCreateFontIndirectExA)
3125 win_skip("CreateFontIndirectExA is not available\n");
3126 return;
3129 if (!is_truetype_font_installed("Arial"))
3131 skip("Arial is not installed\n");
3132 return;
3135 SetLastError(0xdeadbeef);
3136 hfont = pCreateFontIndirectExA(NULL);
3137 ok(hfont == NULL, "got %p\n", hfont);
3138 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3140 memset(&lfex, 0, sizeof(lfex));
3141 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3142 hfont = pCreateFontIndirectExA(&lfex);
3143 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3144 if (hfont)
3145 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3146 DeleteObject(hfont);
3149 static void free_font(void *font)
3151 UnmapViewOfFile(font);
3154 static void *load_font(const char *font_name, DWORD *font_size)
3156 char file_name[MAX_PATH];
3157 HANDLE file, mapping;
3158 void *font;
3160 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3161 strcat(file_name, "\\fonts\\");
3162 strcat(file_name, font_name);
3164 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3165 if (file == INVALID_HANDLE_VALUE) return NULL;
3167 *font_size = GetFileSize(file, NULL);
3169 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3170 if (!mapping)
3172 CloseHandle(file);
3173 return NULL;
3176 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3178 CloseHandle(file);
3179 CloseHandle(mapping);
3180 return font;
3183 static void test_AddFontMemResource(void)
3185 void *font;
3186 DWORD font_size, num_fonts;
3187 HANDLE ret;
3188 DEVMODEA dmA;
3189 BOOL is_winxp;
3191 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3193 win_skip("AddFontMemResourceEx is not available on this platform\n");
3194 return;
3197 font = load_font("sserife.fon", &font_size);
3198 if (!font)
3200 skip("Unable to locate and load font sserife.fon\n");
3201 return;
3204 is_winxp = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dmA) &&
3205 (dmA.dmFields & DM_DISPLAYORIENTATION);
3207 if (is_winxp)
3209 SetLastError(0xdeadbeef);
3210 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3211 ok(!ret, "AddFontMemResourceEx should fail\n");
3212 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3213 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3214 GetLastError());
3216 SetLastError(0xdeadbeef);
3217 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3218 ok(!ret, "AddFontMemResourceEx should fail\n");
3219 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3220 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3221 GetLastError());
3223 SetLastError(0xdeadbeef);
3224 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3225 ok(!ret, "AddFontMemResourceEx should fail\n");
3226 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3227 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3228 GetLastError());
3230 SetLastError(0xdeadbeef);
3231 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3232 ok(!ret, "AddFontMemResourceEx should fail\n");
3233 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3234 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3235 GetLastError());
3237 SetLastError(0xdeadbeef);
3238 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3239 ok(!ret, "AddFontMemResourceEx should fail\n");
3240 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3241 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3242 GetLastError());
3244 SetLastError(0xdeadbeef);
3245 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3246 ok(!ret, "AddFontMemResourceEx should fail\n");
3247 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3248 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3249 GetLastError());
3251 num_fonts = 0xdeadbeef;
3252 SetLastError(0xdeadbeef);
3253 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3254 ok(!ret, "AddFontMemResourceEx should fail\n");
3255 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3256 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3257 GetLastError());
3258 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3260 num_fonts = 0xdeadbeef;
3261 SetLastError(0xdeadbeef);
3262 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3263 ok(!ret, "AddFontMemResourceEx should fail\n");
3264 ok(GetLastError() == 0xdeadbeef,
3265 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3266 GetLastError());
3267 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3269 else
3270 win_skip("AddFontMemResourceEx invalid parameter tests are problematic on Win2k\n");
3272 num_fonts = 0xdeadbeef;
3273 SetLastError(0xdeadbeef);
3274 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3275 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3276 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3277 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3279 free_font(font);
3281 SetLastError(0xdeadbeef);
3282 ok(pRemoveFontMemResourceEx(ret), "RemoveFontMemResourceEx error %d\n", GetLastError());
3284 /* test invalid pointer to number of loaded fonts */
3285 font = load_font("sserife.fon", &font_size);
3286 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3288 SetLastError(0xdeadbeef);
3289 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3290 ok(!ret, "AddFontMemResourceEx should fail\n");
3291 ok(GetLastError() == 0xdeadbeef,
3292 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3293 GetLastError());
3295 SetLastError(0xdeadbeef);
3296 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3297 ok(!ret, "AddFontMemResourceEx should fail\n");
3298 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3299 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3300 GetLastError());
3302 free_font(font);
3305 START_TEST(font)
3307 init();
3309 test_logfont();
3310 test_bitmap_font();
3311 test_outline_font();
3312 test_bitmap_font_metrics();
3313 test_GdiGetCharDimensions();
3314 test_GetCharABCWidths();
3315 test_text_extents();
3316 test_GetGlyphIndices();
3317 test_GetKerningPairs();
3318 test_GetOutlineTextMetrics();
3319 test_SetTextJustification();
3320 test_font_charset();
3321 test_GetFontUnicodeRanges();
3322 test_nonexistent_font();
3323 test_orientation();
3324 test_height_selection();
3325 test_AddFontMemResource();
3327 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3328 * I'd like to avoid them in this test.
3330 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3331 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3332 if (is_truetype_font_installed("Arial Black") &&
3333 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3335 test_EnumFontFamilies("", ANSI_CHARSET);
3336 test_EnumFontFamilies("", SYMBOL_CHARSET);
3337 test_EnumFontFamilies("", DEFAULT_CHARSET);
3339 else
3340 skip("Arial Black or Symbol/Wingdings is not installed\n");
3341 test_GetTextMetrics();
3342 test_GdiRealizationInfo();
3343 test_GetTextFace();
3344 test_GetGlyphOutline();
3345 test_GetTextMetrics2("Tahoma", -11);
3346 test_GetTextMetrics2("Tahoma", -55);
3347 test_GetTextMetrics2("Tahoma", -110);
3348 test_GetTextMetrics2("Arial", -11);
3349 test_GetTextMetrics2("Arial", -55);
3350 test_GetTextMetrics2("Arial", -110);
3351 test_CreateFontIndirect();
3352 test_CreateFontIndirectEx();
3353 test_oemcharset();