Prevent crash when no URL is specified.
[wine] / dlls / gdi / tests / metafile.c
1 /*
2  * Unit tests for metafile functions
3  *
4  * Copyright (c) 2002 Dmitry Timoshkov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23
24 #include "wine/test.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winerror.h"
29
30 static LOGFONTA orig_lf;
31 static BOOL emr_processed = FALSE;
32
33 static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
34     const ENHMETARECORD *emr, int n_objs, LPARAM param)
35 {
36     static int n_record;
37     DWORD i;
38     const INT *dx;
39     INT *orig_dx = (INT *)param;
40     LOGFONTA device_lf;
41     INT ret;
42
43     trace("hdc %p, emr->iType %ld, emr->nSize %ld, param %p\n",
44            hdc, emr->iType, emr->nSize, (void *)param);
45
46     PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
47
48     switch (emr->iType)
49     {
50     case EMR_HEADER:
51         n_record = 0;
52         break;
53
54     case EMR_EXTTEXTOUTA:
55     {
56         const EMREXTTEXTOUTA *emr_ExtTextOutA = (const EMREXTTEXTOUTA *)emr;
57         dx = (const INT *)((const char *)emr + emr_ExtTextOutA->emrtext.offDx);
58
59         ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
60         ok( ret == sizeof(device_lf), "GetObjectA error %ld\n", GetLastError());
61
62         /* compare up to lfOutPrecision, other values are not interesting,
63          * and in fact sometimes arbitrary adapted by Win9x.
64          */
65         ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
66         ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
67
68         for(i = 0; i < emr_ExtTextOutA->emrtext.nChars; i++)
69         {
70             ok(orig_dx[i] == dx[i], "pass %d: dx[%ld] (%d) didn't match %d\n",
71                                      n_record, i, dx[i], orig_dx[i]);
72         }
73         n_record++;
74         emr_processed = TRUE;
75         break;
76     }
77
78     case EMR_EXTTEXTOUTW:
79     {
80         const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr;
81         dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx);
82
83         ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
84         ok( ret == sizeof(device_lf), "GetObjectA error %ld\n", GetLastError());
85
86         /* compare up to lfOutPrecision, other values are not interesting,
87          * and in fact sometimes arbitrary adapted by Win9x.
88          */
89         ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
90         ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
91
92         for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
93         {
94             ok(orig_dx[i] == dx[i], "pass %d: dx[%ld] (%d) didn't match %d\n",
95                                      n_record, i, dx[i], orig_dx[i]);
96         }
97         n_record++;
98         emr_processed = TRUE;
99         break;
100     }
101
102     default:
103         break;
104     }
105
106     return 1;
107 }
108
109 static void test_ExtTextOut(void)
110 {
111     HWND hwnd;
112     HDC hdcDisplay, hdcMetafile;
113     HENHMETAFILE hMetafile;
114     HFONT hFont;
115     static const char text[] = "Simple text to test ExtTextOut on metafiles";
116     INT i, len, dx[256];
117     static const RECT rc = { 0, 0, 100, 100 };
118     BOOL ret;
119
120     assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
121
122     /* Win9x doesn't play EMFs on invisible windows */
123     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
124                            0, 0, 200, 200, 0, 0, 0, NULL);
125     ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
126
127     hdcDisplay = GetDC(hwnd);
128     ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
129
130     trace("hdcDisplay %p\n", hdcDisplay);
131
132     SetMapMode(hdcDisplay, MM_TEXT);
133
134     memset(&orig_lf, 0, sizeof(orig_lf));
135
136     orig_lf.lfCharSet = ANSI_CHARSET;
137     orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
138     orig_lf.lfWeight = FW_DONTCARE;
139     orig_lf.lfHeight = 7;
140     orig_lf.lfQuality = DEFAULT_QUALITY;
141     lstrcpyA(orig_lf.lfFaceName, "Arial");
142     hFont = CreateFontIndirectA(&orig_lf);
143     ok(hFont != 0, "CreateFontIndirectA error %ld\n", GetLastError());
144
145     hFont = SelectObject(hdcDisplay, hFont);
146
147     len = lstrlenA(text);
148     for (i = 0; i < len; i++)
149     {
150         ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
151         ok( ret, "GetCharWidthA error %ld\n", GetLastError());
152     }
153     hFont = SelectObject(hdcDisplay, hFont);
154
155     hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
156     ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
157
158     trace("hdcMetafile %p\n", hdcMetafile);
159
160     ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
161        "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
162
163     hFont = SelectObject(hdcMetafile, hFont);
164
165     /* 1. pass NULL lpDx */
166     ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
167     ok( ret, "ExtTextOutA error %ld\n", GetLastError());
168
169     /* 2. pass custom lpDx */
170     ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
171     ok( ret, "ExtTextOutA error %ld\n", GetLastError());
172
173     hFont = SelectObject(hdcMetafile, hFont);
174     ret = DeleteObject(hFont);
175     ok( ret, "DeleteObject error %ld\n", GetLastError());
176
177     hMetafile = CloseEnhMetaFile(hdcMetafile);
178     ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
179
180     ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
181
182     ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
183     ok( ret, "PlayEnhMetaFile error %ld\n", GetLastError());
184
185     ret = EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, &rc);
186     ok( ret, "EnumEnhMetaFile error %ld\n", GetLastError());
187
188     ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
189
190     ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, NULL),
191        "A valid hdc has to require a valid rc\n");
192
193     ret = DeleteEnhMetaFile(hMetafile);
194     ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
195     ret = ReleaseDC(hwnd, hdcDisplay);
196     ok( ret, "ReleaseDC error %ld\n", GetLastError());
197 }
198
199 /* Win-format metafile (mfdrv) tests */
200 /* These tests compare the generated metafiles byte-by-byte */
201 /* with the nominal results. */
202
203 /* Maximum size of sample metafiles in bytes. */
204 #define MF_BUFSIZE 256
205
206 /* 8x8 bitmap data for a pattern brush */
207 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
208     0x01, 0x00, 0x02, 0x00,
209     0x03, 0x00, 0x04, 0x00,
210     0x05, 0x00, 0x06, 0x00,
211     0x07, 0x00, 0x08, 0x00
212 };
213
214 /* Sample metafiles to be compared to the outputs of the
215  * test functions.
216  */
217
218 static const unsigned char MF_BLANK_BITS[] = {
219     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
220     0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
221     0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
222 };
223
224 static const unsigned char MF_GRAPHICS_BITS[] = {
225     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
226     0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
227     0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
228     0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
229     0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
230     0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
231     0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
232     0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
233     0x00, 0x00, 0x00, 0x00
234 };
235
236 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
237     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
238     0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
239     0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
240     0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
241     0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
242     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
243     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246     0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
247     0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
248     0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
249     0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
250     0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
251     0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
252     0x00, 0x00
253 };
254
255 /* For debugging or dumping the raw metafiles produced by
256  * new test functions.
257  */
258
259 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
260 {
261     char buf[MF_BUFSIZE];
262     UINT mfsize, i;
263
264     mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
265     ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
266
267     printf ("MetaFile %s has bits:\n{\n    ", desc);
268     for (i=0; i<mfsize; i++)
269     {
270         printf ("0x%.2hhx", buf[i]);
271         if (i == mfsize-1)
272             printf ("\n");
273         else if (i % 8 == 7)
274             printf (",\n    ");
275         else
276             printf (", ");
277     }
278     printf ("};\n");
279 }
280
281 /* Compare the metafile produced by a test function with the
282  * expected raw metafile data in "bits".
283  * Return value is 0 for a perfect match,
284  * -1 if lengths aren't equal,
285  * otherwise returns the number of non-matching bytes.
286  */
287
288 static int compare_mf_bits (const HMETAFILE mf, const char *bits, UINT bsize,
289     const char *desc)
290 {
291     char buf[MF_BUFSIZE];
292     UINT mfsize, i;
293     int diff;
294
295     mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
296     ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
297     if (mfsize < MF_BUFSIZE)
298         ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
299             desc, mfsize, bsize);
300     else
301         ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
302             desc, mfsize, bsize);
303     if (mfsize != bsize)
304         return -1;
305
306     diff = 0;
307     for (i=0; i<bsize; i++)
308     {
309        if (buf[i] !=  bits[i])
310            diff++;
311     }
312     ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
313         desc, mfsize, bsize, diff);
314
315     return diff; 
316 }
317
318 /* Test a blank metafile.  May be used as a template for new tests. */
319
320 static void test_mf_Blank(void)
321 {
322     HDC hdcMetafile;
323     HMETAFILE hMetafile;
324     INT caps;
325     BOOL ret;
326
327     hdcMetafile = CreateMetaFileA(NULL);
328     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
329     trace("hdcMetafile %p\n", hdcMetafile);
330
331 /* Tests on metafile initialization */
332     caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
333     ok (caps == DT_METAFILE,
334         "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
335
336     hMetafile = CloseMetaFile(hdcMetafile);
337     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
338     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
339
340     if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
341         "mf_blank") != 0)
342             dump_mf_bits (hMetafile, "mf_Blank");
343
344     ret = DeleteMetaFile(hMetafile);
345     ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
346 }
347
348 /* Simple APIs from mfdrv/graphics.c
349  */
350
351 static void test_mf_Graphics()
352 {
353     HDC hdcMetafile;
354     HMETAFILE hMetafile;
355     POINT oldpoint;
356     BOOL ret;
357
358     hdcMetafile = CreateMetaFileA(NULL);
359     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
360     trace("hdcMetafile %p\n", hdcMetafile);
361
362     ret = MoveToEx(hdcMetafile, 1, 1, NULL);
363     ok( ret, "MoveToEx error %ld.\n", GetLastError());
364     ret = LineTo(hdcMetafile, 2, 2);
365     ok( ret, "LineTo error %ld.\n", GetLastError());
366     ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
367     ok( ret, "MoveToEx error %ld.\n", GetLastError());
368
369 /* oldpoint gets garbage under Win XP, so the following test would
370  * work under Wine but fails under Windows:
371  *
372  *   ok((oldpoint.x == 2) && (oldpoint.y == 2),
373  *       "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
374  *       oldpoint.x, oldpoint.y);
375  */
376
377     ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
378     ok( ret, "Ellipse error %ld.\n", GetLastError());
379
380     hMetafile = CloseMetaFile(hdcMetafile);
381     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
382     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
383
384     if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
385         "mf_Graphics") != 0)
386             dump_mf_bits (hMetafile, "mf_Graphics");
387
388     ret = DeleteMetaFile(hMetafile);
389     ok( ret, "DeleteMetaFile(%p) error %ld\n",
390         hMetafile, GetLastError());
391 }
392
393 static void test_mf_PatternBrush(void)
394 {
395     HDC hdcMetafile;
396     HMETAFILE hMetafile;
397     LOGBRUSH *orig_lb;
398     HBRUSH hBrush;
399     BOOL ret;
400
401     orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
402
403     orig_lb->lbStyle = BS_PATTERN;
404     orig_lb->lbColor = RGB(0, 0, 0);
405     orig_lb->lbHatch = (INT) CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
406     ok((HBITMAP *)orig_lb->lbHatch != NULL, "CreateBitmap error %ld.\n", GetLastError());
407
408     hBrush = CreateBrushIndirect (orig_lb);
409     ok(hBrush != 0, "CreateBrushIndirect error %ld\n", GetLastError());
410
411     hdcMetafile = CreateMetaFileA(NULL);
412     ok(hdcMetafile != 0, "CreateMetaFileA error %ld\n", GetLastError());
413     trace("hdcMetafile %p\n", hdcMetafile);
414
415     hBrush = SelectObject(hdcMetafile, hBrush);
416     ok(hBrush != 0, "SelectObject error %ld.\n", GetLastError());
417
418     hMetafile = CloseMetaFile(hdcMetafile);
419     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
420     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
421
422     if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
423         "mf_Pattern_Brush") != 0)
424             dump_mf_bits (hMetafile, "mf_Pattern_Brush");
425
426     ret = DeleteMetaFile(hMetafile);
427     ok( ret, "DeleteMetaFile error %ld\n", GetLastError());
428     ret = DeleteObject(hBrush);
429     ok( ret, "DeleteObject(HBRUSH) error %ld\n", GetLastError());
430     ret = DeleteObject((HBITMAP *)orig_lb->lbHatch);
431     ok( ret, "DeleteObject(HBITMAP) error %ld\n",
432         GetLastError());
433     HeapFree (GetProcessHeap(), 0, orig_lb);
434 }
435
436 START_TEST(metafile)
437 {
438     /* For enhanced metafiles (enhmfdrv) */
439     test_ExtTextOut();
440
441     /* For win-format metafiles (mfdrv) */
442     test_mf_Blank();
443     test_mf_Graphics();
444     test_mf_PatternBrush();
445 }