Add a test for SetMetaFileBitsEx, make it pass under Wine.
[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 #include <math.h>
24
25 #include "wine/test.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30
31 static LOGFONTA orig_lf;
32 static BOOL emr_processed = FALSE;
33
34 /* Arbitrarily chosen values for the second co-ordinate of a metafile line */
35 #define LINE_X 55.0f
36 #define LINE_Y 15.0f
37
38 static int CALLBACK emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
39     const ENHMETARECORD *emr, int n_objs, LPARAM param)
40 {
41     static int n_record;
42     DWORD i;
43     const INT *dx;
44     INT *orig_dx = (INT *)param;
45     LOGFONTA device_lf;
46     INT ret;
47
48     trace("hdc %p, emr->iType %ld, emr->nSize %ld, param %p\n",
49            hdc, emr->iType, emr->nSize, (void *)param);
50
51     if(!hdc) return 1;
52
53     PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
54
55     switch (emr->iType)
56     {
57     case EMR_HEADER:
58         ok(GetTextAlign(hdc) == 0, "text align %08x\n", GetTextAlign(hdc));
59         ok(GetBkColor(hdc) == RGB(0xff, 0xff, 0xff), "bk color %08lx\n", GetBkColor(hdc));
60         ok(GetTextColor(hdc) == RGB(0x0, 0x0, 0x0), "text color %08lx\n", GetTextColor(hdc));
61         ok(GetROP2(hdc) == R2_COPYPEN, "rop %d\n", GetROP2(hdc));
62         ok(GetArcDirection(hdc) == AD_COUNTERCLOCKWISE, "arc dir %d\n", GetArcDirection(hdc));
63         ok(GetPolyFillMode(hdc) == ALTERNATE, "poly fill %d\n", GetPolyFillMode(hdc));
64         ok(GetStretchBltMode(hdc) == BLACKONWHITE, "stretchblt mode %d\n", GetStretchBltMode(hdc));
65
66         /* GetBkMode, GetRelAbs do not get reset to the default value */
67         ok(GetBkMode(hdc) == OPAQUE, "bk mode %d\n", GetBkMode(hdc));
68         ok(GetRelAbs(hdc, 0) == RELATIVE, "relabs %d\n", GetRelAbs(hdc, 0));
69
70         n_record = 0;
71         break;
72
73     case EMR_EXTTEXTOUTA:
74     {
75         const EMREXTTEXTOUTA *emr_ExtTextOutA = (const EMREXTTEXTOUTA *)emr;
76         dx = (const INT *)((const char *)emr + emr_ExtTextOutA->emrtext.offDx);
77
78         ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
79         ok( ret == sizeof(device_lf), "GetObjectA error %ld\n", GetLastError());
80
81         /* compare up to lfOutPrecision, other values are not interesting,
82          * and in fact sometimes arbitrary adapted by Win9x.
83          */
84         ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
85         ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
86
87         for(i = 0; i < emr_ExtTextOutA->emrtext.nChars; i++)
88         {
89             ok(orig_dx[i] == dx[i], "pass %d: dx[%ld] (%d) didn't match %d\n",
90                                      n_record, i, dx[i], orig_dx[i]);
91         }
92         n_record++;
93         emr_processed = TRUE;
94         break;
95     }
96
97     case EMR_EXTTEXTOUTW:
98     {
99         const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr;
100         dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx);
101
102         ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
103         ok( ret == sizeof(device_lf), "GetObjectA error %ld\n", GetLastError());
104
105         /* compare up to lfOutPrecision, other values are not interesting,
106          * and in fact sometimes arbitrary adapted by Win9x.
107          */
108         ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
109         ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
110
111         for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
112         {
113             ok(orig_dx[i] == dx[i], "pass %d: dx[%ld] (%d) didn't match %d\n",
114                                      n_record, i, dx[i], orig_dx[i]);
115         }
116         n_record++;
117         emr_processed = TRUE;
118         break;
119     }
120
121     default:
122         break;
123     }
124
125     return 1;
126 }
127
128 static void test_ExtTextOut(void)
129 {
130     HWND hwnd;
131     HDC hdcDisplay, hdcMetafile;
132     HENHMETAFILE hMetafile;
133     HFONT hFont;
134     static const char text[] = "Simple text to test ExtTextOut on metafiles";
135     INT i, len, dx[256];
136     static const RECT rc = { 0, 0, 100, 100 };
137     BOOL ret;
138
139     assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
140
141     /* Win9x doesn't play EMFs on invisible windows */
142     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
143                            0, 0, 200, 200, 0, 0, 0, NULL);
144     ok(hwnd != 0, "CreateWindowExA error %ld\n", GetLastError());
145
146     hdcDisplay = GetDC(hwnd);
147     ok(hdcDisplay != 0, "GetDC error %ld\n", GetLastError());
148
149     trace("hdcDisplay %p\n", hdcDisplay);
150
151     SetMapMode(hdcDisplay, MM_TEXT);
152
153     memset(&orig_lf, 0, sizeof(orig_lf));
154
155     orig_lf.lfCharSet = ANSI_CHARSET;
156     orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
157     orig_lf.lfWeight = FW_DONTCARE;
158     orig_lf.lfHeight = 7;
159     orig_lf.lfQuality = DEFAULT_QUALITY;
160     lstrcpyA(orig_lf.lfFaceName, "Arial");
161     hFont = CreateFontIndirectA(&orig_lf);
162     ok(hFont != 0, "CreateFontIndirectA error %ld\n", GetLastError());
163
164     hFont = SelectObject(hdcDisplay, hFont);
165
166     len = lstrlenA(text);
167     for (i = 0; i < len; i++)
168     {
169         ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
170         ok( ret, "GetCharWidthA error %ld\n", GetLastError());
171     }
172     hFont = SelectObject(hdcDisplay, hFont);
173
174     hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
175     ok(hdcMetafile != 0, "CreateEnhMetaFileA error %ld\n", GetLastError());
176
177     trace("hdcMetafile %p\n", hdcMetafile);
178
179     ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
180        "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
181
182     hFont = SelectObject(hdcMetafile, hFont);
183
184     /* 1. pass NULL lpDx */
185     ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
186     ok( ret, "ExtTextOutA error %ld\n", GetLastError());
187
188     /* 2. pass custom lpDx */
189     ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
190     ok( ret, "ExtTextOutA error %ld\n", GetLastError());
191
192     hFont = SelectObject(hdcMetafile, hFont);
193     ret = DeleteObject(hFont);
194     ok( ret, "DeleteObject error %ld\n", GetLastError());
195
196     hMetafile = CloseEnhMetaFile(hdcMetafile);
197     ok(hMetafile != 0, "CloseEnhMetaFile error %ld\n", GetLastError());
198
199     ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
200
201     ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
202     ok( ret, "PlayEnhMetaFile error %ld\n", GetLastError());
203
204     SetTextAlign(hdcDisplay, TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING );
205     SetBkColor(hdcDisplay, RGB(0xff, 0, 0));
206     SetTextColor(hdcDisplay, RGB(0, 0xff, 0));
207     SetROP2(hdcDisplay, R2_NOT);
208     SetArcDirection(hdcDisplay, AD_CLOCKWISE);
209     SetPolyFillMode(hdcDisplay, WINDING);
210     SetStretchBltMode(hdcDisplay, HALFTONE);
211
212     SetRelAbs(hdcDisplay, RELATIVE);
213     SetBkMode(hdcDisplay, OPAQUE);
214
215     ret = EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, &rc);
216     ok( ret, "EnumEnhMetaFile error %ld\n", GetLastError());
217
218     ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
219         "text align %08x\n", GetTextAlign(hdcDisplay));
220     ok( GetBkColor(hdcDisplay) == RGB(0xff, 0, 0), "bk color %08lx\n", GetBkColor(hdcDisplay));
221     ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08lx\n", GetTextColor(hdcDisplay));
222     ok( GetROP2(hdcDisplay) == R2_NOT, "rop2 %d\n", GetROP2(hdcDisplay));
223     ok( GetArcDirection(hdcDisplay) == AD_CLOCKWISE, "arc dir  %d\n", GetArcDirection(hdcDisplay));
224     ok( GetPolyFillMode(hdcDisplay) == WINDING, "poly fill %d\n", GetPolyFillMode(hdcDisplay));
225     ok( GetStretchBltMode(hdcDisplay) == HALFTONE, "stretchblt mode %d\n", GetStretchBltMode(hdcDisplay));
226
227     ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
228
229     ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, emf_enum_proc, dx, NULL),
230        "A valid hdc has to require a valid rc\n");
231
232     ok(EnumEnhMetaFile(NULL, hMetafile, emf_enum_proc, dx, NULL),
233        "A null hdc does not require a valid rc\n");
234
235     ret = DeleteEnhMetaFile(hMetafile);
236     ok( ret, "DeleteEnhMetaFile error %ld\n", GetLastError());
237     ret = ReleaseDC(hwnd, hdcDisplay);
238     ok( ret, "ReleaseDC error %ld\n", GetLastError());
239 }
240
241 /* Win-format metafile (mfdrv) tests */
242 /* These tests compare the generated metafiles byte-by-byte */
243 /* with the nominal results. */
244
245 /* Maximum size of sample metafiles in bytes. */
246 #define MF_BUFSIZE 256
247
248 /* 8x8 bitmap data for a pattern brush */
249 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
250     0x01, 0x00, 0x02, 0x00,
251     0x03, 0x00, 0x04, 0x00,
252     0x05, 0x00, 0x06, 0x00,
253     0x07, 0x00, 0x08, 0x00
254 };
255
256 /* Sample metafiles to be compared to the outputs of the
257  * test functions.
258  */
259
260 static const unsigned char MF_BLANK_BITS[] = {
261     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
262     0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
263     0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
264 };
265
266 static const unsigned char MF_GRAPHICS_BITS[] = {
267     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
268     0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
269     0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
270     0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
271     0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
272     0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
273     0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
274     0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
275     0x00, 0x00, 0x00, 0x00
276 };
277
278 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
279     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
280     0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
281     0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
282     0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
283     0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
284     0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
285     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288     0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
289     0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
290     0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
291     0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
292     0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
293     0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
294     0x00, 0x00
295 };
296
297 /* For debugging or dumping the raw metafiles produced by
298  * new test functions.
299  */
300
301 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
302 {
303     char buf[MF_BUFSIZE];
304     UINT mfsize, i;
305
306     mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
307     ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
308
309     printf ("MetaFile %s has bits:\n{\n    ", desc);
310     for (i=0; i<mfsize; i++)
311     {
312         printf ("0x%.2hhx", buf[i]);
313         if (i == mfsize-1)
314             printf ("\n");
315         else if (i % 8 == 7)
316             printf (",\n    ");
317         else
318             printf (", ");
319     }
320     printf ("};\n");
321 }
322
323 /* Compare the metafile produced by a test function with the
324  * expected raw metafile data in "bits".
325  * Return value is 0 for a perfect match,
326  * -1 if lengths aren't equal,
327  * otherwise returns the number of non-matching bytes.
328  */
329
330 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
331     const char *desc)
332 {
333     unsigned char buf[MF_BUFSIZE];
334     UINT mfsize, i;
335     int diff;
336
337     mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
338     ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
339     if (mfsize < MF_BUFSIZE)
340         ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
341             desc, mfsize, bsize);
342     else
343         ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
344             desc, mfsize, bsize);
345     if (mfsize != bsize)
346         return -1;
347
348     diff = 0;
349     for (i=0; i<bsize; i++)
350     {
351        if (buf[i] !=  bits[i])
352            diff++;
353     }
354     ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
355         desc, mfsize, bsize, diff);
356
357     return diff; 
358 }
359
360 static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
361 {
362     unsigned char buf[MF_BUFSIZE];
363     DWORD mfsize, rd_size, i;
364     int diff;
365     HANDLE hfile;
366     BOOL ret;
367
368     hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
369     assert(hfile != INVALID_HANDLE_VALUE);
370
371     mfsize = GetFileSize(hfile, NULL);
372     assert(mfsize <= MF_BUFSIZE);
373
374     ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
375     ok( ret && rd_size == mfsize, "ReadFile: error %ld\n", GetLastError());
376
377     CloseHandle(hfile);
378
379     ok(mfsize == bsize, "%s: mfsize=%ld, bsize=%d.\n", desc, mfsize, bsize);
380
381     if (mfsize != bsize)
382         return -1;
383
384     diff = 0;
385     for (i=0; i<bsize; i++)
386     {
387         if (buf[i] != bits[i])
388             diff++;
389     }
390     ok(diff == 0, "%s: mfsize=%ld, bsize=%d, diff=%d\n",
391         desc, mfsize, bsize, diff);
392
393     return diff; 
394 }
395
396 /* Test a blank metafile.  May be used as a template for new tests. */
397
398 static void test_mf_Blank(void)
399 {
400     HDC hdcMetafile;
401     HMETAFILE hMetafile;
402     INT caps;
403     BOOL ret;
404     INT type;
405
406     hdcMetafile = CreateMetaFileA(NULL);
407     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
408     trace("hdcMetafile %p\n", hdcMetafile);
409
410 /* Tests on metafile initialization */
411     caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
412     ok (caps == DT_METAFILE,
413         "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
414
415     hMetafile = CloseMetaFile(hdcMetafile);
416     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
417     type = GetObjectType(hMetafile);
418     ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
419     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
420
421     if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
422         "mf_blank") != 0)
423             dump_mf_bits (hMetafile, "mf_Blank");
424
425     ret = DeleteMetaFile(hMetafile);
426     ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
427 }
428
429 static void test_CopyMetaFile(void)
430 {
431     HDC hdcMetafile;
432     HMETAFILE hMetafile, hmf_copy;
433     BOOL ret;
434     char temp_path[MAX_PATH];
435     char mf_name[MAX_PATH];
436     INT type;
437
438     hdcMetafile = CreateMetaFileA(NULL);
439     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
440     trace("hdcMetafile %p\n", hdcMetafile);
441
442     hMetafile = CloseMetaFile(hdcMetafile);
443     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
444     type = GetObjectType(hMetafile);
445     ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
446
447     if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
448         "mf_blank") != 0)
449             dump_mf_bits (hMetafile, "mf_Blank");
450
451     GetTempPathA(MAX_PATH, temp_path);
452     GetTempFileNameA(temp_path, "wmf", 0, mf_name);
453
454     hmf_copy = CopyMetaFileA(hMetafile, mf_name);
455     ok(hmf_copy != 0, "CopyMetaFile error %ld\n", GetLastError());
456
457     type = GetObjectType(hmf_copy);
458     ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
459
460     ret = DeleteMetaFile(hMetafile);
461     ok( ret, "DeleteMetaFile(%p) error %ld\n", hMetafile, GetLastError());
462
463     if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
464         dump_mf_bits(hmf_copy, "mf_Blank");
465
466     ret = DeleteMetaFile(hmf_copy);
467     ok( ret, "DeleteMetaFile(%p) error %ld\n", hmf_copy, GetLastError());
468
469     DeleteFileA(mf_name);
470 }
471
472 static void test_SetMetaFileBits(void)
473 {
474     HMETAFILE hmf;
475     INT type;
476     BOOL ret;
477     BYTE buf[256];
478     METAHEADER *mh;
479
480     hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
481     ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
482     type = GetObjectType(hmf);
483     ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
484
485     if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
486         dump_mf_bits(hmf, "mf_Graphics");
487
488     ret = DeleteMetaFile(hmf);
489     ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
490
491     /* NULL data crashes XP SP1 */
492     /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
493
494     /* Now with not zero size */
495     SetLastError(0xdeadbeef);
496     hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
497     ok(!hmf, "SetMetaFileBitsEx should fail\n");
498     ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %ld\n", GetLastError());
499
500     /* Now with not even size */
501     SetLastError(0xdeadbeef);
502     hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
503     ok(!hmf, "SetMetaFileBitsEx should fail\n");
504     ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %ld\n", GetLastError());
505
506     /* Now with zeroed out or faked some header fields */
507     assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
508     memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
509     mh = (METAHEADER *)buf;
510     /* corruption of any of the below fields leads to a failure */
511     mh->mtType = 0;
512     mh->mtVersion = 0;
513     mh->mtHeaderSize = 0;
514     SetLastError(0xdeadbeef);
515     hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
516     ok(!hmf, "SetMetaFileBitsEx should fail\n");
517     ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %ld\n", GetLastError());
518
519     /* Now with corrupted mtSize field */
520     memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
521     mh = (METAHEADER *)buf;
522     /* corruption of mtSize doesn't lead to a failure */
523     mh->mtSize *= 2;
524     hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
525     ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
526
527     if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
528         dump_mf_bits(hmf, "mf_Graphics");
529
530     ret = DeleteMetaFile(hmf);
531     ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
532
533     /* Now with zeroed out mtSize field */
534     memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
535     mh = (METAHEADER *)buf;
536     /* zeroing mtSize doesn't lead to a failure */
537     mh->mtSize = 0;
538     hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
539     ok(hmf != 0, "SetMetaFileBitsEx error %ld\n", GetLastError());
540
541     if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
542         dump_mf_bits(hmf, "mf_Graphics");
543
544     ret = DeleteMetaFile(hmf);
545     ok(ret, "DeleteMetaFile(%p) error %ld\n", hmf, GetLastError());
546 }
547
548 /* Simple APIs from mfdrv/graphics.c
549  */
550
551 static void test_mf_Graphics(void)
552 {
553     HDC hdcMetafile;
554     HMETAFILE hMetafile;
555     POINT oldpoint;
556     BOOL ret;
557
558     hdcMetafile = CreateMetaFileA(NULL);
559     ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %ld\n", GetLastError());
560     trace("hdcMetafile %p\n", hdcMetafile);
561
562     ret = MoveToEx(hdcMetafile, 1, 1, NULL);
563     ok( ret, "MoveToEx error %ld.\n", GetLastError());
564     ret = LineTo(hdcMetafile, 2, 2);
565     ok( ret, "LineTo error %ld.\n", GetLastError());
566     ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
567     ok( ret, "MoveToEx error %ld.\n", GetLastError());
568
569 /* oldpoint gets garbage under Win XP, so the following test would
570  * work under Wine but fails under Windows:
571  *
572  *   ok((oldpoint.x == 2) && (oldpoint.y == 2),
573  *       "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
574  *       oldpoint.x, oldpoint.y);
575  */
576
577     ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
578     ok( ret, "Ellipse error %ld.\n", GetLastError());
579
580     hMetafile = CloseMetaFile(hdcMetafile);
581     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
582     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
583
584     if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
585         "mf_Graphics") != 0)
586             dump_mf_bits (hMetafile, "mf_Graphics");
587
588     ret = DeleteMetaFile(hMetafile);
589     ok( ret, "DeleteMetaFile(%p) error %ld\n",
590         hMetafile, GetLastError());
591 }
592
593 static void test_mf_PatternBrush(void)
594 {
595     HDC hdcMetafile;
596     HMETAFILE hMetafile;
597     LOGBRUSH *orig_lb;
598     HBRUSH hBrush;
599     BOOL ret;
600
601     orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
602
603     orig_lb->lbStyle = BS_PATTERN;
604     orig_lb->lbColor = RGB(0, 0, 0);
605     orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
606     ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %ld.\n", GetLastError());
607
608     hBrush = CreateBrushIndirect (orig_lb);
609     ok(hBrush != 0, "CreateBrushIndirect error %ld\n", GetLastError());
610
611     hdcMetafile = CreateMetaFileA(NULL);
612     ok(hdcMetafile != 0, "CreateMetaFileA error %ld\n", GetLastError());
613     trace("hdcMetafile %p\n", hdcMetafile);
614
615     hBrush = SelectObject(hdcMetafile, hBrush);
616     ok(hBrush != 0, "SelectObject error %ld.\n", GetLastError());
617
618     hMetafile = CloseMetaFile(hdcMetafile);
619     ok(hMetafile != 0, "CloseMetaFile error %ld\n", GetLastError());
620     ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
621
622     if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
623         "mf_Pattern_Brush") != 0)
624             dump_mf_bits (hMetafile, "mf_Pattern_Brush");
625
626     ret = DeleteMetaFile(hMetafile);
627     ok( ret, "DeleteMetaFile error %ld\n", GetLastError());
628     ret = DeleteObject(hBrush);
629     ok( ret, "DeleteObject(HBRUSH) error %ld\n", GetLastError());
630     ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
631     ok( ret, "DeleteObject(HBITMAP) error %ld\n",
632         GetLastError());
633     HeapFree (GetProcessHeap(), 0, orig_lb);
634 }
635
636 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
637 {
638     LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
639     POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
640     /* When using MM_TEXT Win9x does not update the mapping mode 
641      * until a record is played which actually outputs something */
642     PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
643     LPtoDP(hdc, mapping, 2);
644     trace("Meta record: iType = %ld, (%ld,%ld)-(%ld,%ld)\n", lpEMFR->iType, mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
645     if (lpEMFR->iType == EMR_LINETO)
646     {
647         INT x0, y0, x1, y1;
648         if (!lpMFP || lpMFP->mm == MM_TEXT)
649         {
650             x0 = 0;
651             y0 = 0;
652             x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
653             y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
654         }
655         else
656         {
657             ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%ld\n", lpMFP->mm);
658             
659             x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
660             y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
661             x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
662             y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
663         }
664         ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
665             "(%ld,%ld)->(%ld,%ld), expected (%d,%d)->(%d,%d)\n",
666             mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
667             x0, y0, x1, y1);
668     }
669     return TRUE;
670 }
671
672 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
673 {
674     HDC hdcMf;
675     HMETAFILE hmf;
676     BOOL ret;
677     UINT size;
678     LPBYTE pBits;
679
680     hdcMf = CreateMetaFile(NULL);
681     ok(hdcMf != NULL, "CreateMetaFile failed with error %ld\n", GetLastError());
682     ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
683     ok(ret, "LineTo failed with error %ld\n", GetLastError());
684     hmf = CloseMetaFile(hdcMf);
685     ok(hmf != NULL, "CloseMetaFile failed with error %ld\n", GetLastError());
686     size = GetMetaFileBitsEx(hmf, 0, NULL);
687     ok(size, "GetMetaFileBitsEx failed with error %ld\n", GetLastError());
688     pBits = HeapAlloc(GetProcessHeap(), 0, size);
689     GetMetaFileBitsEx(hmf, size, pBits);
690     DeleteMetaFile(hmf);
691     return SetWinMetaFileBits(size, pBits, NULL, mfp);
692 }
693
694 static void test_mf_conversions(void)
695 {
696     trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
697     {
698         HDC hdcOffscreen = CreateCompatibleDC(NULL);
699         HENHMETAFILE hemf;
700         METAFILEPICT mfp;
701         RECT rect = { 0, 0, 100, 100 };
702         mfp.mm = MM_ANISOTROPIC;
703         mfp.xExt = 100;
704         mfp.yExt = 100;
705         mfp.hMF = NULL;
706         hemf = create_converted_emf(&mfp);
707         EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
708         DeleteEnhMetaFile(hemf);
709         DeleteDC(hdcOffscreen);
710     }
711
712     trace("Testing MF->EMF conversion (MM_TEXT)\n");
713     {
714         HDC hdcOffscreen = CreateCompatibleDC(NULL);
715         HENHMETAFILE hemf;
716         METAFILEPICT mfp;
717         RECT rect = { 0, 0, 100, 100 };
718         mfp.mm = MM_TEXT;
719         mfp.xExt = 0;
720         mfp.yExt = 0;
721         mfp.hMF = NULL;
722         hemf = create_converted_emf(&mfp);
723         EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
724         DeleteEnhMetaFile(hemf);
725         DeleteDC(hdcOffscreen);
726     }
727
728     trace("Testing MF->EMF conversion (NULL mfp)\n");
729     {
730         HDC hdcOffscreen = CreateCompatibleDC(NULL);
731         HENHMETAFILE hemf;
732         RECT rect = { 0, 0, 100, 100 };
733         hemf = create_converted_emf(NULL);
734         EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
735         DeleteEnhMetaFile(hemf);
736         DeleteDC(hdcOffscreen);
737     }
738 }
739
740 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
741 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
742 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
743
744 static void test_gdiis(void)
745 {
746     RECT rect = {0,0,100,100};
747     HDC hdc, hemfDC, hmfDC;
748     HENHMETAFILE hemf;
749     HMODULE hgdi32;
750
751     /* resolve all the functions */
752     hgdi32 = GetModuleHandle("gdi32");
753     pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
754     pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
755     pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
756
757     /* they should all exist or none should exist */
758     if(!pGdiIsMetaPrintDC)
759         return;
760
761     /* try with nothing */
762     ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
763     ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
764     ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
765
766     /* try with a metafile */
767     hmfDC = CreateMetaFile(NULL);
768     ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
769     ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
770     ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
771     DeleteObject(CloseMetaFile(hmfDC));
772
773     /* try with an enhanced metafile */
774     hdc = GetDC(NULL);
775     hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
776     ok(hemfDC != NULL, "failed to create emf\n");
777
778     ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
779     ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
780     ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
781
782     hemf = CloseEnhMetaFile(hemfDC);
783     ok(hemf != NULL, "failed to close EMF\n");
784     DeleteObject(hemf);
785     ReleaseDC(NULL,hdc);
786 }
787
788 START_TEST(metafile)
789 {
790     /* For enhanced metafiles (enhmfdrv) */
791     test_ExtTextOut();
792
793     /* For win-format metafiles (mfdrv) */
794     test_mf_Blank();
795     test_mf_Graphics();
796     test_mf_PatternBrush();
797     test_CopyMetaFile();
798     test_SetMetaFileBits();
799
800     /* For metafile conversions */
801     test_mf_conversions();
802
803     test_gdiis();
804 }