gdi32/tests: Create a window for justification tests that generate output
[wine.git] / dlls / gdi32 / tests / font.c
blobf491459081b1fe776df89dd08cd7550257a5447d
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 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
34 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
36 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
38 return 0;
41 static BOOL is_font_installed(const char *name)
43 HDC hdc = GetDC(0);
44 BOOL ret = FALSE;
46 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
47 ret = TRUE;
49 ReleaseDC(0, hdc);
50 return ret;
53 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
55 LOGFONTA getobj_lf;
56 int ret, minlen = 0;
58 if (!hfont)
59 return;
61 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
62 /* NT4 tries to be clever and only returns the minimum length */
63 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
64 minlen++;
65 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
66 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
67 ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
68 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
69 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
72 static HFONT create_font(const char* test, const LOGFONTA* lf)
74 HFONT hfont = CreateFontIndirectA(lf);
75 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
76 if (hfont)
77 check_font(test, lf, hfont);
78 return hfont;
81 static void test_logfont(void)
83 LOGFONTA lf;
84 HFONT hfont;
86 memset(&lf, 0, sizeof lf);
88 lf.lfCharSet = ANSI_CHARSET;
89 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
90 lf.lfWeight = FW_DONTCARE;
91 lf.lfHeight = 16;
92 lf.lfWidth = 16;
93 lf.lfQuality = DEFAULT_QUALITY;
95 lstrcpyA(lf.lfFaceName, "Arial");
96 hfont = create_font("Arial", &lf);
97 DeleteObject(hfont);
99 memset(&lf, 'A', sizeof(lf));
100 hfont = CreateFontIndirectA(&lf);
101 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
103 lf.lfFaceName[LF_FACESIZE - 1] = 0;
104 check_font("AAA...", &lf, hfont);
105 DeleteObject(hfont);
108 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
110 if (type & RASTER_FONTTYPE)
112 LOGFONT *lf = (LOGFONT *)lParam;
113 *lf = *elf;
114 return 0; /* stop enumeration */
117 return 1; /* continue enumeration */
120 static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
121 INT test_str_len, const TEXTMETRICA *tm_orig,
122 const SIZE *size_orig, INT width_orig,
123 INT scale_x, INT scale_y)
125 HFONT old_hfont;
126 TEXTMETRICA tm;
127 SIZE size;
128 INT width;
130 if (!hfont)
131 return;
133 old_hfont = SelectObject(hdc, hfont);
135 GetTextMetricsA(hdc, &tm);
137 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
138 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
139 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
140 ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
142 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
144 ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x);
145 ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y);
147 GetCharWidthA(hdc, 'A', 'A', &width);
149 ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
151 SelectObject(hdc, old_hfont);
154 /* see whether GDI scales bitmap font metrics */
155 static void test_bitmap_font(void)
157 static const char test_str[11] = "Test String";
158 HDC hdc;
159 LOGFONTA bitmap_lf;
160 HFONT hfont, old_hfont;
161 TEXTMETRICA tm_orig;
162 SIZE size_orig;
163 INT ret, i, width_orig, height_orig;
165 hdc = GetDC(0);
167 /* "System" has only 1 pixel size defined, otherwise the test breaks */
168 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
169 if (ret)
171 ReleaseDC(0, hdc);
172 trace("no bitmap fonts were found, skipping the test\n");
173 return;
176 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
178 height_orig = bitmap_lf.lfHeight;
179 hfont = create_font("bitmap", &bitmap_lf);
181 old_hfont = SelectObject(hdc, hfont);
182 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
183 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
184 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
185 SelectObject(hdc, old_hfont);
186 DeleteObject(hfont);
188 /* test fractional scaling */
189 for (i = 1; i < height_orig; i++)
191 hfont = create_font("fractional", &bitmap_lf);
192 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
193 DeleteObject(hfont);
196 /* test integer scaling 3x2 */
197 bitmap_lf.lfHeight = height_orig * 2;
198 bitmap_lf.lfWidth *= 3;
199 hfont = create_font("3x2", &bitmap_lf);
200 todo_wine
202 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
204 DeleteObject(hfont);
206 /* test integer scaling 3x3 */
207 bitmap_lf.lfHeight = height_orig * 3;
208 bitmap_lf.lfWidth = 0;
209 hfont = create_font("3x3", &bitmap_lf);
211 todo_wine
213 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
215 DeleteObject(hfont);
217 ReleaseDC(0, hdc);
220 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
222 LOGFONT *lf = (LOGFONT *)lParam;
224 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
226 *lf = *elf;
227 return 0; /* stop enumeration */
229 return 1; /* continue enumeration */
232 #define CP1252_BIT 0x00000001
233 #define CP1250_BIT 0x00000002
234 #define CP1251_BIT 0x00000004
235 #define CP1253_BIT 0x00000008
236 #define CP1254_BIT 0x00000010
237 #define CP1255_BIT 0x00000020
238 #define CP1256_BIT 0x00000040
239 #define CP1257_BIT 0x00000080
240 #define CP1258_BIT 0x00000100
241 #define CP874_BIT 0x00010000
242 #define CP932_BIT 0x00020000
243 #define CP936_BIT 0x00040000
244 #define CP949_BIT 0x00080000
245 #define CP950_BIT 0x00100000
247 static void test_bitmap_font_metrics(void)
249 static const struct font_data
251 const char face_name[LF_FACESIZE];
252 int weight, height, ascent, descent, int_leading, ext_leading;
253 int ave_char_width, max_char_width;
254 DWORD ansi_bitfield;
255 } fd[] =
257 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT | CP1250_BIT | CP1251_BIT },
258 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT | CP1250_BIT | CP1251_BIT },
259 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, CP1252_BIT | CP1251_BIT },
260 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, CP1250_BIT },
261 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, CP1252_BIT },
262 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, CP1250_BIT },
263 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, CP1251_BIT },
264 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, CP1252_BIT },
265 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, CP1250_BIT },
266 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, CP1251_BIT },
267 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, CP1252_BIT | CP1250_BIT | CP1251_BIT },
268 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
269 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
270 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
271 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT },
272 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, CP1250_BIT | CP1251_BIT },
273 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, CP1252_BIT | CP1250_BIT },
274 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, CP1251_BIT },
275 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, CP1252_BIT | CP1250_BIT },
276 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, CP1251_BIT },
277 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, CP1252_BIT },
278 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, CP1250_BIT },
279 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, CP1251_BIT },
280 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, CP1252_BIT },
281 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, CP1250_BIT },
282 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, CP1251_BIT },
283 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, CP1252_BIT | CP1250_BIT },
284 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, CP1251_BIT },
285 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, CP1252_BIT | CP1250_BIT | CP1251_BIT },
286 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
287 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, CP1252_BIT | CP1250_BIT | CP1251_BIT },
288 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT },
289 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, CP1250_BIT | CP1251_BIT },
290 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT},
291 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT | CP1251_BIT },
292 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT },
293 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT | CP1251_BIT },
294 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT },
295 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT | CP1251_BIT },
296 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT },
297 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT | CP1251_BIT },
298 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
299 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
300 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
301 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT | CP1250_BIT },
302 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT }
304 /* FIXME: add "Terminal" */
306 HDC hdc;
307 LOGFONT lf;
308 HFONT hfont, old_hfont;
309 TEXTMETRIC tm;
310 INT ret, i;
312 hdc = CreateCompatibleDC(0);
313 assert(hdc);
315 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
317 int bit;
319 memset(&lf, 0, sizeof(lf));
321 lf.lfHeight = fd[i].height;
322 strcpy(lf.lfFaceName, fd[i].face_name);
324 for(bit = 0; bit < 32; bit++)
326 DWORD fs[2];
327 CHARSETINFO csi;
329 fs[0] = 1L << bit;
330 fs[1] = 0;
331 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
332 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
334 lf.lfCharSet = csi.ciCharset;
335 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
336 if (ret) continue;
338 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
340 hfont = create_font(lf.lfFaceName, &lf);
341 old_hfont = SelectObject(hdc, hfont);
342 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
344 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);
345 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);
346 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);
347 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);
348 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);
349 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);
350 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);
352 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
353 that make the max width bigger */
354 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
355 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);
357 SelectObject(hdc, old_hfont);
358 DeleteObject(hfont);
362 DeleteDC(hdc);
365 static void test_GdiGetCharDimensions(void)
367 HDC hdc;
368 TEXTMETRICW tm;
369 LONG ret;
370 SIZE size;
371 LONG avgwidth, height;
372 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
373 typedef LONG (WINAPI *fnGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
374 fnGdiGetCharDimensions GdiGetCharDimensions = (fnGdiGetCharDimensions)GetProcAddress(LoadLibrary("gdi32"), "GdiGetCharDimensions");
375 if (!GdiGetCharDimensions) return;
377 hdc = CreateCompatibleDC(NULL);
379 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
380 avgwidth = ((size.cx / 26) + 1) / 2;
382 ret = GdiGetCharDimensions(hdc, &tm, &height);
383 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
384 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
386 ret = GdiGetCharDimensions(hdc, &tm, NULL);
387 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
389 ret = GdiGetCharDimensions(hdc, NULL, NULL);
390 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
392 height = 0;
393 ret = GdiGetCharDimensions(hdc, NULL, &height);
394 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
395 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
397 DeleteDC(hdc);
400 static void test_GetCharABCWidthsW(void)
402 BOOL ret;
403 ABC abc[1];
404 typedef BOOL (WINAPI *fnGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
405 fnGetCharABCWidthsW GetCharABCWidthsW = (fnGetCharABCWidthsW)GetProcAddress(LoadLibrary("gdi32"), "GetCharABCWidthsW");
406 if (!GetCharABCWidthsW) return;
408 ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
409 ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
412 static void test_text_extents(void)
414 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
415 LPINT extents;
416 INT i, len, fit1, fit2;
417 LOGFONTA lf;
418 TEXTMETRICA tm;
419 HDC hdc;
420 HFONT hfont;
421 SIZE sz;
422 SIZE sz1, sz2;
424 memset(&lf, 0, sizeof(lf));
425 strcpy(lf.lfFaceName, "Arial");
426 lf.lfHeight = 20;
428 hfont = CreateFontIndirectA(&lf);
429 hdc = GetDC(0);
430 hfont = SelectObject(hdc, hfont);
431 GetTextMetricsA(hdc, &tm);
432 GetTextExtentPointA(hdc, "o", 1, &sz);
433 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
435 SetLastError(0xdeadbeef);
436 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
437 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
439 skip("Skipping remainder of text extents test on a Win9x platform\n");
440 hfont = SelectObject(hdc, hfont);
441 DeleteObject(hfont);
442 ReleaseDC(0, hdc);
443 return;
446 len = lstrlenW(wt);
447 extents = HeapAlloc(GetProcessHeap(), 0, len * sizeof extents[0]);
448 memset(extents, 0, len * sizeof extents[0]);
449 extents[0] = 1; /* So that the increasing sequence test will fail
450 if the extents array is untouched. */
451 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
452 GetTextExtentPointW(hdc, wt, len, &sz2);
453 ok(sz1.cy == sz2.cy,
454 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
455 /* Because of the '\n' in the string GetTextExtentExPoint and
456 GetTextExtentPoint return different widths under Win2k, but
457 under WinXP they return the same width. So we don't test that
458 here. */
460 for (i = 1; i < len; ++i)
461 ok(extents[i-1] <= extents[i],
462 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
464 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
465 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
466 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
467 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
468 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
469 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
470 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
471 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
472 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
473 ok(extents[0] == extents[2] && extents[1] == extents[3],
474 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
475 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
476 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
477 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
478 HeapFree(GetProcessHeap(), 0, extents);
480 hfont = SelectObject(hdc, hfont);
481 DeleteObject(hfont);
482 ReleaseDC(NULL, hdc);
485 static void test_GetGlyphIndices()
487 HDC hdc;
488 HFONT hfont;
489 DWORD charcount;
490 LOGFONTA lf;
491 DWORD flags = 0;
492 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
493 WORD glyphs[(sizeof(testtext)/2)-1];
494 TEXTMETRIC textm;
496 typedef BOOL (WINAPI *fnGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
497 fnGetGlyphIndicesW GetGlyphIndicesW = (fnGetGlyphIndicesW)GetProcAddress(LoadLibrary("gdi32"),
498 "GetGlyphIndicesW");
499 if (!GetGlyphIndicesW) {
500 trace("GetGlyphIndices not available on platform\n");
501 return;
504 if(!is_font_installed("Symbol"))
506 trace("Symbol is not installed so skipping this test\n");
507 return;
510 memset(&lf, 0, sizeof(lf));
511 strcpy(lf.lfFaceName, "Symbol");
512 lf.lfHeight = 20;
514 hfont = CreateFontIndirectA(&lf);
515 hdc = GetDC(0);
517 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
518 flags |= GGI_MARK_NONEXISTING_GLYPHS;
519 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
520 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
521 ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
522 flags = 0;
523 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
524 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
525 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
526 textm.tmDefaultChar, glyphs[4]);
529 static void test_GetKerningPairs(void)
531 static const struct kerning_data
533 const char face_name[LF_FACESIZE];
534 LONG height;
535 /* some interesting fields from OUTLINETEXTMETRIC */
536 LONG tmHeight, tmAscent, tmDescent;
537 UINT otmEMSquare;
538 INT otmAscent;
539 INT otmDescent;
540 UINT otmLineGap;
541 UINT otmsCapEmHeight;
542 UINT otmsXHeight;
543 INT otmMacAscent;
544 INT otmMacDescent;
545 UINT otmMacLineGap;
546 UINT otmusMinimumPPEM;
547 /* small subset of kerning pairs to test */
548 DWORD total_kern_pairs;
549 const KERNINGPAIR kern_pair[26];
550 } kd[] =
552 {"Arial", 12, 12, 9, 3,
553 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
556 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
557 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
558 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
559 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
560 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
561 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
562 {933,970,+1},{933,972,-1}
565 {"Arial", -34, 39, 32, 7,
566 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
569 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
570 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
571 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
572 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
573 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
574 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
575 {933,970,+2},{933,972,-3}
578 { "Arial", 120, 120, 97, 23,
579 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
582 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
583 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
584 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
585 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
586 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
587 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
588 {933,970,+6},{933,972,-10}
591 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
592 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
593 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
596 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
597 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
598 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
599 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
600 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
601 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
602 {933,970,+54},{933,972,-83}
605 #endif
607 LOGFONT lf;
608 HFONT hfont, hfont_old;
609 KERNINGPAIR *kern_pair;
610 HDC hdc;
611 DWORD total_kern_pairs, ret, i, n, matches;
613 hdc = GetDC(0);
615 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
616 * which may render this test unusable, so we're trying to avoid that.
618 SetLastError(0xdeadbeef);
619 GetKerningPairsW(hdc, 0, NULL);
620 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
622 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
623 ReleaseDC(0, hdc);
624 return;
627 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
629 OUTLINETEXTMETRICW otm;
631 if (!is_font_installed(kd[i].face_name))
633 trace("%s is not installed so skipping this test\n", kd[i].face_name);
634 continue;
637 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
639 memset(&lf, 0, sizeof(lf));
640 strcpy(lf.lfFaceName, kd[i].face_name);
641 lf.lfHeight = kd[i].height;
642 hfont = CreateFontIndirect(&lf);
643 assert(hfont != 0);
645 hfont_old = SelectObject(hdc, hfont);
647 SetLastError(0xdeadbeef);
648 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
649 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
651 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
652 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
653 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
654 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
655 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
656 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
658 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
659 kd[i].otmEMSquare, otm.otmEMSquare);
660 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
661 kd[i].otmAscent, otm.otmAscent);
662 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
663 kd[i].otmDescent, otm.otmDescent);
664 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
665 kd[i].otmLineGap, otm.otmLineGap);
666 todo_wine {
667 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
668 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
669 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
670 kd[i].otmsXHeight, otm.otmsXHeight);
671 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
672 kd[i].otmMacAscent, otm.otmMacAscent);
673 ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
674 kd[i].otmMacDescent, otm.otmMacDescent);
675 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
676 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
677 kd[i].otmMacLineGap, otm.otmMacLineGap);
678 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
679 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
682 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
683 trace("total_kern_pairs %u\n", total_kern_pairs);
684 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
686 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
687 SetLastError(0xdeadbeef);
688 ret = GetKerningPairsW(hdc, 0, kern_pair);
689 ok(GetLastError() == ERROR_INVALID_PARAMETER,
690 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
691 ok(ret == 0, "got %lu, expected 0\n", ret);
692 #endif
694 ret = GetKerningPairsW(hdc, 100, NULL);
695 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
697 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
698 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
700 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
701 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
703 matches = 0;
705 for (n = 0; n < ret; n++)
707 DWORD j;
708 #if 0
709 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
710 trace("{'%c','%c',%d},\n",
711 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
712 #endif
713 for (j = 0; j < kd[i].total_kern_pairs; j++)
715 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
716 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
718 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
719 "pair %d:%d got %d, expected %d\n",
720 kern_pair[n].wFirst, kern_pair[n].wSecond,
721 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
722 matches++;
727 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
728 matches, kd[i].total_kern_pairs);
730 HeapFree(GetProcessHeap(), 0, kern_pair);
732 SelectObject(hdc, hfont_old);
733 DeleteObject(hfont);
736 ReleaseDC(0, hdc);
739 static void test_GetOutlineTextMetrics(void)
741 OUTLINETEXTMETRIC *otm;
742 LOGFONT lf;
743 HFONT hfont, hfont_old;
744 HDC hdc;
745 DWORD ret, otm_size;
747 if (!is_font_installed("Arial"))
749 skip("Arial is not installed\n");
750 return;
753 hdc = GetDC(0);
755 memset(&lf, 0, sizeof(lf));
756 strcpy(lf.lfFaceName, "Arial");
757 lf.lfHeight = -13;
758 lf.lfWeight = FW_NORMAL;
759 lf.lfPitchAndFamily = DEFAULT_PITCH;
760 lf.lfQuality = PROOF_QUALITY;
761 hfont = CreateFontIndirect(&lf);
762 assert(hfont != 0);
764 hfont_old = SelectObject(hdc, hfont);
765 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
766 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
768 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
770 memset(otm, 0xAA, otm_size);
771 SetLastError(0xdeadbeef);
772 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
773 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
774 ok(ret == 1 /* Win9x */ ||
775 ret == otm->otmSize /* XP*/,
776 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
777 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
779 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
780 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
781 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
782 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
785 memset(otm, 0xAA, otm_size);
786 SetLastError(0xdeadbeef);
787 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
788 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
789 ok(ret == 1 /* Win9x */ ||
790 ret == otm->otmSize /* XP*/,
791 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
792 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
794 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
795 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
796 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
797 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
800 /* ask about truncated data */
801 memset(otm, 0xAA, otm_size);
802 SetLastError(0xdeadbeef);
803 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
804 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
805 ok(ret == 1 /* Win9x */ ||
806 ret == otm->otmSize /* XP*/,
807 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
808 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
810 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
811 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
812 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
814 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
816 HeapFree(GetProcessHeap(), 0, otm);
818 SelectObject(hdc, hfont_old);
819 DeleteObject(hfont);
821 ReleaseDC(0, hdc);
824 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
826 HDC hdc;
827 LOGFONTA lf;
828 HFONT hfont, hfont_old;
829 CHARSETINFO csi;
830 FONTSIGNATURE fs;
831 INT cs;
832 DWORD i, ret;
833 char name[64];
835 assert(count <= 128);
837 memset(&lf, 0, sizeof(lf));
839 lf.lfCharSet = charset;
840 lf.lfHeight = 10;
841 lstrcpyA(lf.lfFaceName, "Arial");
842 SetLastError(0xdeadbeef);
843 hfont = CreateFontIndirectA(&lf);
844 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
846 hdc = GetDC(0);
847 hfont_old = SelectObject(hdc, hfont);
849 cs = GetTextCharsetInfo(hdc, &fs, 0);
850 ok(cs == charset, "expected %d, got %d\n", charset, cs);
852 SetLastError(0xdeadbeef);
853 ret = GetTextFace(hdc, sizeof(name), name);
854 ok(ret, "GetTextFace error %u\n", GetLastError());
856 if (charset == SYMBOL_CHARSET)
858 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
859 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
861 else
863 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
864 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
867 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
869 trace("Can't find codepage for charset %d\n", cs);
870 ReleaseDC(0, hdc);
871 return FALSE;
873 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
875 if (unicode)
877 char ansi_buf[128];
878 WCHAR unicode_buf[128];
880 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
882 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
884 SetLastError(0xdeadbeef);
885 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
886 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
888 else
890 char ansi_buf[128];
892 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
894 SetLastError(0xdeadbeef);
895 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
896 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
899 SelectObject(hdc, hfont_old);
900 DeleteObject(hfont);
902 ReleaseDC(0, hdc);
904 return TRUE;
907 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
909 INT x, y,
910 breakCount,
911 outputWidth = 0, /* to test TabbedTextOut() */
912 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
913 areaWidth = clientArea->right - clientArea->left,
914 nErrors = 0, e;
915 BOOL lastExtent = FALSE;
916 PSTR pFirstChar, pLastChar;
917 SIZE size;
918 TEXTMETRICA tm;
919 struct err
921 char extent[100];
922 int GetTextExtentExPointWWidth;
923 int TabbedTextOutWidth;
924 } error[10];
926 GetTextMetricsA(hdc, &tm);
927 y = clientArea->top;
928 do {
929 breakCount = 0;
930 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
931 pFirstChar = str;
933 do {
934 pLastChar = str;
936 /* if not at the end of the string, ... */
937 if (*str == '\0') break;
938 /* ... add the next word to the current extent */
939 while (*str != '\0' && *str++ != tm.tmBreakChar);
940 breakCount++;
941 SetTextJustification(hdc, 0, 0);
942 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
943 } while ((int) size.cx < areaWidth);
945 /* ignore trailing break chars */
946 breakCount--;
947 while (*(pLastChar - 1) == tm.tmBreakChar)
949 pLastChar--;
950 breakCount--;
953 if (*str == '\0' || breakCount <= 0) pLastChar = str;
955 SetTextJustification(hdc, 0, 0);
956 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
958 /* do not justify the last extent */
959 if (*str != '\0' && breakCount > 0)
961 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
962 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
963 justifiedWidth = size.cx;
965 else lastExtent = TRUE;
967 x = clientArea->left;
969 outputWidth = LOWORD(TabbedTextOut(
970 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
971 0, NULL, 0));
972 /* catch errors and report them */
973 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
975 memset(error[nErrors].extent, 0, 100);
976 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
977 error[nErrors].TabbedTextOutWidth = outputWidth;
978 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
979 nErrors++;
982 y += size.cy;
983 str = pLastChar;
984 } while (*str && y < clientArea->bottom);
986 for (e = 0; e < nErrors; e++)
988 ok(error[e].TabbedTextOutWidth == areaWidth,
989 "The output text (\"%s\") width should be %d, not %d.\n",
990 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
991 /* The width returned by GetTextExtentPoint32() is exactly the same
992 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
993 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
994 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
995 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
999 static void test_SetTextJustification(void)
1001 HDC hdc;
1002 RECT clientArea;
1003 LOGFONTA lf;
1004 HFONT hfont;
1005 HWND hwnd;
1006 static char testText[] =
1007 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1008 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1009 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1010 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1011 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1012 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1013 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1015 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1016 GetClientRect( hwnd, &clientArea );
1017 hdc = GetDC( hwnd );
1019 memset(&lf, 0, sizeof lf);
1020 lf.lfCharSet = ANSI_CHARSET;
1021 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1022 lf.lfWeight = FW_DONTCARE;
1023 lf.lfHeight = 20;
1024 lf.lfQuality = DEFAULT_QUALITY;
1025 lstrcpyA(lf.lfFaceName, "Times New Roman");
1026 hfont = create_font("Times New Roman", &lf);
1027 SelectObject(hdc, hfont);
1029 testJustification(hdc, testText, &clientArea);
1031 DeleteObject(hfont);
1032 ReleaseDC(hwnd, hdc);
1033 DestroyWindow(hwnd);
1036 static void test_font_charset(void)
1038 static struct charset_data
1040 INT charset;
1041 UINT code_page;
1042 WORD font_idxA[128], font_idxW[128];
1043 } cd[] =
1045 { ANSI_CHARSET, 1252 },
1046 { RUSSIAN_CHARSET, 1251 },
1047 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1049 int i;
1051 pGetGlyphIndicesA = (void *)GetProcAddress(GetModuleHandle("gdi32.dll"), "GetGlyphIndicesA");
1052 pGetGlyphIndicesW = (void *)GetProcAddress(GetModuleHandle("gdi32.dll"), "GetGlyphIndicesW");
1054 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1056 skip("Skipping the font charset test on a Win9x platform\n");
1057 return;
1060 if (!is_font_installed("Arial"))
1062 skip("Arial is not installed\n");
1063 return;
1066 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1068 if (cd[i].charset == SYMBOL_CHARSET)
1070 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1072 skip("Symbol or Wingdings is not installed\n");
1073 break;
1076 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1077 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1078 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1081 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1082 if (i > 2)
1084 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1085 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1087 else
1088 skip("Symbol or Wingdings is not installed\n");
1091 START_TEST(font)
1093 test_logfont();
1094 test_bitmap_font();
1095 test_bitmap_font_metrics();
1096 test_GdiGetCharDimensions();
1097 test_GetCharABCWidthsW();
1098 test_text_extents();
1099 test_GetGlyphIndices();
1100 test_GetKerningPairs();
1101 test_GetOutlineTextMetrics();
1102 test_SetTextJustification();
1103 test_font_charset();