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