gdi32: Fix a typo in the memcmp call.
[wine] / dlls / gdi32 / tests / font.c
1 /*
2  * Unit test suite for fonts
3  *
4  * Copyright 2002 Mike McCormack
5  * Copyright 2004 Dmitry Timoshkov
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23 #include <assert.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
30
31 #include "wine/test.h"
32
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);
35
36 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
37 {
38     return 0;
39 }
40
41 static BOOL is_font_installed(const char *name)
42 {
43     HDC hdc = GetDC(0);
44     BOOL ret = FALSE;
45
46     if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
47         ret = TRUE;
48
49     ReleaseDC(0, hdc);
50     return ret;
51 }
52
53 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
54 {
55     LOGFONTA getobj_lf;
56     int ret, minlen = 0;
57
58     if (!hfont)
59         return;
60
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);
70 }
71
72 static HFONT create_font(const char* test, const LOGFONTA* lf)
73 {
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;
79 }
80
81 static void test_logfont(void)
82 {
83     LOGFONTA lf;
84     HFONT hfont;
85
86     memset(&lf, 0, sizeof lf);
87
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;
94
95     lstrcpyA(lf.lfFaceName, "Arial");
96     hfont = create_font("Arial", &lf);
97     DeleteObject(hfont);
98
99     memset(&lf, 'A', sizeof(lf));
100     hfont = CreateFontIndirectA(&lf);
101     ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
102     
103     lf.lfFaceName[LF_FACESIZE - 1] = 0;
104     check_font("AAA...", &lf, hfont);
105     DeleteObject(hfont);
106 }
107
108 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
109 {
110     if (type & RASTER_FONTTYPE)
111     {
112         LOGFONT *lf = (LOGFONT *)lParam;
113         *lf = *elf;
114         return 0; /* stop enumeration */
115     }
116
117     return 1; /* continue enumeration */
118 }
119
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)
124 {
125     HFONT old_hfont;
126     TEXTMETRICA tm;
127     SIZE size;
128     INT width;
129
130     if (!hfont)
131         return;
132
133     old_hfont = SelectObject(hdc, hfont);
134
135     GetTextMetricsA(hdc, &tm);
136
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);
141
142     GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
143
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);
146
147     GetCharWidthA(hdc, 'A', 'A', &width);
148
149     ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
150
151     SelectObject(hdc, old_hfont);
152 }
153
154 /* see whether GDI scales bitmap font metrics */
155 static void test_bitmap_font(void)
156 {
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;
164
165     hdc = GetDC(0);
166
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)
170     {
171         ReleaseDC(0, hdc);
172         trace("no bitmap fonts were found, skipping the test\n");
173         return;
174     }
175
176     trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
177
178     height_orig = bitmap_lf.lfHeight;
179     hfont = create_font("bitmap", &bitmap_lf);
180
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);
187
188     /* test fractional scaling */
189     for (i = 1; i < height_orig; i++)
190     {
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);
194     }
195
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
201 {
202     test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
203 }
204     DeleteObject(hfont);
205
206     /* test integer scaling 3x3 */
207     bitmap_lf.lfHeight = height_orig * 3;
208     bitmap_lf.lfWidth = 0;
209     hfont = create_font("3x3", &bitmap_lf);
210
211 todo_wine
212 {
213     test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
214 }
215     DeleteObject(hfont);
216
217     ReleaseDC(0, hdc);
218 }
219
220 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
221 {
222     LOGFONT *lf = (LOGFONT *)lParam;
223
224     if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
225     {
226         *lf = *elf;
227         return 0; /* stop enumeration */
228     }
229     return 1; /* continue enumeration */
230 }
231
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
246
247 static void test_bitmap_font_metrics(void)
248 {
249     static const struct font_data
250     {
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[] =
256     {
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 }
303
304         /* FIXME: add "Terminal" */
305     };
306     HDC hdc;
307     LOGFONT lf;
308     HFONT hfont, old_hfont;
309     TEXTMETRIC tm;
310     INT ret, i;
311
312     hdc = CreateCompatibleDC(0);
313     assert(hdc);
314
315     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
316     {
317         int bit;
318
319         memset(&lf, 0, sizeof(lf));
320
321         lf.lfHeight = fd[i].height;
322         strcpy(lf.lfFaceName, fd[i].face_name);
323
324         for(bit = 0; bit < 32; bit++)
325         {
326             DWORD fs[2];
327             CHARSETINFO csi;
328
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;
333
334             lf.lfCharSet = csi.ciCharset;
335             ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
336             if (ret) continue;
337
338             trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
339
340             hfont = create_font(lf.lfFaceName, &lf);
341             old_hfont = SelectObject(hdc, hfont);
342             ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
343
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);
351
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);
356
357             SelectObject(hdc, old_hfont);
358             DeleteObject(hfont);
359         }
360     }
361
362     DeleteDC(hdc);
363 }
364
365 static void test_GdiGetCharDimensions(void)
366 {
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;
376
377     hdc = CreateCompatibleDC(NULL);
378
379     GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
380     avgwidth = ((size.cx / 26) + 1) / 2;
381
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);
385
386     ret = GdiGetCharDimensions(hdc, &tm, NULL);
387     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
388
389     ret = GdiGetCharDimensions(hdc, NULL, NULL);
390     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
391
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);
396
397     DeleteDC(hdc);
398 }
399
400 static void test_GetCharABCWidthsW(void)
401 {
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;
407
408     ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
409     ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
410 }
411
412 static void test_text_extents(void)
413 {
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;
423
424     memset(&lf, 0, sizeof(lf));
425     strcpy(lf.lfFaceName, "Arial");
426     lf.lfHeight = 20;
427
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);
434
435     SetLastError(0xdeadbeef);
436     GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
437     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
438     {
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;
444     }
445
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. */
459
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",
463            i);
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);
479
480     hfont = SelectObject(hdc, hfont);
481     DeleteObject(hfont);
482     ReleaseDC(NULL, hdc);
483 }
484
485 static void test_GetGlyphIndices()
486 {
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;
495
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;
502     }
503
504     if(!is_font_installed("Symbol"))
505     {
506         trace("Symbol is not installed so skipping this test\n");
507         return;
508     }
509
510     memset(&lf, 0, sizeof(lf));
511     strcpy(lf.lfFaceName, "Symbol");
512     lf.lfHeight = 20;
513
514     hfont = CreateFontIndirectA(&lf);
515     hdc = GetDC(0);
516
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]);
527 }
528
529 static void test_GetKerningPairs(void)
530 {
531     static const struct kerning_data
532     {
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[] =
551     {
552         {"Arial", 12, 12, 9, 3,
553                   2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
554                   26,
555             {
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}
563                 }
564         },
565         {"Arial", -34, 39, 32, 7,
566                   2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
567                   26,
568             {
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}
576             }
577         },
578         { "Arial", 120, 120, 97, 23,
579                    2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
580                    26,
581             {
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}
589             }
590         },
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,
594                    26,
595             {
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}
603             }
604         }
605 #endif
606     };
607     LOGFONT lf;
608     HFONT hfont, hfont_old;
609     KERNINGPAIR *kern_pair;
610     HDC hdc;
611     DWORD total_kern_pairs, ret, i, n, matches;
612
613     hdc = GetDC(0);
614
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.
617      */
618     SetLastError(0xdeadbeef);
619     GetKerningPairsW(hdc, 0, NULL);
620     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
621     {
622         skip("Skipping the GetKerningPairs test on a Win9x platform\n");
623         ReleaseDC(0, hdc);
624         return;
625     }
626
627     for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
628     {
629         OUTLINETEXTMETRICW otm;
630
631         if (!is_font_installed(kd[i].face_name))
632         {
633             trace("%s is not installed so skipping this test\n", kd[i].face_name);
634             continue;
635         }
636
637         trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
638
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);
644
645         hfont_old = SelectObject(hdc, hfont);
646
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());
650
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);
657
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);
680 }
681
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));
685
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
693
694         ret = GetKerningPairsW(hdc, 100, NULL);
695         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
696
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);
699
700         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
701         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
702
703         matches = 0;
704
705         for (n = 0; n < ret; n++)
706         {
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++)
714             {
715                 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
716                     kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
717                 {
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++;
723                 }
724             }
725         }
726
727         ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
728            matches, kd[i].total_kern_pairs);
729
730         HeapFree(GetProcessHeap(), 0, kern_pair);
731
732         SelectObject(hdc, hfont_old);
733         DeleteObject(hfont);
734     }
735
736     ReleaseDC(0, hdc);
737 }
738
739 static void test_GetOutlineTextMetrics(void)
740 {
741     OUTLINETEXTMETRIC *otm;
742     LOGFONT lf;
743     HFONT hfont, hfont_old;
744     HDC hdc;
745     DWORD ret, otm_size;
746
747     if (!is_font_installed("Arial"))
748     {
749         skip("Arial is not installed\n");
750         return;
751     }
752
753     hdc = GetDC(0);
754
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);
763
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);
767
768     otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
769
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 */
778     {
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);
783     }
784
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 */
793     {
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);
798     }
799
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 */
809     {
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);
813     }
814     ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
815
816     HeapFree(GetProcessHeap(), 0, otm);
817
818     SelectObject(hdc, hfont_old);
819     DeleteObject(hfont);
820
821     ReleaseDC(0, hdc);
822 }
823
824 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
825 {
826     HDC hdc;
827     LOGFONTA lf;
828     HFONT hfont, hfont_old;
829     CHARSETINFO csi;
830     INT cs;
831     DWORD i, ret;
832
833     assert(count <= 128);
834
835     memset(&lf, 0, sizeof(lf));
836
837     lf.lfCharSet = charset;
838     lf.lfHeight = 10;
839     lstrcpyA(lf.lfFaceName, "Arial");
840     SetLastError(0xdeadbeef);
841     hfont = CreateFontIndirectA(&lf);
842     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
843
844     hdc = GetDC(0);
845     hfont_old = SelectObject(hdc, hfont);
846
847     cs = GetTextCharset(hdc);
848     ok(cs == charset, "expected %d, got %d\n", charset, cs);
849
850     if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
851     {
852         trace("Can't find codepage for charset %d\n", cs);
853         ReleaseDC(0, hdc);
854         return FALSE;
855     }
856     ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
857
858     if (unicode)
859     {
860         char ansi_buf[128];
861         WCHAR unicode_buf[128];
862
863         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
864
865         MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
866
867         SetLastError(0xdeadbeef);
868         ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
869         ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
870     }
871     else
872     {
873         char ansi_buf[128];
874
875         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
876
877         SetLastError(0xdeadbeef);
878         ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
879         ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
880     }
881
882     SelectObject(hdc, hfont_old);
883     DeleteObject(hfont);
884
885     ReleaseDC(0, hdc);
886
887     return TRUE;
888 }
889
890 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
891 {
892     INT         x, y,
893                 breakCount,
894                 outputWidth = 0,    /* to test TabbedTextOut() */
895                 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
896                 areaWidth = clientArea->right - clientArea->left,
897                 nErrors = 0, e;
898     BOOL        lastExtent = FALSE;
899     PSTR        pFirstChar, pLastChar;
900     SIZE        size;
901     TEXTMETRICA tm;
902     struct err
903     {
904         char extent[100];
905         int  GetTextExtentExPointWWidth;
906         int  TabbedTextOutWidth;
907     } error[10];
908
909     GetTextMetricsA(hdc, &tm);
910     y = clientArea->top;
911     do {
912         breakCount = 0;
913         while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
914         pFirstChar = str;
915
916         do {
917             pLastChar = str;
918
919             /* if not at the end of the string, ... */
920             if (*str == '\0') break;
921             /* ... add the next word to the current extent */
922             while (*str != '\0' && *str++ != tm.tmBreakChar);
923             breakCount++;
924             SetTextJustification(hdc, 0, 0);
925             GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
926         } while ((int) size.cx < areaWidth);
927
928         /* ignore trailing break chars */
929         breakCount--;
930         while (*(pLastChar - 1) == tm.tmBreakChar)
931         {
932             pLastChar--;
933             breakCount--;
934         }
935
936         if (*str == '\0' || breakCount <= 0) pLastChar = str;
937
938         SetTextJustification(hdc, 0, 0);
939         GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
940
941         /* do not justify the last extent */
942         if (*str != '\0' && breakCount > 0)
943         {
944             SetTextJustification(hdc, areaWidth - size.cx, breakCount);
945             GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
946             justifiedWidth = size.cx;
947         }
948         else lastExtent = TRUE;
949
950         x = clientArea->left;
951
952         outputWidth = LOWORD(TabbedTextOut(
953                              hdc, x, y, pFirstChar, pLastChar - pFirstChar,
954                              0, NULL, 0));
955         /* catch errors and report them */
956         if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
957         {
958             memset(error[nErrors].extent, 0, 100);
959             memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
960             error[nErrors].TabbedTextOutWidth = outputWidth;
961             error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
962             nErrors++;
963         }
964
965         y += size.cy;
966         str = pLastChar;
967     } while (*str && y < clientArea->bottom);
968
969     for (e = 0; e < nErrors; e++)
970     {
971         ok(error[e].TabbedTextOutWidth == areaWidth,
972             "The output text (\"%s\") width should be %d, not %d.\n",
973             error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
974         /* The width returned by GetTextExtentPoint32() is exactly the same
975            returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
976         ok(error[e].GetTextExtentExPointWWidth == areaWidth,
977             "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
978             error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
979     }
980 }
981
982 static void test_SetTextJustification(void)
983 {
984     HDC hdc = GetDC(0);
985     RECT clientArea = {0, 0, 400, 400};
986     LOGFONTA lf;
987     HFONT hfont;
988     static char testText[] =
989             "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
990             "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
991             "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
992             "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
993             "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
994             "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
995             "sunt in culpa qui officia deserunt mollit anim id est laborum.";
996
997     memset(&lf, 0, sizeof lf);
998     lf.lfCharSet = ANSI_CHARSET;
999     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1000     lf.lfWeight = FW_DONTCARE;
1001     lf.lfHeight = 20;
1002     lf.lfQuality = DEFAULT_QUALITY;
1003     lstrcpyA(lf.lfFaceName, "Times New Roman");
1004     hfont = create_font("Times New Roman", &lf);
1005     SelectObject(hdc, hfont);
1006
1007     testJustification(hdc, testText, &clientArea);
1008
1009     DeleteObject(hfont);
1010     ReleaseDC(0, hdc);
1011 }
1012
1013 static void test_font_charset(void)
1014 {
1015     static struct charset_data
1016     {
1017         INT charset;
1018         UINT code_page;
1019         WORD font_idxA[128], font_idxW[128];
1020     } cd[] =
1021     {
1022         { ANSI_CHARSET, 1252 },
1023         { SYMBOL_CHARSET, CP_SYMBOL },
1024         { RUSSIAN_CHARSET, 1251 }
1025     };
1026     int i;
1027
1028     pGetGlyphIndicesA = (void *)GetProcAddress(GetModuleHandle("gdi32.dll"), "GetGlyphIndicesA");
1029     pGetGlyphIndicesW = (void *)GetProcAddress(GetModuleHandle("gdi32.dll"), "GetGlyphIndicesW");
1030
1031     if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1032     {
1033         skip("Skipping the font charset test on a Win9x platform\n");
1034         return;
1035     }
1036
1037     if (!is_font_installed("Arial"))
1038     {
1039         skip("Arial is not installed\n");
1040         return;
1041     }
1042
1043     for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1044     {
1045         get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1046         get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1047         ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1048     }
1049
1050     ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1051     ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1052     ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1053 }
1054
1055 START_TEST(font)
1056 {
1057     test_logfont();
1058     test_bitmap_font();
1059     test_bitmap_font_metrics();
1060     test_GdiGetCharDimensions();
1061     test_GetCharABCWidthsW();
1062     test_text_extents();
1063     test_GetGlyphIndices();
1064     test_GetKerningPairs();
1065     test_GetOutlineTextMetrics();
1066     test_SetTextJustification();
1067     test_font_charset();
1068 }