gdi32: Don't remove leading '@' from face name.
[wine/multimedia.git] / dlls / gdi32 / tests / font.c
blob98c61a09c9583094ad5f7ac699771ee8d6f605b1
1 /*
2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
46 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
48 static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
49 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
50 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
51 static BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static INT (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
53 static BOOL (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
55 static HMODULE hgdi32 = 0;
56 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
58 static void init(void)
60 hgdi32 = GetModuleHandleA("gdi32.dll");
62 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
63 pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
64 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
65 pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
66 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
67 pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
68 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
69 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
70 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
71 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
72 pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
73 pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
74 pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
75 pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
76 pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
79 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
81 if (type != TRUETYPE_FONTTYPE) return 1;
83 return 0;
86 static BOOL is_truetype_font_installed(const char *name)
88 HDC hdc = GetDC(0);
89 BOOL ret = FALSE;
91 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
92 ret = TRUE;
94 ReleaseDC(0, hdc);
95 return ret;
98 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
100 return 0;
103 static BOOL is_font_installed(const char *name)
105 HDC hdc = GetDC(0);
106 BOOL ret = FALSE;
108 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
109 ret = TRUE;
111 ReleaseDC(0, hdc);
112 return ret;
115 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
117 LOGFONTA getobj_lf;
118 int ret, minlen = 0;
120 if (!hfont)
121 return;
123 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
124 /* NT4 tries to be clever and only returns the minimum length */
125 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
126 minlen++;
127 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
128 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
129 ok(lf->lfHeight == getobj_lf.lfHeight ||
130 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
131 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
132 ok(lf->lfWidth == getobj_lf.lfWidth ||
133 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
134 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
135 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
136 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
137 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
138 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
139 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
140 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
141 ok(lf->lfWeight == getobj_lf.lfWeight ||
142 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
143 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
144 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
145 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
146 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
147 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
148 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
149 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
150 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
151 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
152 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
153 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
154 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
157 static HFONT create_font(const char* test, const LOGFONTA* lf)
159 HFONT hfont = CreateFontIndirectA(lf);
160 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
161 if (hfont)
162 check_font(test, lf, hfont);
163 return hfont;
166 static void test_logfont(void)
168 LOGFONTA lf;
169 HFONT hfont;
171 memset(&lf, 0, sizeof lf);
173 lf.lfCharSet = ANSI_CHARSET;
174 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
175 lf.lfWeight = FW_DONTCARE;
176 lf.lfHeight = 16;
177 lf.lfWidth = 16;
178 lf.lfQuality = DEFAULT_QUALITY;
180 lstrcpyA(lf.lfFaceName, "Arial");
181 hfont = create_font("Arial", &lf);
182 DeleteObject(hfont);
184 memset(&lf, 'A', sizeof(lf));
185 hfont = CreateFontIndirectA(&lf);
186 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
188 lf.lfFaceName[LF_FACESIZE - 1] = 0;
189 check_font("AAA...", &lf, hfont);
190 DeleteObject(hfont);
193 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
195 if (type & RASTER_FONTTYPE)
197 LOGFONT *lf = (LOGFONT *)lParam;
198 *lf = *elf;
199 return 0; /* stop enumeration */
202 return 1; /* continue enumeration */
205 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
207 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
208 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
209 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
210 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
211 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
212 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
213 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
214 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
215 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
216 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
217 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
218 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
219 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
220 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
221 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
222 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
223 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
224 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
225 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
226 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
229 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
230 LONG lfWidth, const char *test_str,
231 INT test_str_len, const TEXTMETRICA *tm_orig,
232 const SIZE *size_orig, INT width_of_A_orig,
233 INT scale_x, INT scale_y)
235 LOGFONTA lf;
236 OUTLINETEXTMETRIC otm;
237 TEXTMETRICA tm;
238 SIZE size;
239 INT width_of_A, cx, cy;
240 UINT ret;
242 if (!hfont)
243 return;
245 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
247 GetObjectA(hfont, sizeof(lf), &lf);
249 if (GetOutlineTextMetricsA(hdc, 0, NULL))
251 otm.otmSize = sizeof(otm) / 2;
252 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253 ok(ret == sizeof(otm)/2 /* XP */ ||
254 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
256 memset(&otm, 0x1, sizeof(otm));
257 otm.otmSize = sizeof(otm);
258 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259 ok(ret == sizeof(otm) /* XP */ ||
260 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
262 memset(&tm, 0x2, sizeof(tm));
263 ret = GetTextMetricsA(hdc, &tm);
264 ok(ret, "GetTextMetricsA failed\n");
265 /* the structure size is aligned */
266 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
268 ok(0, "tm != otm\n");
269 compare_tm(&tm, &otm.otmTextMetrics);
272 tm = otm.otmTextMetrics;
273 if (0) /* these metrics are scaled too, but with rounding errors */
275 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
276 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
278 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
279 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
280 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
281 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
282 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
283 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
285 else
287 ret = GetTextMetricsA(hdc, &tm);
288 ok(ret, "GetTextMetricsA failed\n");
291 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
292 cy = tm.tmHeight / tm_orig->tmHeight;
293 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
294 lfHeight, scale_x, scale_y, cx, cy);
295 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
296 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
297 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
298 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
299 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
301 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
302 if (lf.lfHeight)
304 if (lf.lfWidth)
305 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
307 else
308 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
310 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
312 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
313 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
315 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
317 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
320 /* Test how GDI scales bitmap font metrics */
321 static void test_bitmap_font(void)
323 static const char test_str[11] = "Test String";
324 HDC hdc;
325 LOGFONTA bitmap_lf;
326 HFONT hfont, old_hfont;
327 TEXTMETRICA tm_orig;
328 SIZE size_orig;
329 INT ret, i, width_orig, height_orig, scale, lfWidth;
331 hdc = GetDC(0);
333 /* "System" has only 1 pixel size defined, otherwise the test breaks */
334 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
335 if (ret)
337 ReleaseDC(0, hdc);
338 trace("no bitmap fonts were found, skipping the test\n");
339 return;
342 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
344 height_orig = bitmap_lf.lfHeight;
345 lfWidth = bitmap_lf.lfWidth;
347 hfont = create_font("bitmap", &bitmap_lf);
348 old_hfont = SelectObject(hdc, hfont);
349 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
350 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
351 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
352 SelectObject(hdc, old_hfont);
353 DeleteObject(hfont);
355 bitmap_lf.lfHeight = 0;
356 bitmap_lf.lfWidth = 4;
357 hfont = create_font("bitmap", &bitmap_lf);
358 old_hfont = SelectObject(hdc, hfont);
359 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
360 SelectObject(hdc, old_hfont);
361 DeleteObject(hfont);
363 bitmap_lf.lfHeight = height_orig;
364 bitmap_lf.lfWidth = lfWidth;
366 /* test fractional scaling */
367 for (i = 1; i <= height_orig * 6; i++)
369 INT nearest_height;
371 bitmap_lf.lfHeight = i;
372 hfont = create_font("fractional", &bitmap_lf);
373 scale = (i + height_orig - 1) / height_orig;
374 nearest_height = scale * height_orig;
375 /* Only jump to the next height if the difference <= 25% original height */
376 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
377 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
378 so we'll not test this particular height. */
379 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
380 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
381 old_hfont = SelectObject(hdc, hfont);
382 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
383 SelectObject(hdc, old_hfont);
384 DeleteObject(hfont);
387 /* test integer scaling 3x2 */
388 bitmap_lf.lfHeight = height_orig * 2;
389 bitmap_lf.lfWidth *= 3;
390 hfont = create_font("3x2", &bitmap_lf);
391 old_hfont = SelectObject(hdc, hfont);
392 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
393 SelectObject(hdc, old_hfont);
394 DeleteObject(hfont);
396 /* test integer scaling 3x3 */
397 bitmap_lf.lfHeight = height_orig * 3;
398 bitmap_lf.lfWidth = 0;
399 hfont = create_font("3x3", &bitmap_lf);
400 old_hfont = SelectObject(hdc, hfont);
401 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
402 SelectObject(hdc, old_hfont);
403 DeleteObject(hfont);
405 ReleaseDC(0, hdc);
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
411 static const char test_str[11] = "Test String";
412 HDC hdc, hdc_2;
413 LOGFONTA lf;
414 HFONT hfont, old_hfont, old_hfont_2;
415 OUTLINETEXTMETRICA otm;
416 SIZE size_orig;
417 INT width_orig, height_orig, lfWidth;
418 XFORM xform;
419 GLYPHMETRICS gm;
420 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
421 POINT pt;
422 INT ret;
424 if (!is_truetype_font_installed("Arial"))
426 skip("Arial is not installed\n");
427 return;
430 hdc = CreateCompatibleDC(0);
432 memset(&lf, 0, sizeof(lf));
433 strcpy(lf.lfFaceName, "Arial");
434 lf.lfHeight = 72;
435 hfont = create_font("outline", &lf);
436 old_hfont = SelectObject(hdc, hfont);
437 otm.otmSize = sizeof(otm);
438 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
442 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
443 SelectObject(hdc, old_hfont);
444 DeleteObject(hfont);
446 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
447 lf.lfHeight = otm.otmEMSquare;
448 lf.lfHeight = -lf.lfHeight;
449 hfont = create_font("outline", &lf);
450 old_hfont = SelectObject(hdc, hfont);
451 otm.otmSize = sizeof(otm);
452 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
453 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
454 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
455 SelectObject(hdc, old_hfont);
456 DeleteObject(hfont);
458 height_orig = otm.otmTextMetrics.tmHeight;
459 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
461 /* test integer scaling 3x2 */
462 lf.lfHeight = height_orig * 2;
463 lf.lfWidth = lfWidth * 3;
464 hfont = create_font("3x2", &lf);
465 old_hfont = SelectObject(hdc, hfont);
466 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
467 SelectObject(hdc, old_hfont);
468 DeleteObject(hfont);
470 /* test integer scaling 3x3 */
471 lf.lfHeight = height_orig * 3;
472 lf.lfWidth = lfWidth * 3;
473 hfont = create_font("3x3", &lf);
474 old_hfont = SelectObject(hdc, hfont);
475 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
476 SelectObject(hdc, old_hfont);
477 DeleteObject(hfont);
479 /* test integer scaling 1x1 */
480 lf.lfHeight = height_orig * 1;
481 lf.lfWidth = lfWidth * 1;
482 hfont = create_font("1x1", &lf);
483 old_hfont = SelectObject(hdc, hfont);
484 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485 SelectObject(hdc, old_hfont);
486 DeleteObject(hfont);
488 /* test integer scaling 1x1 */
489 lf.lfHeight = height_orig;
490 lf.lfWidth = 0;
491 hfont = create_font("1x1", &lf);
492 old_hfont = SelectObject(hdc, hfont);
493 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
495 /* with an identity matrix */
496 memset(&gm, 0, sizeof(gm));
497 SetLastError(0xdeadbeef);
498 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
499 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
500 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
501 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
502 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
503 /* with a custom matrix */
504 memset(&gm, 0, sizeof(gm));
505 SetLastError(0xdeadbeef);
506 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
507 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
508 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
509 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
510 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
512 /* Test that changing the DC transformation affects only the font
513 * selected on this DC and doesn't affect the same font selected on
514 * another DC.
516 hdc_2 = CreateCompatibleDC(0);
517 old_hfont_2 = SelectObject(hdc_2, hfont);
518 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
520 SetMapMode(hdc, MM_ANISOTROPIC);
522 /* font metrics on another DC should be unchanged */
523 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
525 /* test restrictions of compatibility mode GM_COMPATIBLE */
526 /* part 1: rescaling only X should not change font scaling on screen.
527 So compressing the X axis by 2 is not done, and this
528 appears as X scaling of 2 that no one requested. */
529 SetWindowExtEx(hdc, 100, 100, NULL);
530 SetViewportExtEx(hdc, 50, 100, NULL);
531 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
532 /* font metrics on another DC should be unchanged */
533 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
535 /* part 2: rescaling only Y should change font scaling.
536 As also X is scaled by a factor of 2, but this is not
537 requested by the DC transformation, we get a scaling factor
538 of 2 in the X coordinate. */
539 SetViewportExtEx(hdc, 100, 200, NULL);
540 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
541 /* font metrics on another DC should be unchanged */
542 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
544 /* restore scaling */
545 SetMapMode(hdc, MM_TEXT);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
550 SelectObject(hdc_2, old_hfont_2);
551 DeleteDC(hdc_2);
553 if (!SetGraphicsMode(hdc, GM_ADVANCED))
555 SelectObject(hdc, old_hfont);
556 DeleteObject(hfont);
557 DeleteDC(hdc);
558 skip("GM_ADVANCED is not supported on this platform\n");
559 return;
562 xform.eM11 = 20.0f;
563 xform.eM12 = 0.0f;
564 xform.eM21 = 0.0f;
565 xform.eM22 = 20.0f;
566 xform.eDx = 0.0f;
567 xform.eDy = 0.0f;
569 SetLastError(0xdeadbeef);
570 ret = SetWorldTransform(hdc, &xform);
571 ok(ret, "SetWorldTransform error %u\n", GetLastError());
573 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
575 /* with an identity matrix */
576 memset(&gm, 0, sizeof(gm));
577 SetLastError(0xdeadbeef);
578 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581 pt.x = width_orig; pt.y = 0;
582 LPtoDP(hdc, &pt, 1);
583 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
584 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
585 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
586 /* with a custom matrix */
587 memset(&gm, 0, sizeof(gm));
588 SetLastError(0xdeadbeef);
589 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
590 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
591 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
592 pt.x = width_orig; pt.y = 0;
593 LPtoDP(hdc, &pt, 1);
594 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
595 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
596 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598 SetLastError(0xdeadbeef);
599 ret = SetMapMode(hdc, MM_LOMETRIC);
600 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
602 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
604 /* with an identity matrix */
605 memset(&gm, 0, sizeof(gm));
606 SetLastError(0xdeadbeef);
607 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
608 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610 pt.x = width_orig; pt.y = 0;
611 LPtoDP(hdc, &pt, 1);
612 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
613 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
614 /* with a custom matrix */
615 memset(&gm, 0, sizeof(gm));
616 SetLastError(0xdeadbeef);
617 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
618 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
619 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
620 pt.x = width_orig; pt.y = 0;
621 LPtoDP(hdc, &pt, 1);
622 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
623 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
625 SetLastError(0xdeadbeef);
626 ret = SetMapMode(hdc, MM_TEXT);
627 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
629 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
631 /* with an identity matrix */
632 memset(&gm, 0, sizeof(gm));
633 SetLastError(0xdeadbeef);
634 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
635 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
636 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
637 pt.x = width_orig; pt.y = 0;
638 LPtoDP(hdc, &pt, 1);
639 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
640 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
641 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
642 /* with a custom matrix */
643 memset(&gm, 0, sizeof(gm));
644 SetLastError(0xdeadbeef);
645 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
646 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
647 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
648 pt.x = width_orig; pt.y = 0;
649 LPtoDP(hdc, &pt, 1);
650 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
651 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
652 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
654 SelectObject(hdc, old_hfont);
655 DeleteObject(hfont);
656 DeleteDC(hdc);
659 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
661 LOGFONT *lf = (LOGFONT *)lParam;
663 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
665 *lf = *elf;
666 return 0; /* stop enumeration */
668 return 1; /* continue enumeration */
671 static void test_bitmap_font_metrics(void)
673 static const struct font_data
675 const char face_name[LF_FACESIZE];
676 int weight, height, ascent, descent, int_leading, ext_leading;
677 int ave_char_width, max_char_width, dpi;
678 BYTE first_char, last_char, def_char, break_char;
679 DWORD ansi_bitfield;
680 WORD skip_lang_id;
681 } fd[] =
683 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
684 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
685 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
686 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
687 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
688 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
689 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
690 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
691 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
692 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
693 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
694 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
695 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
696 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
697 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
698 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
700 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
701 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
702 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
703 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
704 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
705 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
706 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
707 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
708 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
709 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
710 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
711 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
713 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
714 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
715 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
716 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
717 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
718 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
719 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
720 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
721 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
722 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
723 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
724 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
725 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
726 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
727 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
728 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
729 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
731 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
732 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
733 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
734 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
735 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
736 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
737 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
738 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
739 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
740 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
741 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
743 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
744 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
745 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
747 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
748 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
749 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
751 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
752 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
753 { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
755 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
756 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
758 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
759 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
760 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN },
761 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
762 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
765 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
766 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC },
767 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN },
768 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
769 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
770 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC },
771 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN },
772 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
773 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
774 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC },
775 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN },
776 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
777 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC },
778 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN },
780 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
781 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
782 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
783 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
784 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
785 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
786 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
787 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
788 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
789 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
790 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
791 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
793 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
794 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
795 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
797 /* The 120dpi version still has its dpi marked as 96 */
798 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
800 /* FIXME: add "Terminal" */
802 HDC hdc;
803 LOGFONT lf;
804 HFONT hfont, old_hfont;
805 TEXTMETRIC tm;
806 INT ret, i;
807 WORD system_lang_id;
809 system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
811 hdc = CreateCompatibleDC(0);
812 assert(hdc);
814 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
816 int bit;
818 memset(&lf, 0, sizeof(lf));
820 lf.lfHeight = fd[i].height;
821 strcpy(lf.lfFaceName, fd[i].face_name);
823 for(bit = 0; bit < 32; bit++)
825 DWORD fs[2];
826 CHARSETINFO csi;
827 BOOL bRet;
829 fs[0] = 1L << bit;
830 fs[1] = 0;
831 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
832 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
834 lf.lfCharSet = csi.ciCharset;
835 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
836 if (ret) continue;
838 hfont = create_font(lf.lfFaceName, &lf);
839 old_hfont = SelectObject(hdc, hfont);
840 bRet = GetTextMetrics(hdc, &tm);
841 ok(bRet, "GetTextMetrics error %d\n", GetLastError());
842 if(fd[i].dpi == tm.tmDigitizedAspectX)
844 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
845 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
847 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
848 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
849 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
850 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
851 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
852 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
853 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
854 ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmFirstChar);
855 ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmLastChar);
856 ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmDefaultChar);
857 ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, fd[i].height, tm.tmBreakChar);
859 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
860 that make the max width bigger */
861 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
862 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
864 else
865 skip("Skipping font metrics test for system langid 0x%x\n",
866 system_lang_id);
868 SelectObject(hdc, old_hfont);
869 DeleteObject(hfont);
873 DeleteDC(hdc);
876 static void test_GdiGetCharDimensions(void)
878 HDC hdc;
879 TEXTMETRICW tm;
880 LONG ret;
881 SIZE size;
882 LONG avgwidth, height;
883 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
885 if (!pGdiGetCharDimensions)
887 win_skip("GdiGetCharDimensions not available on this platform\n");
888 return;
891 hdc = CreateCompatibleDC(NULL);
893 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
894 avgwidth = ((size.cx / 26) + 1) / 2;
896 ret = pGdiGetCharDimensions(hdc, &tm, &height);
897 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
898 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
900 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
901 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
903 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
904 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
906 height = 0;
907 ret = pGdiGetCharDimensions(hdc, NULL, &height);
908 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
909 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
911 DeleteDC(hdc);
914 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
915 const TEXTMETRIC *lpntme,
916 DWORD FontType, LPARAM lParam)
918 if (FontType & TRUETYPE_FONTTYPE)
920 HFONT hfont;
922 hfont = CreateFontIndirect(lpelfe);
923 if (hfont)
925 *(HFONT *)lParam = hfont;
926 return 0;
930 return 1;
933 static void test_GetCharABCWidths(void)
935 static const WCHAR str[] = {'a',0};
936 BOOL ret;
937 HDC hdc;
938 LOGFONTA lf;
939 HFONT hfont;
940 ABC abc[1];
941 ABCFLOAT abcf[1];
942 WORD glyphs[1];
943 DWORD nb;
944 static const struct
946 UINT first;
947 UINT last;
948 } range[] =
950 {0xff, 0xff},
951 {0x100, 0x100},
952 {0xff, 0x100},
953 {0x1ff, 0xff00},
954 {0xffff, 0xffff},
955 {0x10000, 0x10000},
956 {0xffff, 0x10000},
957 {0xffffff, 0xffffff},
958 {0x1000000, 0x1000000},
959 {0xffffff, 0x1000000},
960 {0xffffffff, 0xffffffff}
962 static const struct
964 UINT cs;
965 UINT a;
966 UINT w;
967 BOOL r[sizeof range / sizeof range[0]];
968 } c[] =
970 {ANSI_CHARSET, 0x30, 0x30, {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
971 {SHIFTJIS_CHARSET, 0x82a0, 0x3042, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
972 {HANGEUL_CHARSET, 0x8141, 0xac02, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
973 {JOHAB_CHARSET, 0x8446, 0x3135, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
974 {GB2312_CHARSET, 0x8141, 0x4e04, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}},
975 {CHINESEBIG5_CHARSET, 0xa142, 0x3001, {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}}
977 UINT i;
979 if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
981 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
982 return;
985 memset(&lf, 0, sizeof(lf));
986 strcpy(lf.lfFaceName, "System");
987 lf.lfHeight = 20;
989 hfont = CreateFontIndirectA(&lf);
990 hdc = GetDC(0);
991 hfont = SelectObject(hdc, hfont);
993 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
994 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
996 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
997 ok(!ret, "GetCharABCWidthsI should have failed\n");
999 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1000 ok(!ret, "GetCharABCWidthsI should have failed\n");
1002 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1003 ok(ret, "GetCharABCWidthsI should have succeeded\n");
1005 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1006 ok(!ret, "GetCharABCWidthsW should have failed\n");
1008 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1009 ok(!ret, "GetCharABCWidthsW should have failed\n");
1011 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1012 ok(!ret, "GetCharABCWidthsW should have failed\n");
1014 ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1015 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1017 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1018 ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1020 ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1021 ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1023 hfont = SelectObject(hdc, hfont);
1024 DeleteObject(hfont);
1026 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1028 ABC a[2], w[2];
1029 ABC full[256];
1030 UINT code = 0x41, j;
1032 lf.lfFaceName[0] = '\0';
1033 lf.lfCharSet = c[i].cs;
1034 lf.lfPitchAndFamily = 0;
1035 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1037 skip("TrueType font for charset %u is not installed\n", c[i].cs);
1038 continue;
1041 memset(a, 0, sizeof a);
1042 memset(w, 0, sizeof w);
1043 hfont = SelectObject(hdc, hfont);
1044 ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1045 pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1046 memcmp(a, w, sizeof a) == 0,
1047 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1049 memset(a, 0xbb, sizeof a);
1050 ret = pGetCharABCWidthsA(hdc, code, code, a);
1051 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1052 memset(full, 0xcc, sizeof full);
1053 ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1054 ok(ret, "GetCharABCWidthsA should have succeeded\n");
1055 ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1056 "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1058 for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1060 ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1061 ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1062 range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1065 hfont = SelectObject(hdc, hfont);
1066 DeleteObject(hfont);
1069 ReleaseDC(NULL, hdc);
1072 static void test_text_extents(void)
1074 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1075 LPINT extents;
1076 INT i, len, fit1, fit2;
1077 LOGFONTA lf;
1078 TEXTMETRICA tm;
1079 HDC hdc;
1080 HFONT hfont;
1081 SIZE sz;
1082 SIZE sz1, sz2;
1083 BOOL ret;
1085 memset(&lf, 0, sizeof(lf));
1086 strcpy(lf.lfFaceName, "Arial");
1087 lf.lfHeight = 20;
1089 hfont = CreateFontIndirectA(&lf);
1090 hdc = GetDC(0);
1091 hfont = SelectObject(hdc, hfont);
1092 GetTextMetricsA(hdc, &tm);
1093 GetTextExtentPointA(hdc, "o", 1, &sz);
1094 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1096 SetLastError(0xdeadbeef);
1097 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1098 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1100 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1101 hfont = SelectObject(hdc, hfont);
1102 DeleteObject(hfont);
1103 ReleaseDC(0, hdc);
1104 return;
1107 len = lstrlenW(wt);
1108 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1109 extents[0] = 1; /* So that the increasing sequence test will fail
1110 if the extents array is untouched. */
1111 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1112 GetTextExtentPointW(hdc, wt, len, &sz2);
1113 ok(sz1.cy == sz2.cy,
1114 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1115 /* Because of the '\n' in the string GetTextExtentExPoint and
1116 GetTextExtentPoint return different widths under Win2k, but
1117 under WinXP they return the same width. So we don't test that
1118 here. */
1120 for (i = 1; i < len; ++i)
1121 ok(extents[i-1] <= extents[i],
1122 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1124 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1125 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1126 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1127 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1128 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1129 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1130 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1131 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1132 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1133 ok(extents[0] == extents[2] && extents[1] == extents[3],
1134 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1135 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1136 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1137 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1138 HeapFree(GetProcessHeap(), 0, extents);
1140 /* extents functions fail with -ve counts (the interesting case being -1) */
1141 ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1142 ok(ret == FALSE, "got %d\n", ret);
1143 ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1144 ok(ret == FALSE, "got %d\n", ret);
1145 ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1146 ok(ret == FALSE, "got %d\n", ret);
1148 /* max_extent = 0 succeeds and returns zero */
1149 fit1 = fit2 = -215;
1150 ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1151 ok(ret == TRUE ||
1152 broken(ret == FALSE), /* NT4, 2k */
1153 "got %d\n", ret);
1154 ok(fit1 == 0 ||
1155 broken(fit1 == -215), /* NT4, 2k */
1156 "fit = %d\n", fit1);
1157 ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1158 ok(ret == TRUE, "got %d\n", ret);
1159 ok(fit2 == 0, "fit = %d\n", fit2);
1161 /* max_extent = -1 is interpreted as a very large width that will
1162 * definitely fit our three characters */
1163 fit1 = fit2 = -215;
1164 ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1165 ok(ret == TRUE, "got %d\n", ret);
1166 todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1167 ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1168 ok(ret == TRUE, "got %d\n", ret);
1169 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1171 /* max_extent = -2 is interpreted similarly, but the Ansi version
1172 * rejects it while the Unicode one accepts it */
1173 fit1 = fit2 = -215;
1174 ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1175 todo_wine ok(ret == FALSE, "got %d\n", ret);
1176 todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1177 ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1178 ok(ret == TRUE, "got %d\n", ret);
1179 todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1181 hfont = SelectObject(hdc, hfont);
1182 DeleteObject(hfont);
1183 ReleaseDC(NULL, hdc);
1186 static void test_GetGlyphIndices(void)
1188 HDC hdc;
1189 HFONT hfont;
1190 DWORD charcount;
1191 LOGFONTA lf;
1192 DWORD flags = 0;
1193 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1194 WORD glyphs[(sizeof(testtext)/2)-1];
1195 TEXTMETRIC textm;
1196 HFONT hOldFont;
1198 if (!pGetGlyphIndicesW) {
1199 win_skip("GetGlyphIndicesW not available on platform\n");
1200 return;
1203 hdc = GetDC(0);
1205 memset(&lf, 0, sizeof(lf));
1206 strcpy(lf.lfFaceName, "System");
1207 lf.lfHeight = 16;
1208 lf.lfCharSet = ANSI_CHARSET;
1210 hfont = CreateFontIndirectA(&lf);
1211 ok(hfont != 0, "CreateFontIndirectEx failed\n");
1212 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1213 if (textm.tmCharSet == ANSI_CHARSET)
1215 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1216 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1217 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1218 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1219 flags = 0;
1220 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1221 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1222 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1223 textm.tmDefaultChar, glyphs[4]);
1225 else
1226 /* FIXME: Write tests for non-ANSI charsets. */
1227 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1229 if(!is_font_installed("Tahoma"))
1231 skip("Tahoma is not installed so skipping this test\n");
1232 return;
1234 memset(&lf, 0, sizeof(lf));
1235 strcpy(lf.lfFaceName, "Tahoma");
1236 lf.lfHeight = 20;
1238 hfont = CreateFontIndirectA(&lf);
1239 hOldFont = SelectObject(hdc, hfont);
1240 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1241 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1242 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1243 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1244 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1245 flags = 0;
1246 testtext[0] = textm.tmDefaultChar;
1247 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1248 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1249 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1250 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1251 DeleteObject(SelectObject(hdc, hOldFont));
1254 static void test_GetKerningPairs(void)
1256 static const struct kerning_data
1258 const char face_name[LF_FACESIZE];
1259 LONG height;
1260 /* some interesting fields from OUTLINETEXTMETRIC */
1261 LONG tmHeight, tmAscent, tmDescent;
1262 UINT otmEMSquare;
1263 INT otmAscent;
1264 INT otmDescent;
1265 UINT otmLineGap;
1266 UINT otmsCapEmHeight;
1267 UINT otmsXHeight;
1268 INT otmMacAscent;
1269 INT otmMacDescent;
1270 UINT otmMacLineGap;
1271 UINT otmusMinimumPPEM;
1272 /* small subset of kerning pairs to test */
1273 DWORD total_kern_pairs;
1274 const KERNINGPAIR kern_pair[26];
1275 } kd[] =
1277 {"Arial", 12, 12, 9, 3,
1278 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1281 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1282 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1283 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1284 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1285 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1286 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1287 {933,970,+1},{933,972,-1}
1290 {"Arial", -34, 39, 32, 7,
1291 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1294 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1295 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1296 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1297 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1298 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1299 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1300 {933,970,+2},{933,972,-3}
1303 { "Arial", 120, 120, 97, 23,
1304 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1307 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1308 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1309 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1310 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1311 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1312 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1313 {933,970,+6},{933,972,-10}
1316 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1317 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1318 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1321 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1322 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1323 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1324 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1325 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1326 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1327 {933,970,+54},{933,972,-83}
1330 #endif
1332 LOGFONT lf;
1333 HFONT hfont, hfont_old;
1334 KERNINGPAIR *kern_pair;
1335 HDC hdc;
1336 DWORD total_kern_pairs, ret, i, n, matches;
1338 hdc = GetDC(0);
1340 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1341 * which may render this test unusable, so we're trying to avoid that.
1343 SetLastError(0xdeadbeef);
1344 GetKerningPairsW(hdc, 0, NULL);
1345 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1347 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1348 ReleaseDC(0, hdc);
1349 return;
1352 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1354 OUTLINETEXTMETRICW otm;
1355 UINT uiRet;
1357 if (!is_font_installed(kd[i].face_name))
1359 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1360 continue;
1363 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1365 memset(&lf, 0, sizeof(lf));
1366 strcpy(lf.lfFaceName, kd[i].face_name);
1367 lf.lfHeight = kd[i].height;
1368 hfont = CreateFontIndirect(&lf);
1369 assert(hfont != 0);
1371 hfont_old = SelectObject(hdc, hfont);
1373 SetLastError(0xdeadbeef);
1374 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1375 uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1376 ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1378 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1379 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1380 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1381 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1382 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1383 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1385 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1386 kd[i].otmEMSquare, otm.otmEMSquare);
1387 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1388 kd[i].otmAscent, otm.otmAscent);
1389 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1390 kd[i].otmDescent, otm.otmDescent);
1391 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1392 kd[i].otmLineGap, otm.otmLineGap);
1393 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1394 kd[i].otmMacDescent, otm.otmMacDescent);
1395 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1396 kd[i].otmMacAscent, otm.otmMacAscent);
1397 todo_wine {
1398 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1399 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1400 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1401 kd[i].otmsXHeight, otm.otmsXHeight);
1402 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1403 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1404 kd[i].otmMacLineGap, otm.otmMacLineGap);
1405 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1406 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1409 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1410 trace("total_kern_pairs %u\n", total_kern_pairs);
1411 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1413 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1414 * passes on XP.
1416 SetLastError(0xdeadbeef);
1417 ret = GetKerningPairsW(hdc, 0, kern_pair);
1418 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1419 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1420 ok(ret == 0, "got %u, expected 0\n", ret);
1422 ret = GetKerningPairsW(hdc, 100, NULL);
1423 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1425 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1426 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1428 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1429 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1431 matches = 0;
1433 for (n = 0; n < ret; n++)
1435 DWORD j;
1436 /* Disabled to limit console spam */
1437 if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1438 trace("{'%c','%c',%d},\n",
1439 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1440 for (j = 0; j < kd[i].total_kern_pairs; j++)
1442 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1443 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1445 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1446 "pair %d:%d got %d, expected %d\n",
1447 kern_pair[n].wFirst, kern_pair[n].wSecond,
1448 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1449 matches++;
1454 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1455 matches, kd[i].total_kern_pairs);
1457 HeapFree(GetProcessHeap(), 0, kern_pair);
1459 SelectObject(hdc, hfont_old);
1460 DeleteObject(hfont);
1463 ReleaseDC(0, hdc);
1466 static void test_height_selection(void)
1468 static const struct font_data
1470 const char face_name[LF_FACESIZE];
1471 int requested_height;
1472 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1473 } fd[] =
1475 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1476 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1477 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1478 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1479 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1480 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1481 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1482 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1483 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1484 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1486 HDC hdc;
1487 LOGFONT lf;
1488 HFONT hfont, old_hfont;
1489 TEXTMETRIC tm;
1490 INT ret, i;
1492 hdc = CreateCompatibleDC(0);
1493 assert(hdc);
1495 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1497 if (!is_truetype_font_installed(fd[i].face_name))
1499 skip("%s is not installed\n", fd[i].face_name);
1500 continue;
1503 memset(&lf, 0, sizeof(lf));
1504 lf.lfHeight = fd[i].requested_height;
1505 lf.lfWeight = fd[i].weight;
1506 strcpy(lf.lfFaceName, fd[i].face_name);
1508 hfont = CreateFontIndirect(&lf);
1509 assert(hfont);
1511 old_hfont = SelectObject(hdc, hfont);
1512 ret = GetTextMetrics(hdc, &tm);
1513 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1514 if(fd[i].dpi == tm.tmDigitizedAspectX)
1516 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1517 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);
1518 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);
1519 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);
1520 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);
1521 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1522 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);
1523 #endif
1524 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);
1527 SelectObject(hdc, old_hfont);
1528 DeleteObject(hfont);
1531 DeleteDC(hdc);
1534 static void test_GetOutlineTextMetrics(void)
1536 OUTLINETEXTMETRIC *otm;
1537 LOGFONT lf;
1538 HFONT hfont, hfont_old;
1539 HDC hdc;
1540 DWORD ret, otm_size;
1541 LPSTR unset_ptr;
1543 if (!is_font_installed("Arial"))
1545 skip("Arial is not installed\n");
1546 return;
1549 hdc = GetDC(0);
1551 memset(&lf, 0, sizeof(lf));
1552 strcpy(lf.lfFaceName, "Arial");
1553 lf.lfHeight = -13;
1554 lf.lfWeight = FW_NORMAL;
1555 lf.lfPitchAndFamily = DEFAULT_PITCH;
1556 lf.lfQuality = PROOF_QUALITY;
1557 hfont = CreateFontIndirect(&lf);
1558 assert(hfont != 0);
1560 hfont_old = SelectObject(hdc, hfont);
1561 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1562 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1564 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1566 memset(otm, 0xAA, otm_size);
1567 SetLastError(0xdeadbeef);
1568 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1569 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1570 ok(ret == 1 /* Win9x */ ||
1571 ret == otm->otmSize /* XP*/,
1572 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1573 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1575 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1576 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1577 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1578 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1581 memset(otm, 0xAA, otm_size);
1582 SetLastError(0xdeadbeef);
1583 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1584 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1585 ok(ret == 1 /* Win9x */ ||
1586 ret == otm->otmSize /* XP*/,
1587 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1588 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1590 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1591 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1592 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1593 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1596 /* ask about truncated data */
1597 memset(otm, 0xAA, otm_size);
1598 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1599 SetLastError(0xdeadbeef);
1600 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1601 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1602 ok(ret == 1 /* Win9x */ ||
1603 ret == otm->otmSize /* XP*/,
1604 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1605 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1607 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1608 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1609 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1611 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1613 HeapFree(GetProcessHeap(), 0, otm);
1615 SelectObject(hdc, hfont_old);
1616 DeleteObject(hfont);
1618 ReleaseDC(0, hdc);
1621 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1623 INT y,
1624 breakCount,
1625 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1626 areaWidth = clientArea->right - clientArea->left,
1627 nErrors = 0, e;
1628 BOOL lastExtent = FALSE;
1629 PSTR pFirstChar, pLastChar;
1630 SIZE size;
1631 TEXTMETRICA tm;
1632 struct err
1634 char extent[100];
1635 int GetTextExtentExPointWWidth;
1636 } error[10];
1638 GetTextMetricsA(hdc, &tm);
1639 y = clientArea->top;
1640 do {
1641 breakCount = 0;
1642 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1643 pFirstChar = str;
1645 do {
1646 pLastChar = str;
1648 /* if not at the end of the string, ... */
1649 if (*str == '\0') break;
1650 /* ... add the next word to the current extent */
1651 while (*str != '\0' && *str++ != tm.tmBreakChar);
1652 breakCount++;
1653 SetTextJustification(hdc, 0, 0);
1654 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1655 } while ((int) size.cx < areaWidth);
1657 /* ignore trailing break chars */
1658 breakCount--;
1659 while (*(pLastChar - 1) == tm.tmBreakChar)
1661 pLastChar--;
1662 breakCount--;
1665 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1667 SetTextJustification(hdc, 0, 0);
1668 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1670 /* do not justify the last extent */
1671 if (*str != '\0' && breakCount > 0)
1673 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1674 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1675 justifiedWidth = size.cx;
1677 else lastExtent = TRUE;
1679 /* catch errors and report them */
1680 if (!lastExtent && (justifiedWidth != areaWidth))
1682 memset(error[nErrors].extent, 0, 100);
1683 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1684 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1685 nErrors++;
1688 y += size.cy;
1689 str = pLastChar;
1690 } while (*str && y < clientArea->bottom);
1692 for (e = 0; e < nErrors; e++)
1694 /* The width returned by GetTextExtentPoint32() is exactly the same
1695 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1696 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1697 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1698 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1702 static void test_SetTextJustification(void)
1704 HDC hdc;
1705 RECT clientArea;
1706 LOGFONTA lf;
1707 HFONT hfont;
1708 HWND hwnd;
1709 static char testText[] =
1710 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1711 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1712 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1713 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1714 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1715 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1716 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1718 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1719 GetClientRect( hwnd, &clientArea );
1720 hdc = GetDC( hwnd );
1722 memset(&lf, 0, sizeof lf);
1723 lf.lfCharSet = ANSI_CHARSET;
1724 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1725 lf.lfWeight = FW_DONTCARE;
1726 lf.lfHeight = 20;
1727 lf.lfQuality = DEFAULT_QUALITY;
1728 lstrcpyA(lf.lfFaceName, "Times New Roman");
1729 hfont = create_font("Times New Roman", &lf);
1730 SelectObject(hdc, hfont);
1732 testJustification(hdc, testText, &clientArea);
1734 DeleteObject(hfont);
1735 ReleaseDC(hwnd, hdc);
1736 DestroyWindow(hwnd);
1739 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1741 HDC hdc;
1742 LOGFONTA lf;
1743 HFONT hfont, hfont_old;
1744 CHARSETINFO csi;
1745 FONTSIGNATURE fs;
1746 INT cs;
1747 DWORD i, ret;
1748 char name[64];
1750 assert(count <= 128);
1752 memset(&lf, 0, sizeof(lf));
1754 lf.lfCharSet = charset;
1755 lf.lfHeight = 10;
1756 lstrcpyA(lf.lfFaceName, "Arial");
1757 SetLastError(0xdeadbeef);
1758 hfont = CreateFontIndirectA(&lf);
1759 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1761 hdc = GetDC(0);
1762 hfont_old = SelectObject(hdc, hfont);
1764 cs = GetTextCharsetInfo(hdc, &fs, 0);
1765 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1767 SetLastError(0xdeadbeef);
1768 ret = GetTextFaceA(hdc, sizeof(name), name);
1769 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1771 if (charset == SYMBOL_CHARSET)
1773 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1774 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1776 else
1778 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1779 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1782 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1784 trace("Can't find codepage for charset %d\n", cs);
1785 ReleaseDC(0, hdc);
1786 return FALSE;
1788 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1790 if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1792 skip("Font code page %d, looking for code page %d\n",
1793 pGdiGetCodePage(hdc), code_page);
1794 ReleaseDC(0, hdc);
1795 return FALSE;
1798 if (unicode)
1800 char ansi_buf[128];
1801 WCHAR unicode_buf[128];
1803 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1805 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1807 SetLastError(0xdeadbeef);
1808 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1809 ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1810 count, ret, GetLastError());
1812 else
1814 char ansi_buf[128];
1816 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1818 SetLastError(0xdeadbeef);
1819 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1820 ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1821 count, ret, GetLastError());
1824 SelectObject(hdc, hfont_old);
1825 DeleteObject(hfont);
1827 ReleaseDC(0, hdc);
1829 return TRUE;
1832 static void test_font_charset(void)
1834 static struct charset_data
1836 INT charset;
1837 UINT code_page;
1838 WORD font_idxA[128], font_idxW[128];
1839 } cd[] =
1841 { ANSI_CHARSET, 1252 },
1842 { RUSSIAN_CHARSET, 1251 },
1843 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1845 int i;
1847 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1849 win_skip("Skipping the font charset test on a Win9x platform\n");
1850 return;
1853 if (!is_font_installed("Arial"))
1855 skip("Arial is not installed\n");
1856 return;
1859 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1861 if (cd[i].charset == SYMBOL_CHARSET)
1863 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1865 skip("Symbol or Wingdings is not installed\n");
1866 break;
1869 if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1870 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1871 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1874 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1875 if (i > 2)
1877 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1878 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1880 else
1881 skip("Symbol or Wingdings is not installed\n");
1884 static void test_GetFontUnicodeRanges(void)
1886 LOGFONTA lf;
1887 HDC hdc;
1888 HFONT hfont, hfont_old;
1889 DWORD size;
1890 GLYPHSET *gs;
1891 DWORD i;
1893 if (!pGetFontUnicodeRanges)
1895 win_skip("GetFontUnicodeRanges not available before W2K\n");
1896 return;
1899 memset(&lf, 0, sizeof(lf));
1900 lstrcpyA(lf.lfFaceName, "Arial");
1901 hfont = create_font("Arial", &lf);
1903 hdc = GetDC(0);
1904 hfont_old = SelectObject(hdc, hfont);
1906 size = pGetFontUnicodeRanges(NULL, NULL);
1907 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1909 size = pGetFontUnicodeRanges(hdc, NULL);
1910 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1912 gs = HeapAlloc(GetProcessHeap(), 0, size);
1914 size = pGetFontUnicodeRanges(hdc, gs);
1915 ok(size, "GetFontUnicodeRanges failed\n");
1917 if (0) /* Disabled to limit console spam */
1918 for (i = 0; i < gs->cRanges; i++)
1919 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1920 trace("found %u ranges\n", gs->cRanges);
1922 HeapFree(GetProcessHeap(), 0, gs);
1924 SelectObject(hdc, hfont_old);
1925 DeleteObject(hfont);
1926 ReleaseDC(NULL, hdc);
1929 #define MAX_ENUM_FONTS 4096
1931 struct enum_font_data
1933 int total;
1934 LOGFONT lf[MAX_ENUM_FONTS];
1937 struct enum_font_dataW
1939 int total;
1940 LOGFONTW lf[MAX_ENUM_FONTS];
1943 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1945 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1947 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1949 if (type != TRUETYPE_FONTTYPE) return 1;
1950 if (0) /* Disabled to limit console spam */
1951 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1952 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1953 if (efd->total < MAX_ENUM_FONTS)
1954 efd->lf[efd->total++] = *lf;
1955 else
1956 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1958 return 1;
1961 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1963 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1965 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1967 if (type != TRUETYPE_FONTTYPE) return 1;
1968 if (0) /* Disabled to limit console spam */
1969 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1970 wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1971 if (efd->total < MAX_ENUM_FONTS)
1972 efd->lf[efd->total++] = *lf;
1973 else
1974 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1976 return 1;
1979 static void get_charset_stats(struct enum_font_data *efd,
1980 int *ansi_charset, int *symbol_charset,
1981 int *russian_charset)
1983 int i;
1985 *ansi_charset = 0;
1986 *symbol_charset = 0;
1987 *russian_charset = 0;
1989 for (i = 0; i < efd->total; i++)
1991 switch (efd->lf[i].lfCharSet)
1993 case ANSI_CHARSET:
1994 (*ansi_charset)++;
1995 break;
1996 case SYMBOL_CHARSET:
1997 (*symbol_charset)++;
1998 break;
1999 case RUSSIAN_CHARSET:
2000 (*russian_charset)++;
2001 break;
2006 static void get_charset_statsW(struct enum_font_dataW *efd,
2007 int *ansi_charset, int *symbol_charset,
2008 int *russian_charset)
2010 int i;
2012 *ansi_charset = 0;
2013 *symbol_charset = 0;
2014 *russian_charset = 0;
2016 for (i = 0; i < efd->total; i++)
2018 switch (efd->lf[i].lfCharSet)
2020 case ANSI_CHARSET:
2021 (*ansi_charset)++;
2022 break;
2023 case SYMBOL_CHARSET:
2024 (*symbol_charset)++;
2025 break;
2026 case RUSSIAN_CHARSET:
2027 (*russian_charset)++;
2028 break;
2033 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2035 struct enum_font_data efd;
2036 struct enum_font_dataW efdw;
2037 LOGFONT lf;
2038 HDC hdc;
2039 int i, ret, ansi_charset, symbol_charset, russian_charset;
2041 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2043 if (*font_name && !is_truetype_font_installed(font_name))
2045 skip("%s is not installed\n", font_name);
2046 return;
2049 hdc = GetDC(0);
2051 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2052 * while EnumFontFamiliesEx doesn't.
2054 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2057 * Use EnumFontFamiliesW since win98 crashes when the
2058 * second parameter is NULL using EnumFontFamilies
2060 efdw.total = 0;
2061 SetLastError(0xdeadbeef);
2062 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2063 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2064 if(ret)
2066 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2067 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2068 ansi_charset, symbol_charset, russian_charset);
2069 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2070 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2071 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2072 ok(russian_charset > 0 ||
2073 broken(russian_charset == 0), /* NT4 */
2074 "NULL family should enumerate RUSSIAN_CHARSET\n");
2077 efdw.total = 0;
2078 SetLastError(0xdeadbeef);
2079 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2080 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2081 if(ret)
2083 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2084 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2085 ansi_charset, symbol_charset, russian_charset);
2086 ok(efdw.total > 0, "fonts enumerated: NULL\n");
2087 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2088 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2089 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2093 efd.total = 0;
2094 SetLastError(0xdeadbeef);
2095 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2096 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2097 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2098 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2099 ansi_charset, symbol_charset, russian_charset,
2100 *font_name ? font_name : "<empty>");
2101 if (*font_name)
2102 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2103 else
2104 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2105 for (i = 0; i < efd.total; i++)
2107 /* FIXME: remove completely once Wine is fixed */
2108 if (efd.lf[i].lfCharSet != font_charset)
2110 todo_wine
2111 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2113 else
2114 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2115 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2116 font_name, efd.lf[i].lfFaceName);
2119 memset(&lf, 0, sizeof(lf));
2120 lf.lfCharSet = ANSI_CHARSET;
2121 lstrcpy(lf.lfFaceName, font_name);
2122 efd.total = 0;
2123 SetLastError(0xdeadbeef);
2124 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2125 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2126 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2127 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2128 ansi_charset, symbol_charset, russian_charset,
2129 *font_name ? font_name : "<empty>");
2130 if (font_charset == SYMBOL_CHARSET)
2132 if (*font_name)
2133 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2134 else
2135 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2137 else
2139 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2140 for (i = 0; i < efd.total; i++)
2142 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2143 if (*font_name)
2144 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2145 font_name, efd.lf[i].lfFaceName);
2149 /* DEFAULT_CHARSET should enumerate all available charsets */
2150 memset(&lf, 0, sizeof(lf));
2151 lf.lfCharSet = DEFAULT_CHARSET;
2152 lstrcpy(lf.lfFaceName, font_name);
2153 efd.total = 0;
2154 SetLastError(0xdeadbeef);
2155 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2156 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2157 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2158 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2159 ansi_charset, symbol_charset, russian_charset,
2160 *font_name ? font_name : "<empty>");
2161 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2162 for (i = 0; i < efd.total; i++)
2164 if (*font_name)
2165 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2166 font_name, efd.lf[i].lfFaceName);
2168 if (*font_name)
2170 switch (font_charset)
2172 case ANSI_CHARSET:
2173 ok(ansi_charset > 0,
2174 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2175 ok(!symbol_charset,
2176 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2177 ok(russian_charset > 0,
2178 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2179 break;
2180 case SYMBOL_CHARSET:
2181 ok(!ansi_charset,
2182 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2183 ok(symbol_charset,
2184 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2185 ok(!russian_charset,
2186 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2187 break;
2188 case DEFAULT_CHARSET:
2189 ok(ansi_charset > 0,
2190 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2191 ok(symbol_charset > 0,
2192 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2193 ok(russian_charset > 0,
2194 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2195 break;
2198 else
2200 ok(ansi_charset > 0,
2201 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2202 ok(symbol_charset > 0,
2203 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2204 ok(russian_charset > 0,
2205 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2208 memset(&lf, 0, sizeof(lf));
2209 lf.lfCharSet = SYMBOL_CHARSET;
2210 lstrcpy(lf.lfFaceName, font_name);
2211 efd.total = 0;
2212 SetLastError(0xdeadbeef);
2213 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2214 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2215 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2216 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2217 ansi_charset, symbol_charset, russian_charset,
2218 *font_name ? font_name : "<empty>");
2219 if (*font_name && font_charset == ANSI_CHARSET)
2220 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2221 else
2223 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2224 for (i = 0; i < efd.total; i++)
2226 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2227 if (*font_name)
2228 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2229 font_name, efd.lf[i].lfFaceName);
2232 ok(!ansi_charset,
2233 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2234 ok(symbol_charset > 0,
2235 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2236 ok(!russian_charset,
2237 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2240 ReleaseDC(0, hdc);
2243 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2245 struct enum_font_data *efd = (struct enum_font_data *)lParam;
2247 if (type != TRUETYPE_FONTTYPE) return 1;
2249 if (efd->total < MAX_ENUM_FONTS)
2250 efd->lf[efd->total++] = *lf;
2251 else
2252 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2254 return 1;
2257 static void test_EnumFontFamiliesEx_default_charset(void)
2259 struct enum_font_data efd;
2260 LOGFONT gui_font, enum_font;
2261 DWORD ret;
2262 HDC hdc;
2264 ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2265 ok(ret, "GetObject failed.\n");
2266 if (!ret)
2267 return;
2269 efd.total = 0;
2271 hdc = GetDC(0);
2272 memset(&enum_font, 0, sizeof(enum_font));
2273 lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2274 enum_font.lfCharSet = DEFAULT_CHARSET;
2275 EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2276 ReleaseDC(0, hdc);
2278 if (efd.total == 0) {
2279 skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2280 return;
2282 trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2284 ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2285 "(%s) got charset %d expected %d\n",
2286 efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2288 return;
2291 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2293 HFONT hfont, hfont_prev;
2294 DWORD ret;
2295 GLYPHMETRICS gm1, gm2;
2296 LOGFONTA lf2 = *lf;
2297 WORD idx;
2299 if(!pGetGlyphIndicesA)
2300 return;
2302 /* negative widths are handled just as positive ones */
2303 lf2.lfWidth = -lf->lfWidth;
2305 SetLastError(0xdeadbeef);
2306 hfont = CreateFontIndirectA(lf);
2307 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2308 check_font("original", lf, hfont);
2310 hfont_prev = SelectObject(hdc, hfont);
2312 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2313 if (ret == GDI_ERROR || idx == 0xffff)
2315 SelectObject(hdc, hfont_prev);
2316 DeleteObject(hfont);
2317 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2318 return;
2321 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2322 memset(&gm1, 0xab, sizeof(gm1));
2323 SetLastError(0xdeadbeef);
2324 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2325 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2327 SelectObject(hdc, hfont_prev);
2328 DeleteObject(hfont);
2330 SetLastError(0xdeadbeef);
2331 hfont = CreateFontIndirectA(&lf2);
2332 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2333 check_font("negative width", &lf2, hfont);
2335 hfont_prev = SelectObject(hdc, hfont);
2337 memset(&gm2, 0xbb, sizeof(gm2));
2338 SetLastError(0xdeadbeef);
2339 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2340 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2342 SelectObject(hdc, hfont_prev);
2343 DeleteObject(hfont);
2345 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2346 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2347 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2348 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2349 gm1.gmCellIncX == gm2.gmCellIncX &&
2350 gm1.gmCellIncY == gm2.gmCellIncY,
2351 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2352 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2353 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2354 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2355 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2358 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2359 #include "pshpack2.h"
2360 typedef struct
2362 USHORT version;
2363 SHORT xAvgCharWidth;
2364 USHORT usWeightClass;
2365 USHORT usWidthClass;
2366 SHORT fsType;
2367 SHORT ySubscriptXSize;
2368 SHORT ySubscriptYSize;
2369 SHORT ySubscriptXOffset;
2370 SHORT ySubscriptYOffset;
2371 SHORT ySuperscriptXSize;
2372 SHORT ySuperscriptYSize;
2373 SHORT ySuperscriptXOffset;
2374 SHORT ySuperscriptYOffset;
2375 SHORT yStrikeoutSize;
2376 SHORT yStrikeoutPosition;
2377 SHORT sFamilyClass;
2378 PANOSE panose;
2379 ULONG ulUnicodeRange1;
2380 ULONG ulUnicodeRange2;
2381 ULONG ulUnicodeRange3;
2382 ULONG ulUnicodeRange4;
2383 CHAR achVendID[4];
2384 USHORT fsSelection;
2385 USHORT usFirstCharIndex;
2386 USHORT usLastCharIndex;
2387 /* According to the Apple spec, original version didn't have the below fields,
2388 * version numbers were taken from the OpenType spec.
2390 /* version 0 (TrueType 1.5) */
2391 USHORT sTypoAscender;
2392 USHORT sTypoDescender;
2393 USHORT sTypoLineGap;
2394 USHORT usWinAscent;
2395 USHORT usWinDescent;
2396 /* version 1 (TrueType 1.66) */
2397 ULONG ulCodePageRange1;
2398 ULONG ulCodePageRange2;
2399 /* version 2 (OpenType 1.2) */
2400 SHORT sxHeight;
2401 SHORT sCapHeight;
2402 USHORT usDefaultChar;
2403 USHORT usBreakChar;
2404 USHORT usMaxContext;
2405 } TT_OS2_V2;
2406 #include "poppack.h"
2408 #ifdef WORDS_BIGENDIAN
2409 #define GET_BE_WORD(x) (x)
2410 #define GET_BE_DWORD(x) (x)
2411 #else
2412 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2413 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2414 #endif
2416 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2417 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2418 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2419 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2420 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2421 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2423 typedef struct
2425 USHORT version;
2426 USHORT num_tables;
2427 } cmap_header;
2429 typedef struct
2431 USHORT plat_id;
2432 USHORT enc_id;
2433 ULONG offset;
2434 } cmap_encoding_record;
2436 typedef struct
2438 USHORT format;
2439 USHORT length;
2440 USHORT language;
2442 BYTE glyph_ids[256];
2443 } cmap_format_0;
2445 typedef struct
2447 USHORT format;
2448 USHORT length;
2449 USHORT language;
2451 USHORT seg_countx2;
2452 USHORT search_range;
2453 USHORT entry_selector;
2454 USHORT range_shift;
2456 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2457 /* Then follows:
2458 USHORT pad;
2459 USHORT start_count[seg_countx2 / 2];
2460 USHORT id_delta[seg_countx2 / 2];
2461 USHORT id_range_offset[seg_countx2 / 2];
2462 USHORT glyph_ids[];
2464 } cmap_format_4;
2466 typedef struct
2468 USHORT end_count;
2469 USHORT start_count;
2470 USHORT id_delta;
2471 USHORT id_range_offset;
2472 } cmap_format_4_seg;
2474 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2476 ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2477 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2478 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2479 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2480 os2->panose.bWeight, os2->panose.bProportion);
2483 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2485 int i;
2486 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2488 *first = 256;
2490 for(i = 0; i < 256; i++)
2492 if(cmap->glyph_ids[i] == 0) continue;
2493 *last = i;
2494 if(*first == 256) *first = i;
2496 if(*first == 256) return FALSE;
2497 return TRUE;
2500 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2502 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2503 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2504 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2505 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2506 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2509 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2511 int i;
2512 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2513 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2514 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2516 *first = 0x10000;
2518 for(i = 0; i < seg_count; i++)
2520 DWORD code, index;
2521 cmap_format_4_seg seg;
2523 get_seg4(cmap, i, &seg);
2524 for(code = seg.start_count; code <= seg.end_count; code++)
2526 if(seg.id_range_offset == 0)
2527 index = (seg.id_delta + code) & 0xffff;
2528 else
2530 index = seg.id_range_offset / 2
2531 + code - seg.start_count
2532 + i - seg_count;
2534 /* some fonts have broken last segment */
2535 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2536 index = GET_BE_WORD(glyph_ids[index]);
2537 else
2539 trace("segment %04x/%04x index %04x points to nowhere\n",
2540 seg.start_count, seg.end_count, index);
2541 index = 0;
2543 if(index) index += seg.id_delta;
2545 if(*first == 0x10000)
2546 *last = *first = code;
2547 else if(index)
2548 *last = code;
2552 if(*first == 0x10000) return FALSE;
2553 return TRUE;
2556 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2558 USHORT i;
2559 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2561 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2563 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2564 return (BYTE *)header + GET_BE_DWORD(record->offset);
2565 record++;
2567 return NULL;
2570 typedef enum
2572 cmap_none,
2573 cmap_ms_unicode,
2574 cmap_ms_symbol
2575 } cmap_type;
2577 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2579 LONG size, ret;
2580 cmap_header *header;
2581 void *cmap;
2582 BOOL r = FALSE;
2583 WORD format;
2585 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2586 ok(size != GDI_ERROR, "no cmap table found\n");
2587 if(size == GDI_ERROR) return FALSE;
2589 header = HeapAlloc(GetProcessHeap(), 0, size);
2590 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2591 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2592 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2594 cmap = get_cmap(header, 3, 1);
2595 if(cmap)
2596 *cmap_type = cmap_ms_unicode;
2597 else
2599 cmap = get_cmap(header, 3, 0);
2600 if(cmap) *cmap_type = cmap_ms_symbol;
2602 if(!cmap)
2604 *cmap_type = cmap_none;
2605 goto end;
2608 format = GET_BE_WORD(*(WORD *)cmap);
2609 switch(format)
2611 case 0:
2612 r = get_first_last_from_cmap0(cmap, first, last);
2613 break;
2614 case 4:
2615 r = get_first_last_from_cmap4(cmap, first, last, size);
2616 break;
2617 default:
2618 trace("unhandled cmap format %d\n", format);
2619 break;
2622 end:
2623 HeapFree(GetProcessHeap(), 0, header);
2624 return r;
2627 #define TT_PLATFORM_MICROSOFT 3
2628 #define TT_MS_ID_UNICODE_CS 1
2629 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2630 #define TT_NAME_ID_FULL_NAME 4
2632 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2634 struct sfnt_name_header
2636 USHORT format;
2637 USHORT number_of_record;
2638 USHORT storage_offset;
2639 } *header;
2640 struct sfnt_name
2642 USHORT platform_id;
2643 USHORT encoding_id;
2644 USHORT language_id;
2645 USHORT name_id;
2646 USHORT length;
2647 USHORT offset;
2648 } *entry;
2649 BOOL r = FALSE;
2650 LONG size, offset, length;
2651 LONG c, ret;
2652 WCHAR *name;
2653 BYTE *data;
2654 USHORT i;
2656 size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2657 ok(size != GDI_ERROR, "no name table found\n");
2658 if(size == GDI_ERROR) return FALSE;
2660 data = HeapAlloc(GetProcessHeap(), 0, size);
2661 ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2662 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2664 header = (void *)data;
2665 header->format = GET_BE_WORD(header->format);
2666 header->number_of_record = GET_BE_WORD(header->number_of_record);
2667 header->storage_offset = GET_BE_WORD(header->storage_offset);
2668 if (header->format != 0)
2670 trace("got format %u\n", header->format);
2671 goto out;
2673 if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2675 trace("number records out of range: %d\n", header->number_of_record);
2676 goto out;
2678 if (header->storage_offset >= size)
2680 trace("storage_offset %u > size %u\n", header->storage_offset, size);
2681 goto out;
2684 entry = (void *)&header[1];
2685 for (i = 0; i < header->number_of_record; i++)
2687 if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2688 GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2689 GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2690 GET_BE_WORD(entry[i].name_id) != name_id)
2692 continue;
2695 offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2696 length = GET_BE_WORD(entry[i].length);
2697 if (offset + length > size)
2699 trace("entry %d is out of range\n", i);
2700 break;
2702 if (length >= out_size)
2704 trace("buffer too small for entry %d\n", i);
2705 break;
2708 name = (WCHAR *)(data + offset);
2709 for (c = 0; c < length / 2; c++)
2710 out_buf[c] = GET_BE_WORD(name[c]);
2711 out_buf[c] = 0;
2713 r = TRUE;
2714 break;
2717 out:
2718 HeapFree(GetProcessHeap(), 0, data);
2719 return r;
2722 static void test_text_metrics(const LOGFONTA *lf)
2724 HDC hdc;
2725 HFONT hfont, hfont_old;
2726 TEXTMETRICA tmA;
2727 TT_OS2_V2 tt_os2;
2728 LONG size, ret;
2729 const char *font_name = lf->lfFaceName;
2730 DWORD cmap_first = 0, cmap_last = 0;
2731 cmap_type cmap_type;
2732 BOOL sys_lang_non_english;
2734 sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2735 hdc = GetDC(0);
2737 SetLastError(0xdeadbeef);
2738 hfont = CreateFontIndirectA(lf);
2739 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2741 hfont_old = SelectObject(hdc, hfont);
2743 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2744 if (size == GDI_ERROR)
2746 trace("OS/2 chunk was not found\n");
2747 goto end_of_test;
2749 if (size > sizeof(tt_os2))
2751 trace("got too large OS/2 chunk of size %u\n", size);
2752 size = sizeof(tt_os2);
2755 memset(&tt_os2, 0, sizeof(tt_os2));
2756 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2757 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2759 SetLastError(0xdeadbeef);
2760 ret = GetTextMetricsA(hdc, &tmA);
2761 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2763 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2765 skip("Unable to retrieve first and last glyphs from cmap\n");
2767 else
2769 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2770 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2771 UINT os2_first_char, os2_last_char, default_char, break_char;
2772 USHORT version;
2773 TEXTMETRICW tmW;
2775 version = GET_BE_WORD(tt_os2.version);
2777 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2778 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2779 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2780 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2782 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2783 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2784 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2786 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2788 expect_first_W = 0;
2789 switch(GetACP())
2791 case 1257: /* Baltic */
2792 expect_last_W = 0xf8fd;
2793 break;
2794 default:
2795 expect_last_W = 0xf0ff;
2797 expect_break_W = 0x20;
2798 expect_default_W = expect_break_W - 1;
2799 expect_first_A = 0x1e;
2800 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2802 else
2804 expect_first_W = cmap_first;
2805 expect_last_W = min(cmap_last, os2_last_char);
2806 if(os2_first_char <= 1)
2807 expect_break_W = os2_first_char + 2;
2808 else if(os2_first_char > 0xff)
2809 expect_break_W = 0x20;
2810 else
2811 expect_break_W = os2_first_char;
2812 expect_default_W = expect_break_W - 1;
2813 expect_first_A = expect_default_W - 1;
2814 expect_last_A = min(expect_last_W, 0xff);
2816 expect_break_A = expect_break_W;
2817 expect_default_A = expect_default_W;
2819 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2820 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2821 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2822 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2823 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2824 else
2825 ok(tmA.tmFirstChar == expect_first_A ||
2826 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2827 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2828 if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2829 ok(tmA.tmLastChar == expect_last_A ||
2830 tmA.tmLastChar == 0xff /* win9x */,
2831 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2832 else
2833 skip("tmLastChar is DBCS lead byte\n");
2834 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2835 font_name, tmA.tmBreakChar, expect_break_A);
2836 ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2837 "A: tmDefaultChar for %s got %02x expected %02x\n",
2838 font_name, tmA.tmDefaultChar, expect_default_A);
2841 SetLastError(0xdeadbeef);
2842 ret = GetTextMetricsW(hdc, &tmW);
2843 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2844 "GetTextMetricsW error %u\n", GetLastError());
2845 if (ret)
2847 /* Wine uses the os2 first char */
2848 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2849 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2850 font_name, tmW.tmFirstChar, expect_first_W);
2851 else
2852 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2853 font_name, tmW.tmFirstChar, expect_first_W);
2855 /* Wine uses the os2 last char */
2856 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2857 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2858 font_name, tmW.tmLastChar, expect_last_W);
2859 else
2860 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2861 font_name, tmW.tmLastChar, expect_last_W);
2862 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2863 font_name, tmW.tmBreakChar, expect_break_W);
2864 ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2865 "W: tmDefaultChar for %s got %02x expected %02x\n",
2866 font_name, tmW.tmDefaultChar, expect_default_W);
2868 /* Test the aspect ratio while we have tmW */
2869 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2870 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2871 tmW.tmDigitizedAspectX, ret);
2872 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2873 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2874 tmW.tmDigitizedAspectX, ret);
2878 /* test FF_ values */
2879 switch(tt_os2.panose.bFamilyType)
2881 case PAN_ANY:
2882 case PAN_NO_FIT:
2883 case PAN_FAMILY_TEXT_DISPLAY:
2884 case PAN_FAMILY_PICTORIAL:
2885 default:
2886 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2887 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2889 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2890 break;
2892 switch(tt_os2.panose.bSerifStyle)
2894 case PAN_ANY:
2895 case PAN_NO_FIT:
2896 default:
2897 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2898 break;
2900 case PAN_SERIF_COVE:
2901 case PAN_SERIF_OBTUSE_COVE:
2902 case PAN_SERIF_SQUARE_COVE:
2903 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2904 case PAN_SERIF_SQUARE:
2905 case PAN_SERIF_THIN:
2906 case PAN_SERIF_BONE:
2907 case PAN_SERIF_EXAGGERATED:
2908 case PAN_SERIF_TRIANGLE:
2909 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2910 break;
2912 case PAN_SERIF_NORMAL_SANS:
2913 case PAN_SERIF_OBTUSE_SANS:
2914 case PAN_SERIF_PERP_SANS:
2915 case PAN_SERIF_FLARED:
2916 case PAN_SERIF_ROUNDED:
2917 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2918 break;
2920 break;
2922 case PAN_FAMILY_SCRIPT:
2923 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2924 break;
2926 case PAN_FAMILY_DECORATIVE:
2927 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2928 break;
2931 test_negative_width(hdc, lf);
2933 end_of_test:
2934 SelectObject(hdc, hfont_old);
2935 DeleteObject(hfont);
2937 ReleaseDC(0, hdc);
2940 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2942 INT *enumed = (INT *)lParam;
2944 if (type == TRUETYPE_FONTTYPE)
2946 (*enumed)++;
2947 test_text_metrics(lf);
2949 return 1;
2952 static void test_GetTextMetrics(void)
2954 LOGFONTA lf;
2955 HDC hdc;
2956 INT enumed;
2958 /* Report only once */
2959 if(!pGetGlyphIndicesA)
2960 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2962 hdc = GetDC(0);
2964 memset(&lf, 0, sizeof(lf));
2965 lf.lfCharSet = DEFAULT_CHARSET;
2966 enumed = 0;
2967 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2968 trace("Tested metrics of %d truetype fonts\n", enumed);
2970 ReleaseDC(0, hdc);
2973 static void test_nonexistent_font(void)
2975 static const struct
2977 const char *name;
2978 int charset;
2979 } font_subst[] =
2981 { "Times New Roman Baltic", 186 },
2982 { "Times New Roman CE", 238 },
2983 { "Times New Roman CYR", 204 },
2984 { "Times New Roman Greek", 161 },
2985 { "Times New Roman TUR", 162 }
2987 LOGFONTA lf;
2988 HDC hdc;
2989 HFONT hfont;
2990 CHARSETINFO csi;
2991 INT cs, expected_cs, i;
2992 char buf[LF_FACESIZE];
2994 if (!is_truetype_font_installed("Arial") ||
2995 !is_truetype_font_installed("Times New Roman"))
2997 skip("Arial or Times New Roman not installed\n");
2998 return;
3001 expected_cs = GetACP();
3002 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3004 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3005 return;
3007 expected_cs = csi.ciCharset;
3008 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3010 hdc = GetDC(0);
3012 memset(&lf, 0, sizeof(lf));
3013 lf.lfHeight = 100;
3014 lf.lfWeight = FW_REGULAR;
3015 lf.lfCharSet = ANSI_CHARSET;
3016 lf.lfPitchAndFamily = FF_SWISS;
3017 strcpy(lf.lfFaceName, "Nonexistent font");
3018 hfont = CreateFontIndirectA(&lf);
3019 hfont = SelectObject(hdc, hfont);
3020 GetTextFaceA(hdc, sizeof(buf), buf);
3021 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3022 cs = GetTextCharset(hdc);
3023 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3024 DeleteObject(SelectObject(hdc, hfont));
3026 memset(&lf, 0, sizeof(lf));
3027 lf.lfHeight = -13;
3028 lf.lfWeight = FW_DONTCARE;
3029 strcpy(lf.lfFaceName, "Nonexistent font");
3030 hfont = CreateFontIndirectA(&lf);
3031 hfont = SelectObject(hdc, hfont);
3032 GetTextFaceA(hdc, sizeof(buf), buf);
3033 todo_wine /* Wine uses Arial for all substitutions */
3034 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3035 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3036 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3037 "Got %s\n", buf);
3038 cs = GetTextCharset(hdc);
3039 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3040 DeleteObject(SelectObject(hdc, hfont));
3042 memset(&lf, 0, sizeof(lf));
3043 lf.lfHeight = -13;
3044 lf.lfWeight = FW_REGULAR;
3045 strcpy(lf.lfFaceName, "Nonexistent font");
3046 hfont = CreateFontIndirectA(&lf);
3047 hfont = SelectObject(hdc, hfont);
3048 GetTextFaceA(hdc, sizeof(buf), buf);
3049 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3050 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3051 cs = GetTextCharset(hdc);
3052 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3053 DeleteObject(SelectObject(hdc, hfont));
3055 memset(&lf, 0, sizeof(lf));
3056 lf.lfHeight = -13;
3057 lf.lfWeight = FW_DONTCARE;
3058 strcpy(lf.lfFaceName, "Times New Roman");
3059 hfont = CreateFontIndirectA(&lf);
3060 hfont = SelectObject(hdc, hfont);
3061 GetTextFaceA(hdc, sizeof(buf), buf);
3062 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3063 cs = GetTextCharset(hdc);
3064 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3065 DeleteObject(SelectObject(hdc, hfont));
3067 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3069 memset(&lf, 0, sizeof(lf));
3070 lf.lfHeight = -13;
3071 lf.lfWeight = FW_REGULAR;
3072 strcpy(lf.lfFaceName, font_subst[i].name);
3073 hfont = CreateFontIndirectA(&lf);
3074 hfont = SelectObject(hdc, hfont);
3075 cs = GetTextCharset(hdc);
3076 if (font_subst[i].charset == expected_cs)
3078 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3079 GetTextFaceA(hdc, sizeof(buf), buf);
3080 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3082 else
3084 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3085 GetTextFaceA(hdc, sizeof(buf), buf);
3086 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3087 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3089 DeleteObject(SelectObject(hdc, hfont));
3091 memset(&lf, 0, sizeof(lf));
3092 lf.lfHeight = -13;
3093 lf.lfWeight = FW_DONTCARE;
3094 strcpy(lf.lfFaceName, font_subst[i].name);
3095 hfont = CreateFontIndirectA(&lf);
3096 hfont = SelectObject(hdc, hfont);
3097 GetTextFaceA(hdc, sizeof(buf), buf);
3098 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3099 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3100 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3101 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3102 "got %s for font %s\n", buf, font_subst[i].name);
3103 cs = GetTextCharset(hdc);
3104 ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3105 DeleteObject(SelectObject(hdc, hfont));
3108 ReleaseDC(0, hdc);
3111 static void test_GdiRealizationInfo(void)
3113 HDC hdc;
3114 DWORD info[4];
3115 BOOL r;
3116 HFONT hfont, hfont_old;
3117 LOGFONTA lf;
3119 if(!pGdiRealizationInfo)
3121 win_skip("GdiRealizationInfo not available\n");
3122 return;
3125 hdc = GetDC(0);
3127 memset(info, 0xcc, sizeof(info));
3128 r = pGdiRealizationInfo(hdc, info);
3129 ok(r != 0, "ret 0\n");
3130 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3131 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3133 if (!is_truetype_font_installed("Arial"))
3135 skip("skipping GdiRealizationInfo with truetype font\n");
3136 goto end;
3139 memset(&lf, 0, sizeof(lf));
3140 strcpy(lf.lfFaceName, "Arial");
3141 lf.lfHeight = 20;
3142 lf.lfWeight = FW_NORMAL;
3143 hfont = CreateFontIndirectA(&lf);
3144 hfont_old = SelectObject(hdc, hfont);
3146 memset(info, 0xcc, sizeof(info));
3147 r = pGdiRealizationInfo(hdc, info);
3148 ok(r != 0, "ret 0\n");
3149 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3150 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3152 DeleteObject(SelectObject(hdc, hfont_old));
3154 end:
3155 ReleaseDC(0, hdc);
3158 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3159 the nul in the count of characters copied when the face name buffer is not
3160 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3161 always includes it. */
3162 static void test_GetTextFace(void)
3164 static const char faceA[] = "Tahoma";
3165 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3166 LOGFONTA fA = {0};
3167 LOGFONTW fW = {0};
3168 char bufA[LF_FACESIZE];
3169 WCHAR bufW[LF_FACESIZE];
3170 HFONT f, g;
3171 HDC dc;
3172 int n;
3174 if(!is_font_installed("Tahoma"))
3176 skip("Tahoma is not installed so skipping this test\n");
3177 return;
3180 /* 'A' case. */
3181 memcpy(fA.lfFaceName, faceA, sizeof faceA);
3182 f = CreateFontIndirectA(&fA);
3183 ok(f != NULL, "CreateFontIndirectA failed\n");
3185 dc = GetDC(NULL);
3186 g = SelectObject(dc, f);
3187 n = GetTextFaceA(dc, sizeof bufA, bufA);
3188 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3189 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3191 /* Play with the count arg. */
3192 bufA[0] = 'x';
3193 n = GetTextFaceA(dc, 0, bufA);
3194 ok(n == 0, "GetTextFaceA returned %d\n", n);
3195 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3197 bufA[0] = 'x';
3198 n = GetTextFaceA(dc, 1, bufA);
3199 ok(n == 0, "GetTextFaceA returned %d\n", n);
3200 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3202 bufA[0] = 'x'; bufA[1] = 'y';
3203 n = GetTextFaceA(dc, 2, bufA);
3204 ok(n == 1, "GetTextFaceA returned %d\n", n);
3205 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3207 n = GetTextFaceA(dc, 0, NULL);
3208 ok(n == sizeof faceA ||
3209 broken(n == 0), /* win98, winMe */
3210 "GetTextFaceA returned %d\n", n);
3212 DeleteObject(SelectObject(dc, g));
3213 ReleaseDC(NULL, dc);
3215 /* 'W' case. */
3216 memcpy(fW.lfFaceName, faceW, sizeof faceW);
3217 SetLastError(0xdeadbeef);
3218 f = CreateFontIndirectW(&fW);
3219 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3221 win_skip("CreateFontIndirectW is not implemented\n");
3222 return;
3224 ok(f != NULL, "CreateFontIndirectW failed\n");
3226 dc = GetDC(NULL);
3227 g = SelectObject(dc, f);
3228 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3229 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3230 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3232 /* Play with the count arg. */
3233 bufW[0] = 'x';
3234 n = GetTextFaceW(dc, 0, bufW);
3235 ok(n == 0, "GetTextFaceW returned %d\n", n);
3236 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3238 bufW[0] = 'x';
3239 n = GetTextFaceW(dc, 1, bufW);
3240 ok(n == 1, "GetTextFaceW returned %d\n", n);
3241 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3243 bufW[0] = 'x'; bufW[1] = 'y';
3244 n = GetTextFaceW(dc, 2, bufW);
3245 ok(n == 2, "GetTextFaceW returned %d\n", n);
3246 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3248 n = GetTextFaceW(dc, 0, NULL);
3249 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3251 DeleteObject(SelectObject(dc, g));
3252 ReleaseDC(NULL, dc);
3255 static void test_orientation(void)
3257 static const char test_str[11] = "Test String";
3258 HDC hdc;
3259 LOGFONTA lf;
3260 HFONT hfont, old_hfont;
3261 SIZE size;
3263 if (!is_truetype_font_installed("Arial"))
3265 skip("Arial is not installed\n");
3266 return;
3269 hdc = CreateCompatibleDC(0);
3270 memset(&lf, 0, sizeof(lf));
3271 lstrcpyA(lf.lfFaceName, "Arial");
3272 lf.lfHeight = 72;
3273 lf.lfOrientation = lf.lfEscapement = 900;
3274 hfont = create_font("orientation", &lf);
3275 old_hfont = SelectObject(hdc, hfont);
3276 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3277 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3278 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3279 SelectObject(hdc, old_hfont);
3280 DeleteObject(hfont);
3281 DeleteDC(hdc);
3284 static void test_oemcharset(void)
3286 HDC hdc;
3287 LOGFONTA lf, clf;
3288 HFONT hfont, old_hfont;
3289 int charset;
3291 hdc = CreateCompatibleDC(0);
3292 ZeroMemory(&lf, sizeof(lf));
3293 lf.lfHeight = 12;
3294 lf.lfCharSet = OEM_CHARSET;
3295 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3296 lstrcpyA(lf.lfFaceName, "Terminal");
3297 hfont = CreateFontIndirectA(&lf);
3298 old_hfont = SelectObject(hdc, hfont);
3299 charset = GetTextCharset(hdc);
3300 todo_wine
3301 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3302 hfont = SelectObject(hdc, old_hfont);
3303 GetObjectA(hfont, sizeof(clf), &clf);
3304 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3305 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3306 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3307 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3308 DeleteObject(hfont);
3309 DeleteDC(hdc);
3312 static void test_GetGlyphOutline(void)
3314 HDC hdc;
3315 GLYPHMETRICS gm, gm2;
3316 LOGFONTA lf;
3317 HFONT hfont, old_hfont;
3318 INT ret, ret2;
3319 static const struct
3321 UINT cs;
3322 UINT a;
3323 UINT w;
3324 } c[] =
3326 {ANSI_CHARSET, 0x30, 0x30},
3327 {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3328 {HANGEUL_CHARSET, 0x8141, 0xac02},
3329 {JOHAB_CHARSET, 0x8446, 0x3135},
3330 {GB2312_CHARSET, 0x8141, 0x4e04},
3331 {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3333 UINT i;
3335 if (!is_truetype_font_installed("Tahoma"))
3337 skip("Tahoma is not installed\n");
3338 return;
3341 hdc = CreateCompatibleDC(0);
3342 memset(&lf, 0, sizeof(lf));
3343 lf.lfHeight = 72;
3344 lstrcpyA(lf.lfFaceName, "Tahoma");
3345 SetLastError(0xdeadbeef);
3346 hfont = CreateFontIndirectA(&lf);
3347 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3348 old_hfont = SelectObject(hdc, hfont);
3350 memset(&gm, 0, sizeof(gm));
3351 SetLastError(0xdeadbeef);
3352 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3353 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3355 memset(&gm, 0, sizeof(gm));
3356 SetLastError(0xdeadbeef);
3357 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3358 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3359 ok(GetLastError() == 0xdeadbeef ||
3360 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3361 "expected 0xdeadbeef, got %u\n", GetLastError());
3363 memset(&gm, 0, sizeof(gm));
3364 SetLastError(0xdeadbeef);
3365 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3366 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3367 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3369 memset(&gm, 0, sizeof(gm));
3370 SetLastError(0xdeadbeef);
3371 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3372 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3374 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3375 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3378 /* test for needed buffer size request on space char */
3379 memset(&gm, 0, sizeof(gm));
3380 SetLastError(0xdeadbeef);
3381 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3382 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3383 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3385 /* requesting buffer size for space char + error */
3386 memset(&gm, 0, sizeof(gm));
3387 SetLastError(0xdeadbeef);
3388 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3389 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3391 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3392 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3395 SelectObject(hdc, old_hfont);
3396 DeleteObject(hfont);
3398 for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3400 lf.lfFaceName[0] = '\0';
3401 lf.lfCharSet = c[i].cs;
3402 lf.lfPitchAndFamily = 0;
3403 if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3405 skip("TrueType font for charset %u is not installed\n", c[i].cs);
3406 continue;
3409 old_hfont = SelectObject(hdc, hfont);
3411 /* expected to ignore superfluous bytes (sigle-byte character) */
3412 ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3413 ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3414 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3416 ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3417 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3418 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3420 /* expected to ignore superfluous bytes (double-byte character) */
3421 ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3422 ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3423 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3424 "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3426 /* expected to match wide-char version results */
3427 ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3428 ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3430 hfont = SelectObject(hdc, old_hfont);
3431 DeleteObject(hfont);
3434 DeleteDC(hdc);
3437 /* bug #9995: there is a limit to the character width that can be specified */
3438 static void test_GetTextMetrics2(const char *fontname, int font_height)
3440 HFONT of, hf;
3441 HDC hdc;
3442 TEXTMETRICA tm;
3443 BOOL ret;
3444 int ave_width, height, width, ratio, scale;
3446 if (!is_truetype_font_installed( fontname)) {
3447 skip("%s is not installed\n", fontname);
3448 return;
3450 hdc = CreateCompatibleDC(0);
3451 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3452 /* select width = 0 */
3453 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3454 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3455 DEFAULT_QUALITY, VARIABLE_PITCH,
3456 fontname);
3457 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3458 of = SelectObject( hdc, hf);
3459 ret = GetTextMetricsA( hdc, &tm);
3460 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3461 height = tm.tmHeight;
3462 ave_width = tm.tmAveCharWidth;
3463 SelectObject( hdc, of);
3464 DeleteObject( hf);
3466 trace("height %d, ave width %d\n", height, ave_width);
3468 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3470 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3471 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3472 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3473 ok(hf != 0, "CreateFont failed\n");
3474 of = SelectObject(hdc, hf);
3475 ret = GetTextMetrics(hdc, &tm);
3476 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3477 SelectObject(hdc, of);
3478 DeleteObject(hf);
3480 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3481 break;
3484 DeleteDC(hdc);
3486 ratio = width / height;
3487 scale = width / ave_width;
3489 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3490 width, height, ratio, width, ave_width, scale);
3492 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3495 static void test_CreateFontIndirect(void)
3497 LOGFONTA lf, getobj_lf;
3498 int ret, i;
3499 HFONT hfont;
3500 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3502 memset(&lf, 0, sizeof(lf));
3503 lf.lfCharSet = ANSI_CHARSET;
3504 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3505 lf.lfHeight = 16;
3506 lf.lfWidth = 16;
3507 lf.lfQuality = DEFAULT_QUALITY;
3508 lf.lfItalic = FALSE;
3509 lf.lfWeight = FW_DONTCARE;
3511 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3513 lstrcpyA(lf.lfFaceName, TestName[i]);
3514 hfont = CreateFontIndirectA(&lf);
3515 ok(hfont != 0, "CreateFontIndirectA failed\n");
3516 SetLastError(0xdeadbeef);
3517 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3518 ok(ret, "GetObject failed: %d\n", GetLastError());
3519 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3520 ok(lf.lfWeight == getobj_lf.lfWeight ||
3521 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3522 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3523 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3524 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3525 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3526 DeleteObject(hfont);
3530 static void test_CreateFontIndirectEx(void)
3532 ENUMLOGFONTEXDVA lfex;
3533 HFONT hfont;
3535 if (!pCreateFontIndirectExA)
3537 win_skip("CreateFontIndirectExA is not available\n");
3538 return;
3541 if (!is_truetype_font_installed("Arial"))
3543 skip("Arial is not installed\n");
3544 return;
3547 SetLastError(0xdeadbeef);
3548 hfont = pCreateFontIndirectExA(NULL);
3549 ok(hfont == NULL, "got %p\n", hfont);
3550 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3552 memset(&lfex, 0, sizeof(lfex));
3553 lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3554 hfont = pCreateFontIndirectExA(&lfex);
3555 ok(hfont != 0, "CreateFontIndirectEx failed\n");
3556 if (hfont)
3557 check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3558 DeleteObject(hfont);
3561 static void free_font(void *font)
3563 UnmapViewOfFile(font);
3566 static void *load_font(const char *font_name, DWORD *font_size)
3568 char file_name[MAX_PATH];
3569 HANDLE file, mapping;
3570 void *font;
3572 if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3573 strcat(file_name, "\\fonts\\");
3574 strcat(file_name, font_name);
3576 file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3577 if (file == INVALID_HANDLE_VALUE) return NULL;
3579 *font_size = GetFileSize(file, NULL);
3581 mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3582 if (!mapping)
3584 CloseHandle(file);
3585 return NULL;
3588 font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3590 CloseHandle(file);
3591 CloseHandle(mapping);
3592 return font;
3595 static void test_AddFontMemResource(void)
3597 void *font;
3598 DWORD font_size, num_fonts;
3599 HANDLE ret;
3600 BOOL bRet;
3602 if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3604 win_skip("AddFontMemResourceEx is not available on this platform\n");
3605 return;
3608 font = load_font("sserife.fon", &font_size);
3609 if (!font)
3611 skip("Unable to locate and load font sserife.fon\n");
3612 return;
3615 SetLastError(0xdeadbeef);
3616 ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3617 ok(!ret, "AddFontMemResourceEx should fail\n");
3618 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3619 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3620 GetLastError());
3622 SetLastError(0xdeadbeef);
3623 ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3624 ok(!ret, "AddFontMemResourceEx should fail\n");
3625 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3626 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3627 GetLastError());
3629 SetLastError(0xdeadbeef);
3630 ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3631 ok(!ret, "AddFontMemResourceEx should fail\n");
3632 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3633 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3634 GetLastError());
3636 SetLastError(0xdeadbeef);
3637 ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3638 ok(!ret, "AddFontMemResourceEx should fail\n");
3639 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3640 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3641 GetLastError());
3643 SetLastError(0xdeadbeef);
3644 ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3645 ok(!ret, "AddFontMemResourceEx should fail\n");
3646 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3647 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3648 GetLastError());
3650 SetLastError(0xdeadbeef);
3651 ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3652 ok(!ret, "AddFontMemResourceEx should fail\n");
3653 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3654 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3655 GetLastError());
3657 num_fonts = 0xdeadbeef;
3658 SetLastError(0xdeadbeef);
3659 ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3660 ok(!ret, "AddFontMemResourceEx should fail\n");
3661 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3662 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3663 GetLastError());
3664 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3666 if (0) /* hangs under windows 2000 */
3668 num_fonts = 0xdeadbeef;
3669 SetLastError(0xdeadbeef);
3670 ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3671 ok(!ret, "AddFontMemResourceEx should fail\n");
3672 ok(GetLastError() == 0xdeadbeef,
3673 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3674 GetLastError());
3675 ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3678 num_fonts = 0xdeadbeef;
3679 SetLastError(0xdeadbeef);
3680 ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3681 ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3682 ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3683 ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3685 free_font(font);
3687 SetLastError(0xdeadbeef);
3688 bRet = pRemoveFontMemResourceEx(ret);
3689 ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3691 /* test invalid pointer to number of loaded fonts */
3692 font = load_font("sserife.fon", &font_size);
3693 ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3695 SetLastError(0xdeadbeef);
3696 ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3697 ok(!ret, "AddFontMemResourceEx should fail\n");
3698 ok(GetLastError() == 0xdeadbeef,
3699 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3700 GetLastError());
3702 SetLastError(0xdeadbeef);
3703 ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3704 ok(!ret, "AddFontMemResourceEx should fail\n");
3705 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3706 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3707 GetLastError());
3709 free_font(font);
3712 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3714 LOGFONT *lf;
3716 if (type != TRUETYPE_FONTTYPE) return 1;
3718 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3720 lf = (LOGFONT *)lparam;
3721 *lf = *elf;
3722 return 0;
3725 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3727 int ret;
3728 LOGFONT *lf;
3730 if (type != TRUETYPE_FONTTYPE) return 1;
3732 lf = (LOGFONT *)lparam;
3733 ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3734 if(ret == 0)
3736 ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3737 *lf = *elf;
3738 return 0;
3740 return 1;
3743 static void test_EnumFonts(void)
3745 int ret;
3746 LOGFONT lf;
3747 HDC hdc;
3749 if (!is_truetype_font_installed("Arial"))
3751 skip("Arial is not installed\n");
3752 return;
3755 /* Windows uses localized font face names, so Arial Bold won't be found */
3756 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3758 skip("User locale is not English, skipping the test\n");
3759 return;
3762 hdc = CreateCompatibleDC(0);
3764 ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3765 ok(!ret, "font Arial is not enumerated\n");
3766 ret = strcmp(lf.lfFaceName, "Arial");
3767 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3768 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3770 lstrcpy(lf.lfFaceName, "Arial");
3771 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3772 ok(!ret, "font Arial is not enumerated\n");
3773 ret = strcmp(lf.lfFaceName, "Arial");
3774 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3775 ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3777 ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3778 ok(!ret, "font Arial Bold is not enumerated\n");
3779 ret = strcmp(lf.lfFaceName, "Arial");
3780 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3781 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3783 lstrcpy(lf.lfFaceName, "Arial Bold");
3784 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3785 ok(ret, "font Arial Bold should not be enumerated\n");
3787 ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3788 ok(!ret, "font Arial Bold Italic is not enumerated\n");
3789 ret = strcmp(lf.lfFaceName, "Arial");
3790 ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3791 ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3793 lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3794 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3795 ok(ret, "font Arial Bold Italic should not be enumerated\n");
3797 ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3798 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3800 lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3801 ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3802 ok(ret, "font Arial Italic Bold should not be enumerated\n");
3804 DeleteDC(hdc);
3807 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3809 const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3810 const char *fullname = (const char *)lParam;
3812 if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3814 return 1;
3817 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3819 HDC hdc = GetDC(0);
3820 BOOL ret = FALSE;
3822 if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3823 ret = TRUE;
3825 ReleaseDC(0, hdc);
3826 return ret;
3829 static void test_fullname(void)
3831 static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3832 char buf[LF_FULLFACESIZE];
3833 HFONT hfont, of;
3834 LOGFONTA lf;
3835 HDC hdc;
3836 int i;
3838 hdc = CreateCompatibleDC(0);
3839 ok(hdc != NULL, "CreateCompatibleDC failed\n");
3841 memset(&lf, 0, sizeof(lf));
3842 lf.lfCharSet = ANSI_CHARSET;
3843 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3844 lf.lfHeight = 16;
3845 lf.lfWidth = 16;
3846 lf.lfQuality = DEFAULT_QUALITY;
3847 lf.lfItalic = FALSE;
3848 lf.lfWeight = FW_DONTCARE;
3850 for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3852 if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3854 skip("%s is not installed\n", TestName[i]);
3855 continue;
3858 lstrcpyA(lf.lfFaceName, TestName[i]);
3859 hfont = CreateFontIndirectA(&lf);
3860 ok(hfont != 0, "CreateFontIndirectA failed\n");
3862 of = SelectObject(hdc, hfont);
3863 buf[0] = 0;
3864 ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3865 "face full name could not be read\n");
3866 ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3867 SelectObject(hdc, of);
3868 DeleteObject(hfont);
3870 DeleteDC(hdc);
3873 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
3875 char tmp_path[MAX_PATH];
3876 HRSRC rsrc;
3877 void *rsrc_data;
3878 DWORD rsrc_size;
3879 HANDLE hfile;
3880 BOOL ret;
3882 SetLastError(0xdeadbeef);
3883 rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
3884 ok(rsrc != 0, "FindResource error %d\n", GetLastError());
3885 if (!rsrc) return FALSE;
3886 SetLastError(0xdeadbeef);
3887 rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
3888 ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
3889 if (!rsrc_data) return FALSE;
3890 SetLastError(0xdeadbeef);
3891 rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
3892 ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
3893 if (!rsrc_size) return FALSE;
3895 SetLastError(0xdeadbeef);
3896 ret = GetTempPath(MAX_PATH, tmp_path);
3897 ok(ret, "GetTempPath() error %d\n", GetLastError());
3898 SetLastError(0xdeadbeef);
3899 ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
3900 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3902 SetLastError(0xdeadbeef);
3903 hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
3904 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
3905 if (hfile == INVALID_HANDLE_VALUE) return FALSE;
3907 SetLastError(0xdeadbeef);
3908 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
3909 ok(ret, "WriteFile() error %d\n", GetLastError());
3911 CloseHandle(hfile);
3912 return ret;
3915 static void test_CreateScalableFontResource(void)
3917 char ttf_name[MAX_PATH];
3918 char tmp_path[MAX_PATH];
3919 char fot_name[MAX_PATH];
3920 char *file_part;
3921 DWORD ret;
3923 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
3925 win_skip("AddFontResourceExA is not available on this platform\n");
3926 return;
3929 if (!write_ttf_file("wine_test.ttf", ttf_name))
3931 skip("Failed to create ttf file for testing\n");
3932 return;
3935 trace("created %s\n", ttf_name);
3937 ret = is_truetype_font_installed("wine_test");
3938 ok(!ret, "font wine_test should not be enumerated\n");
3940 ret = GetTempPath(MAX_PATH, tmp_path);
3941 ok(ret, "GetTempPath() error %d\n", GetLastError());
3942 ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
3943 ok(ret, "GetTempFileName() error %d\n", GetLastError());
3945 ret = GetFileAttributes(fot_name);
3946 ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
3948 SetLastError(0xdeadbeef);
3949 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3950 ok(!ret, "CreateScalableFontResource() should fail\n");
3951 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3953 SetLastError(0xdeadbeef);
3954 ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
3955 ok(!ret, "CreateScalableFontResource() should fail\n");
3956 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3958 file_part = strrchr(ttf_name, '\\');
3959 SetLastError(0xdeadbeef);
3960 ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
3961 ok(!ret, "CreateScalableFontResource() should fail\n");
3962 ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3964 SetLastError(0xdeadbeef);
3965 ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
3966 ok(!ret, "CreateScalableFontResource() should fail\n");
3967 todo_wine
3968 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3970 SetLastError(0xdeadbeef);
3971 ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
3972 ok(!ret, "CreateScalableFontResource() should fail\n");
3973 todo_wine
3974 ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3976 ret = DeleteFile(fot_name);
3977 ok(ret, "DeleteFile() error %d\n", GetLastError());
3979 ret = pRemoveFontResourceExA(fot_name, 0, 0);
3980 todo_wine
3981 ok(!ret, "RemoveFontResourceEx() should fail\n");
3983 /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3984 if (ret) return;
3986 /* test public font resource */
3987 SetLastError(0xdeadbeef);
3988 ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3989 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3991 ret = is_truetype_font_installed("wine_test");
3992 ok(!ret, "font wine_test should not be enumerated\n");
3994 SetLastError(0xdeadbeef);
3995 ret = pAddFontResourceExA(fot_name, 0, 0);
3996 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3998 ret = is_truetype_font_installed("wine_test");
3999 ok(ret, "font wine_test should be enumerated\n");
4001 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4002 ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4004 SetLastError(0xdeadbeef);
4005 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4006 todo_wine
4007 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4009 ret = is_truetype_font_installed("wine_test");
4010 todo_wine
4011 ok(!ret, "font wine_test should not be enumerated\n");
4013 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4014 if (ret)
4016 /* remove once RemoveFontResource is implemented */
4017 DeleteFile(fot_name);
4018 DeleteFile(ttf_name);
4019 return;
4022 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4023 ok(!ret, "RemoveFontResourceEx() should fail\n");
4025 DeleteFile(fot_name);
4027 /* test hidden font resource */
4028 SetLastError(0xdeadbeef);
4029 ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4030 ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4032 ret = is_truetype_font_installed("wine_test");
4033 ok(!ret, "font wine_test should not be enumerated\n");
4035 SetLastError(0xdeadbeef);
4036 ret = pAddFontResourceExA(fot_name, 0, 0);
4037 ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4039 ret = is_truetype_font_installed("wine_test");
4040 ok(!ret, "font wine_test should not be enumerated\n");
4042 /* XP allows removing a private font added with 0 flags */
4043 SetLastError(0xdeadbeef);
4044 ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4045 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4047 ret = is_truetype_font_installed("wine_test");
4048 ok(!ret, "font wine_test should not be enumerated\n");
4050 ret = pRemoveFontResourceExA(fot_name, 0, 0);
4051 ok(!ret, "RemoveFontResourceEx() should fail\n");
4053 DeleteFile(fot_name);
4054 DeleteFile(ttf_name);
4057 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm)
4059 LOGFONTA lf;
4060 HFONT hfont, hfont_prev;
4061 HDC hdc;
4062 char facename[100];
4063 DWORD ret;
4065 *installed = is_truetype_font_installed(name);
4067 lf.lfHeight = -18;
4068 lf.lfWidth = 0;
4069 lf.lfEscapement = 0;
4070 lf.lfOrientation = 0;
4071 lf.lfWeight = FW_DONTCARE;
4072 lf.lfItalic = 0;
4073 lf.lfUnderline = 0;
4074 lf.lfStrikeOut = 0;
4075 lf.lfCharSet = DEFAULT_CHARSET;
4076 lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4077 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4078 lf.lfQuality = DEFAULT_QUALITY;
4079 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4080 strcpy(lf.lfFaceName, name);
4082 hfont = CreateFontIndirectA(&lf);
4083 ok(hfont != NULL, "CreateFontIndirectA failed\n");
4085 hdc = GetDC(NULL);
4087 hfont_prev = SelectObject(hdc, hfont);
4088 ok(hfont_prev != NULL, "SelectObject failed\n");
4090 ret = GetTextFaceA(hdc, sizeof facename, facename);
4091 ok(ret, "GetTextFaceA failed\n");
4092 *selected = !strcmp(facename, name);
4094 ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4095 ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4096 if (!*selected)
4097 memset(gm, 0, sizeof *gm);
4099 SelectObject(hdc, hfont_prev);
4100 DeleteObject(hfont);
4101 ReleaseDC(NULL, hdc);
4104 static void test_vertical_font(void)
4106 char ttf_name[MAX_PATH];
4107 int num;
4108 BOOL ret, installed, selected;
4109 GLYPHMETRICS gm;
4111 if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4113 win_skip("AddFontResourceExA is not available on this platform\n");
4114 return;
4117 if (!write_ttf_file("vertical.ttf", ttf_name))
4119 skip("Failed to create ttf file for testing\n");
4120 return;
4123 num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4124 todo_wine
4125 ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4127 check_vertical_font("@WineTestVertical", &installed, &selected, &gm);
4128 ok(installed, "@WineTestVertical is not installed\n");
4129 ok(selected, "@WineTestVertical is not selected\n");
4130 todo_wine
4131 ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4132 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4133 gm.gmBlackBoxX, gm.gmBlackBoxY);
4135 check_vertical_font("@@WineTestVertical", &installed, &selected, &gm);
4136 todo_wine
4137 ok(installed, "@@WineTestVertical is not installed\n");
4138 todo_wine
4139 ok(selected, "@@WineTestVertical is not selected\n");
4140 todo_wine
4141 ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4142 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4143 gm.gmBlackBoxX, gm.gmBlackBoxY);
4145 ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4146 ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4148 DeleteFile(ttf_name);
4151 START_TEST(font)
4153 init();
4155 test_logfont();
4156 test_bitmap_font();
4157 test_outline_font();
4158 test_bitmap_font_metrics();
4159 test_GdiGetCharDimensions();
4160 test_GetCharABCWidths();
4161 test_text_extents();
4162 test_GetGlyphIndices();
4163 test_GetKerningPairs();
4164 test_GetOutlineTextMetrics();
4165 test_SetTextJustification();
4166 test_font_charset();
4167 test_GetFontUnicodeRanges();
4168 test_nonexistent_font();
4169 test_orientation();
4170 test_height_selection();
4171 test_AddFontMemResource();
4172 test_EnumFonts();
4174 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4175 * I'd like to avoid them in this test.
4177 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4178 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4179 if (is_truetype_font_installed("Arial Black") &&
4180 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4182 test_EnumFontFamilies("", ANSI_CHARSET);
4183 test_EnumFontFamilies("", SYMBOL_CHARSET);
4184 test_EnumFontFamilies("", DEFAULT_CHARSET);
4186 else
4187 skip("Arial Black or Symbol/Wingdings is not installed\n");
4188 test_EnumFontFamiliesEx_default_charset();
4189 test_GetTextMetrics();
4190 test_GdiRealizationInfo();
4191 test_GetTextFace();
4192 test_GetGlyphOutline();
4193 test_GetTextMetrics2("Tahoma", -11);
4194 test_GetTextMetrics2("Tahoma", -55);
4195 test_GetTextMetrics2("Tahoma", -110);
4196 test_GetTextMetrics2("Arial", -11);
4197 test_GetTextMetrics2("Arial", -55);
4198 test_GetTextMetrics2("Arial", -110);
4199 test_CreateFontIndirect();
4200 test_CreateFontIndirectEx();
4201 test_oemcharset();
4202 test_fullname();
4204 test_vertical_font();
4205 /* CreateScalableFontResource should be last test until RemoveFontResource
4206 * is properly implemented.
4208 test_CreateScalableFontResource();