Sync to trunk r38500
[reactos.git] / rostests / winetests / gdi32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 eto_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 %d, emr->nSize %d, 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 %08x\n", GetBkColor(hdc));
81 ok(GetTextColor(hdc) == RGB(0x0, 0x0, 0x0), "text color %08x\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 %d\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[%d] (%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 %d\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[%d] (%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 %d\n", GetLastError());
167
168 hdcDisplay = GetDC(hwnd);
169 ok(hdcDisplay != 0, "GetDC error %d\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 %d\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 %d\n", GetLastError());
193 }
194 hFont = SelectObject(hdcDisplay, hFont);
195
196 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
197 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\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 %d\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 %d\n", GetLastError());
213
214 hFont = SelectObject(hdcMetafile, hFont);
215 ret = DeleteObject(hFont);
216 ok( ret, "DeleteObject error %d\n", GetLastError());
217
218 hMetafile = CloseEnhMetaFile(hdcMetafile);
219 ok(hMetafile != 0, "CloseEnhMetaFile error %d\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 %d\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, eto_emf_enum_proc, dx, &rc);
238 ok( ret, "EnumEnhMetaFile error %d\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 %08x\n", GetBkColor(hdcDisplay));
243 ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08x\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, eto_emf_enum_proc, dx, NULL),
252 "A valid hdc has to require a valid rc\n");
253
254 ok(EnumEnhMetaFile(NULL, hMetafile, eto_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 %d\n", GetLastError());
259 ret = ReleaseDC(hwnd, hdcDisplay);
260 ok( ret, "ReleaseDC error %d\n", GetLastError());
261 DestroyWindow(hwnd);
262 }
263
264 static void check_dc_state(HDC hdc, int restore_no,
265 int wnd_org_x, int wnd_org_y, int wnd_ext_x, int wnd_ext_y,
266 int vp_org_x, int vp_org_y, int vp_ext_x, int vp_ext_y)
267 {
268 BOOL ret;
269 XFORM xform;
270 POINT vp_org, win_org;
271 SIZE vp_size, win_size;
272 FLOAT xscale, yscale, edx, edy;
273
274 SetLastError(0xdeadbeef);
275 ret = GetWorldTransform(hdc, &xform);
276 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) goto win9x_here;
277 ok(ret, "GetWorldTransform error %u\n", GetLastError());
278
279 trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
280
281 ok(xform.eM12 == 0.0, "%d: expected eM12 0.0, got %f\n", restore_no, xform.eM12);
282 ok(xform.eM21 == 0.0, "%d: expected eM21 0.0, got %f\n", restore_no, xform.eM21);
283
284 xscale = (FLOAT)vp_ext_x / (FLOAT)wnd_ext_x;
285 trace("x scale %f\n", xscale);
286 ok(fabs(xscale - xform.eM11) < 0.01, "%d: vp_ext_x %d, wnd_ext_cx %d, eM11 %f\n",
287 restore_no, vp_ext_x, wnd_ext_x, xform.eM11);
288
289 yscale = (FLOAT)vp_ext_y / (FLOAT)wnd_ext_y;
290 trace("y scale %f\n", yscale);
291 ok(fabs(yscale - xform.eM22) < 0.01, "%d: vp_ext_y %d, wnd_ext_y %d, eM22 %f\n",
292 restore_no, vp_ext_y, wnd_ext_y, xform.eM22);
293
294 edx = (FLOAT)vp_org_x - xform.eM11 * (FLOAT)wnd_org_x;
295 ok(fabs(edx - xform.eDx) < 0.01, "%d: edx %f != eDx %f\n", restore_no, edx, xform.eDx);
296 edy = (FLOAT)vp_org_y - xform.eM22 * (FLOAT)wnd_org_y;
297 ok(fabs(edy - xform.eDy) < 0.01, "%d: edy %f != eDy %f\n", restore_no, edy, xform.eDy);
298
299 return;
300
301 win9x_here:
302
303 GetWindowOrgEx(hdc, &win_org);
304 GetViewportOrgEx(hdc, &vp_org);
305 GetWindowExtEx(hdc, &win_size);
306 GetViewportExtEx(hdc, &vp_size);
307
308 ok(wnd_org_x == win_org.x, "%d: wnd_org_x: %d != %d\n", restore_no, wnd_org_x, win_org.x);
309 ok(wnd_org_y == win_org.y, "%d: wnd_org_y: %d != %d\n", restore_no, wnd_org_y, win_org.y);
310
311 ok(vp_org_x == vp_org.x, "%d: vport_org_x: %d != %d\n", restore_no, vp_org_x, vp_org.x);
312 ok(vp_org_y == vp_org.y, "%d: vport_org_y: %d != %d\n", restore_no, vp_org_y, vp_org.y);
313
314 ok(wnd_ext_x == win_size.cx, "%d: wnd_ext_x: %d != %d\n", restore_no, wnd_ext_x, win_size.cx);
315 ok(wnd_ext_y == win_size.cy, "%d: wnd_ext_y: %d != %d\n", restore_no, wnd_ext_y, win_size.cy);
316
317 ok(vp_ext_x == vp_size.cx, "%d: vport_ext_x: %d != %d\n", restore_no, vp_ext_x, vp_size.cx);
318 ok(vp_ext_y == vp_size.cy, "%d: vport_ext_y: %d != %d\n", restore_no, vp_ext_y, vp_size.cy);
319 }
320
321 static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
322 const ENHMETARECORD *emr, int n_objs, LPARAM param)
323 {
324 BOOL ret;
325 XFORM xform;
326 POINT pt;
327 SIZE size;
328 static int save_state;
329 static int restore_no;
330
331 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
332 hdc, emr->iType, emr->nSize, (void *)param);
333
334 trace("BEFORE:\n");
335 SetLastError(0xdeadbeef);
336 ret = GetWorldTransform(hdc, &xform);
337 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
338 {
339 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
340 trace("window org (%d,%d)\n", pt.x, pt.y);
341 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
342 trace("vport org (%d,%d)\n", pt.x, pt.y);
343 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
344 trace("window ext (%d,%d)\n", size.cx, size.cy);
345 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
346 trace("vport ext (%d,%d)\n", size.cx, size.cy);
347 }
348 else
349 {
350 ok(ret, "GetWorldTransform error %u\n", GetLastError());
351 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
352 }
353
354 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
355
356 switch (emr->iType)
357 {
358 case EMR_HEADER:
359 {
360 static RECT exp_bounds = { 0, 0, 150, 150 };
361 RECT bounds;
362 const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
363
364 trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
365 emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
366 emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
367 trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
368 emf->szlDevice.cx, emf->szlDevice.cy);
369
370 SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
371 ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
372
373 save_state = 0;
374 restore_no = 0;
375 check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
376 break;
377 }
378
379 case EMR_LINETO:
380 {
381 const EMRLINETO *line = (const EMRLINETO *)emr;
382 trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
383 break;
384 }
385 case EMR_SETWINDOWORGEX:
386 {
387 const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
388 trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
389 break;
390 }
391 case EMR_SETWINDOWEXTEX:
392 {
393 const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
394 trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
395 break;
396 }
397 case EMR_SETVIEWPORTORGEX:
398 {
399 const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
400 trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
401 break;
402 }
403 case EMR_SETVIEWPORTEXTEX:
404 {
405 const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
406 trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
407 break;
408 }
409 case EMR_SAVEDC:
410 save_state++;
411 trace("EMR_SAVEDC\n");
412 break;
413
414 case EMR_RESTOREDC:
415 {
416 const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
417 trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
418
419 switch(++restore_no)
420 {
421 case 1:
422 ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
423 check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
424 break;
425 case 2:
426 ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
427 check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
428 break;
429 case 3:
430 ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
431 check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
432 break;
433 }
434 ok(restore_no <= 3, "restore_no %d\n", restore_no);
435 save_state += restoredc->iRelative;
436 break;
437 }
438 case EMR_EOF:
439 ok(save_state == 0, "EOF save_state %d\n", save_state);
440 break;
441 }
442
443 trace("AFTER:\n");
444 SetLastError(0xdeadbeef);
445 ret = GetWorldTransform(hdc, &xform);
446 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
447 {
448 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
449 trace("window org (%d,%d)\n", pt.x, pt.y);
450 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
451 trace("vport org (%d,%d)\n", pt.x, pt.y);
452 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
453 trace("window ext (%d,%d)\n", size.cx, size.cy);
454 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
455 trace("vport ext (%d,%d)\n", size.cx, size.cy);
456 }
457 else
458 {
459 ok(ret, "GetWorldTransform error %u\n", GetLastError());
460 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
461 }
462
463 return 1;
464 }
465
466 static void test_SaveDC(void)
467 {
468 HDC hdcMetafile, hdcDisplay;
469 HENHMETAFILE hMetafile;
470 HWND hwnd;
471 int ret;
472 static const RECT rc = { 0, 0, 150, 150 };
473
474 /* Win9x doesn't play EMFs on invisible windows */
475 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
476 0, 0, 200, 200, 0, 0, 0, NULL);
477 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
478
479 hdcDisplay = GetDC(hwnd);
480 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
481
482 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
483 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
484
485 SetMapMode(hdcMetafile, MM_ANISOTROPIC);
486
487 /* Need to write something to the emf, otherwise Windows won't play it back */
488 LineTo(hdcMetafile, 150, 150);
489
490 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
491 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
492 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
493 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
494
495 /* Force Win9x to update DC state */
496 SetPixelV(hdcMetafile, 50, 50, 0);
497
498 ret = SaveDC(hdcMetafile);
499 ok(ret == 1, "ret = %d\n", ret);
500
501 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
502 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
503 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
504 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
505
506 /* Force Win9x to update DC state */
507 SetPixelV(hdcMetafile, 50, 50, 0);
508
509 ret = SaveDC(hdcMetafile);
510 ok(ret == 2, "ret = %d\n", ret);
511
512 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
513 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
514 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
515 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
516
517 /* Force Win9x to update DC state */
518 SetPixelV(hdcMetafile, 50, 50, 0);
519
520 ret = SaveDC(hdcMetafile);
521 ok(ret == 3, "ret = %d\n", ret);
522
523 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
524 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
525 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
526 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
527
528 /* Force Win9x to update DC state */
529 SetPixelV(hdcMetafile, 50, 50, 0);
530
531 ret = RestoreDC(hdcMetafile, -1);
532 ok(ret, "ret = %d\n", ret);
533
534 ret = SaveDC(hdcMetafile);
535 ok(ret == 3, "ret = %d\n", ret);
536
537 ret = RestoreDC(hdcMetafile, 1);
538 ok(ret, "ret = %d\n", ret);
539
540 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
541 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
542 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
543 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
544
545 /* Force Win9x to update DC state */
546 SetPixelV(hdcMetafile, 50, 50, 0);
547
548 ret = SaveDC(hdcMetafile);
549 ok(ret == 1, "ret = %d\n", ret);
550
551 ret = SaveDC(hdcMetafile);
552 ok(ret == 2, "ret = %d\n", ret);
553
554 hMetafile = CloseEnhMetaFile(hdcMetafile);
555 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
556
557 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
558 ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
559
560 ret = DeleteEnhMetaFile(hMetafile);
561 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
562 ret = ReleaseDC(hwnd, hdcDisplay);
563 ok( ret, "ReleaseDC error %d\n", GetLastError());
564 DestroyWindow(hwnd);
565 }
566
567 /* Win-format metafile (mfdrv) tests */
568 /* These tests compare the generated metafiles byte-by-byte */
569 /* with the nominal results. */
570
571 /* Maximum size of sample metafiles in bytes. */
572 #define MF_BUFSIZE 512
573
574 /* 8x8 bitmap data for a pattern brush */
575 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
576 0x01, 0x00, 0x02, 0x00,
577 0x03, 0x00, 0x04, 0x00,
578 0x05, 0x00, 0x06, 0x00,
579 0x07, 0x00, 0x08, 0x00
580 };
581
582 /* Sample metafiles to be compared to the outputs of the
583 * test functions.
584 */
585
586 static const unsigned char MF_BLANK_BITS[] = {
587 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
588 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
590 };
591
592 static const unsigned char MF_GRAPHICS_BITS[] = {
593 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
595 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
596 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
597 0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
598 0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
599 0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
600 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
601 0x00, 0x00, 0x00, 0x00
602 };
603
604 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
605 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
606 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
608 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
609 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
610 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
615 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
616 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
617 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
618 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
619 0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
620 0x00, 0x00
621 };
622
623 static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
624 {
625 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
627 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
628 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
629 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
630 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
631 0x00, 0x00
632 };
633
634 static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
635 {
636 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
641 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
642 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
643 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
646 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
649 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
650 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
651 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
653 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
654 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
655 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
656 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
659 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
660 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
661 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
662 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
663 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
664 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
665 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
666 0x14, 0x00, 0x00, 0x00
667 };
668
669 static const unsigned char MF_LINETO_BITS[] = {
670 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
671 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
672 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
673 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
674 0x00, 0x00
675 };
676
677 static const unsigned char EMF_LINETO_BITS[] = {
678 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
683 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
684 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
685 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
688 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
691 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
692 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
693 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
694 0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
695 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
696 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
697 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
698 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
699 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
700 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
701 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
702 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
703 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
704 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
705 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
706 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
707 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
708 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
709 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
710 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
711 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
712 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
713 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
715 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
717 };
718
719 static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
720 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
721 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
725 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
726 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
727 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
728 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
729 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
730 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
732 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
733 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
734 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
735 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
736 0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
737 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
738 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
739 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
740 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
741 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
743 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
744 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
745 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
746 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
747 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
748 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
749 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
750 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
751 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
752 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
753 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
754 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
755 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
756 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
757 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
758 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
759 };
760
761 static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
762 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
767 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
768 0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
769 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
771 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
772 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
775 0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
776 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
777 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
778 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
779 0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
780 0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
781 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
782 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
783 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
784 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
785 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
786 0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
787 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
788 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
790 0x14, 0x00, 0x00, 0x00
791 };
792
793 /* For debugging or dumping the raw metafiles produced by
794 * new test functions.
795 */
796 static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
797 INT nobj, LPARAM param)
798 {
799 trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, param %p\n",
800 hdc, mr->rdFunction, mr->rdSize, (void *)param);
801 return TRUE;
802 }
803
804 /* For debugging or dumping the raw metafiles produced by
805 * new test functions.
806 */
807
808 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
809 {
810 BYTE buf[MF_BUFSIZE];
811 UINT mfsize, i;
812
813 if (!winetest_debug) return;
814
815 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
816 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
817
818 printf ("MetaFile %s has bits:\n{\n ", desc);
819 for (i=0; i<mfsize; i++)
820 {
821 printf ("0x%02x", buf[i]);
822 if (i == mfsize-1)
823 printf ("\n");
824 else if (i % 8 == 7)
825 printf (",\n ");
826 else
827 printf (", ");
828 }
829 printf ("};\n");
830 }
831
832 /* Compare the metafile produced by a test function with the
833 * expected raw metafile data in "bits".
834 * Return value is 0 for a perfect match,
835 * -1 if lengths aren't equal,
836 * otherwise returns the number of non-matching bytes.
837 */
838
839 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
840 const char *desc)
841 {
842 unsigned char buf[MF_BUFSIZE];
843 UINT mfsize, i;
844 int diff;
845
846 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
847 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
848 if (mfsize < MF_BUFSIZE)
849 ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
850 desc, mfsize, bsize);
851 else
852 ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
853 desc, mfsize, bsize);
854 if (mfsize != bsize)
855 return -1;
856
857 diff = 0;
858 for (i=0; i<bsize; i++)
859 {
860 if (buf[i] != bits[i])
861 diff++;
862 }
863 ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
864 desc, mfsize, bsize, diff);
865
866 return diff;
867 }
868
869 static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
870 {
871 unsigned char buf[MF_BUFSIZE];
872 DWORD mfsize, rd_size, i;
873 int diff;
874 HANDLE hfile;
875 BOOL ret;
876
877 hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
878 assert(hfile != INVALID_HANDLE_VALUE);
879
880 mfsize = GetFileSize(hfile, NULL);
881 assert(mfsize <= MF_BUFSIZE);
882
883 ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
884 ok( ret && rd_size == mfsize, "ReadFile: error %d\n", GetLastError());
885
886 CloseHandle(hfile);
887
888 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n", desc, mfsize, bsize);
889
890 if (mfsize != bsize)
891 return -1;
892
893 diff = 0;
894 for (i=0; i<bsize; i++)
895 {
896 if (buf[i] != bits[i])
897 diff++;
898 }
899 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
900 desc, mfsize, bsize, diff);
901
902 return diff;
903 }
904
905 /* For debugging or dumping the raw EMFs produced by
906 * new test functions.
907 */
908 static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
909 {
910 BYTE buf[MF_BUFSIZE];
911 UINT mfsize, i;
912
913 if (!winetest_debug) return;
914
915 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
916 ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
917
918 printf("EMF %s has bits:\n{\n ", desc);
919 for (i = 0; i < mfsize; i++)
920 {
921 printf ("0x%02x", buf[i]);
922 if (i == mfsize-1)
923 printf ("\n");
924 else if (i % 8 == 7)
925 printf (",\n ");
926 else
927 printf (", ");
928 }
929 printf ("};\n");
930 }
931
932 static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
933 {
934 BYTE *emf;
935 BYTE buf[MF_BUFSIZE];
936 UINT mfsize, offset;
937
938 if (!winetest_debug) return;
939
940 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
941 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
942
943 printf("EMF %s has records:\n", desc);
944
945 emf = buf;
946 offset = 0;
947 while(offset < mfsize)
948 {
949 EMR *emr = (EMR *)(emf + offset);
950 printf("emr->iType %d, emr->nSize %u\n", emr->iType, emr->nSize);
951 /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
952 offset += emr->nSize;
953 }
954 }
955
956 static void dump_emf_record(const ENHMETARECORD *emr, const char *desc)
957 {
958 const BYTE *buf;
959 DWORD i;
960
961 if (!winetest_debug) return;
962
963 printf ("%s: EMF record %u has bits:\n{\n", desc, emr->iType);
964 buf = (const BYTE *)emr;
965 for (i = 0; i < emr->nSize; i++)
966 {
967 printf ("0x%02x", buf[i]);
968 if (i == emr->nSize - 1)
969 printf ("\n");
970 else if (i % 8 == 7)
971 printf (",\n");
972 else
973 printf (", ");
974 }
975 printf ("};\n");
976 }
977
978 static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2,
979 const char *desc, BOOL todo)
980 {
981 int diff;
982
983 if (emr1->iType != emr2->iType && todo)
984 {
985 todo_wine
986 {
987 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
988 desc, emr1->iType, emr2->iType);
989 }
990 }
991 else
992 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
993 desc, emr1->iType, emr2->iType);
994
995 if (emr1->nSize != emr2->nSize && todo)
996 {
997 todo_wine
998 {
999 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1000 desc, emr1->nSize, emr2->nSize);
1001 }
1002 }
1003 else
1004 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1005 desc, emr1->nSize, emr2->nSize);
1006
1007 /* iType and nSize mismatches are fatal */
1008 if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE;
1009
1010 /* contents of EMR_GDICOMMENT are not interesting */
1011 if (emr1->iType == EMR_GDICOMMENT) return TRUE;
1012
1013 diff = memcmp(emr1->dParm, emr2->dParm, emr1->nSize - sizeof(EMR));
1014 if (diff && todo)
1015 {
1016 todo_wine
1017 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1018 }
1019 else
1020 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1021
1022 if (diff)
1023 {
1024 dump_emf_record(emr1, "expected bits");
1025 dump_emf_record(emr2, "actual bits");
1026 }
1027
1028 return diff == 0 || todo; /* report all non-fatal record mismatches */
1029 }
1030
1031 /* Compare the EMF produced by a test function with the
1032 * expected raw EMF data in "bits".
1033 * Return value is 0 for a perfect match,
1034 * -1 if lengths aren't equal,
1035 * otherwise returns the number of non-matching bytes.
1036 */
1037 static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
1038 UINT bsize, const char *desc, BOOL todo)
1039 {
1040 unsigned char buf[MF_BUFSIZE];
1041 UINT mfsize, offset;
1042 const ENHMETAHEADER *emh1, *emh2;
1043
1044 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1045 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1046
1047 if (mfsize < MF_BUFSIZE)
1048 {
1049 if (mfsize != bsize && todo)
1050 {
1051 todo_wine
1052 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1053 }
1054 else
1055 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1056 }
1057 else
1058 ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
1059 desc, mfsize, bsize);
1060
1061 /* basic things must match */
1062 emh1 = (const ENHMETAHEADER *)bits;
1063 emh2 = (const ENHMETAHEADER *)buf;
1064 ok(emh1->iType == EMR_HEADER, "expected EMR_HEADER, got %u\n", emh1->iType);
1065 ok(emh1->nSize == sizeof(ENHMETAHEADER), "expected sizeof(ENHMETAHEADER), got %u\n", emh1->nSize);
1066 ok(emh2->nBytes == mfsize, "expected emh->nBytes %u, got %u\n", mfsize, emh2->nBytes);
1067 ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature);
1068
1069 ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType);
1070 ok(emh1->nSize == emh2->nSize, "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
1071 ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
1072 if (todo && emh1->nBytes != emh2->nBytes)
1073 {
1074 todo_wine
1075 ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1076 }
1077 else
1078 ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1079 if (todo && emh1->nRecords != emh2->nRecords)
1080 {
1081 todo_wine
1082 ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
1083 }
1084 else
1085 ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
1086
1087 offset = emh1->nSize;
1088 while (offset < emh1->nBytes)
1089 {
1090 const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset);
1091 const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset);
1092
1093 trace("EMF record %u, size %u/record %u, size %u\n",
1094 emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
1095
1096 if (!match_emf_record(emr1, emr2, desc, todo)) return -1;
1097
1098 offset += emr1->nSize;
1099 }
1100 return 0;
1101 }
1102
1103 /* Test a blank metafile. May be used as a template for new tests. */
1104
1105 static void test_mf_Blank(void)
1106 {
1107 HDC hdcMetafile;
1108 HMETAFILE hMetafile;
1109 INT caps;
1110 BOOL ret;
1111 INT type;
1112
1113 hdcMetafile = CreateMetaFileA(NULL);
1114 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1115 trace("hdcMetafile %p\n", hdcMetafile);
1116
1117 /* Tests on metafile initialization */
1118 caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
1119 ok (caps == DT_METAFILE,
1120 "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
1121
1122 hMetafile = CloseMetaFile(hdcMetafile);
1123 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1124 type = GetObjectType(hMetafile);
1125 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1126 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1127
1128 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1129 "mf_blank") != 0)
1130 {
1131 dump_mf_bits(hMetafile, "mf_Blank");
1132 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1133 }
1134
1135 ret = DeleteMetaFile(hMetafile);
1136 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1137 }
1138
1139 static void test_CopyMetaFile(void)
1140 {
1141 HDC hdcMetafile;
1142 HMETAFILE hMetafile, hmf_copy;
1143 BOOL ret;
1144 char temp_path[MAX_PATH];
1145 char mf_name[MAX_PATH];
1146 INT type;
1147
1148 hdcMetafile = CreateMetaFileA(NULL);
1149 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1150 trace("hdcMetafile %p\n", hdcMetafile);
1151
1152 hMetafile = CloseMetaFile(hdcMetafile);
1153 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1154 type = GetObjectType(hMetafile);
1155 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1156
1157 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1158 "mf_blank") != 0)
1159 {
1160 dump_mf_bits(hMetafile, "mf_Blank");
1161 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1162 }
1163
1164 GetTempPathA(MAX_PATH, temp_path);
1165 GetTempFileNameA(temp_path, "wmf", 0, mf_name);
1166
1167 hmf_copy = CopyMetaFileA(hMetafile, mf_name);
1168 ok(hmf_copy != 0, "CopyMetaFile error %d\n", GetLastError());
1169
1170 type = GetObjectType(hmf_copy);
1171 ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
1172
1173 ret = DeleteMetaFile(hMetafile);
1174 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1175
1176 if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
1177 {
1178 dump_mf_bits(hMetafile, "mf_Blank");
1179 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1180 }
1181
1182 ret = DeleteMetaFile(hmf_copy);
1183 ok( ret, "DeleteMetaFile(%p) error %d\n", hmf_copy, GetLastError());
1184
1185 DeleteFileA(mf_name);
1186 }
1187
1188 static void test_SetMetaFileBits(void)
1189 {
1190 HMETAFILE hmf;
1191 INT type;
1192 BOOL ret;
1193 BYTE buf[256];
1194 METAHEADER *mh;
1195
1196 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
1197 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1198 type = GetObjectType(hmf);
1199 ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
1200
1201 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1202 {
1203 dump_mf_bits(hmf, "mf_Graphics");
1204 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1205 }
1206
1207 ret = DeleteMetaFile(hmf);
1208 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1209
1210 /* NULL data crashes XP SP1 */
1211 /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
1212
1213 /* Now with not zero size */
1214 SetLastError(0xdeadbeef);
1215 hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
1216 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1217 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1218
1219 /* Now with not even size */
1220 SetLastError(0xdeadbeef);
1221 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
1222 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1223 ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
1224
1225 /* Now with zeroed out or faked some header fields */
1226 assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
1227 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1228 mh = (METAHEADER *)buf;
1229 /* corruption of any of the below fields leads to a failure */
1230 mh->mtType = 0;
1231 mh->mtVersion = 0;
1232 mh->mtHeaderSize = 0;
1233 SetLastError(0xdeadbeef);
1234 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1235 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1236 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1237
1238 /* Now with corrupted mtSize field */
1239 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1240 mh = (METAHEADER *)buf;
1241 /* corruption of mtSize doesn't lead to a failure */
1242 mh->mtSize *= 2;
1243 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1244 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1245
1246 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1247 {
1248 dump_mf_bits(hmf, "mf_Graphics");
1249 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1250 }
1251
1252 ret = DeleteMetaFile(hmf);
1253 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1254
1255 /* Now with zeroed out mtSize field */
1256 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1257 mh = (METAHEADER *)buf;
1258 /* zeroing mtSize doesn't lead to a failure */
1259 mh->mtSize = 0;
1260 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1261 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1262
1263 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1264 {
1265 dump_mf_bits(hmf, "mf_Graphics");
1266 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1267 }
1268
1269 ret = DeleteMetaFile(hmf);
1270 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1271 }
1272
1273 /* Simple APIs from mfdrv/graphics.c
1274 */
1275
1276 static void test_mf_Graphics(void)
1277 {
1278 HDC hdcMetafile;
1279 HMETAFILE hMetafile;
1280 POINT oldpoint;
1281 BOOL ret;
1282
1283 hdcMetafile = CreateMetaFileA(NULL);
1284 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1285 trace("hdcMetafile %p\n", hdcMetafile);
1286
1287 ret = MoveToEx(hdcMetafile, 1, 1, NULL);
1288 ok( ret, "MoveToEx error %d.\n", GetLastError());
1289 ret = LineTo(hdcMetafile, 2, 2);
1290 ok( ret, "LineTo error %d.\n", GetLastError());
1291 ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
1292 ok( ret, "MoveToEx error %d.\n", GetLastError());
1293
1294 /* oldpoint gets garbage under Win XP, so the following test would
1295 * work under Wine but fails under Windows:
1296 *
1297 * ok((oldpoint.x == 2) && (oldpoint.y == 2),
1298 * "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
1299 * oldpoint.x, oldpoint.y);
1300 */
1301
1302 ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
1303 ok( ret, "Ellipse error %d.\n", GetLastError());
1304
1305 hMetafile = CloseMetaFile(hdcMetafile);
1306 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1307 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1308
1309 if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
1310 "mf_Graphics") != 0)
1311 {
1312 dump_mf_bits(hMetafile, "mf_Graphics");
1313 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1314 }
1315
1316 ret = DeleteMetaFile(hMetafile);
1317 ok( ret, "DeleteMetaFile(%p) error %d\n",
1318 hMetafile, GetLastError());
1319 }
1320
1321 static void test_mf_PatternBrush(void)
1322 {
1323 HDC hdcMetafile;
1324 HMETAFILE hMetafile;
1325 LOGBRUSH *orig_lb;
1326 HBRUSH hBrush;
1327 BOOL ret;
1328
1329 orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
1330
1331 orig_lb->lbStyle = BS_PATTERN;
1332 orig_lb->lbColor = RGB(0, 0, 0);
1333 orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
1334 ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
1335
1336 hBrush = CreateBrushIndirect (orig_lb);
1337 ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
1338
1339 hdcMetafile = CreateMetaFileA(NULL);
1340 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
1341 trace("hdcMetafile %p\n", hdcMetafile);
1342
1343 hBrush = SelectObject(hdcMetafile, hBrush);
1344 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
1345
1346 hMetafile = CloseMetaFile(hdcMetafile);
1347 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1348 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1349
1350 if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
1351 "mf_Pattern_Brush") != 0)
1352 {
1353 dump_mf_bits(hMetafile, "mf_Pattern_Brush");
1354 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1355 }
1356
1357 ret = DeleteMetaFile(hMetafile);
1358 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
1359 ret = DeleteObject(hBrush);
1360 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
1361 ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
1362 ok( ret, "DeleteObject(HBITMAP) error %d\n",
1363 GetLastError());
1364 HeapFree (GetProcessHeap(), 0, orig_lb);
1365 }
1366
1367 static void test_mf_ExtTextOut_on_path(void)
1368 {
1369 HDC hdcMetafile;
1370 HMETAFILE hMetafile;
1371 BOOL ret;
1372 static const INT dx[4] = { 3, 5, 8, 12 };
1373
1374 hdcMetafile = CreateMetaFileA(NULL);
1375 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1376 trace("hdcMetafile %p\n", hdcMetafile);
1377
1378 ret = BeginPath(hdcMetafile);
1379 ok(!ret, "BeginPath on metafile DC should fail\n");
1380
1381 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1382 ok(ret, "ExtTextOut error %d\n", GetLastError());
1383
1384 ret = EndPath(hdcMetafile);
1385 ok(!ret, "EndPath on metafile DC should fail\n");
1386
1387 hMetafile = CloseMetaFile(hdcMetafile);
1388 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1389
1390 if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
1391 "mf_TextOut_on_path") != 0)
1392 {
1393 dump_mf_bits(hMetafile, "mf_TextOut_on_path");
1394 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1395 }
1396
1397 ret = DeleteMetaFile(hMetafile);
1398 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1399 }
1400
1401 static void test_emf_ExtTextOut_on_path(void)
1402 {
1403 HWND hwnd;
1404 HDC hdcDisplay, hdcMetafile;
1405 HENHMETAFILE hMetafile;
1406 BOOL ret;
1407 static const INT dx[4] = { 3, 5, 8, 12 };
1408
1409 /* Win9x doesn't play EMFs on invisible windows */
1410 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1411 0, 0, 200, 200, 0, 0, 0, NULL);
1412 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1413
1414 hdcDisplay = GetDC(hwnd);
1415 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
1416
1417 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
1418 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1419
1420 ret = BeginPath(hdcMetafile);
1421 ok(ret, "BeginPath error %d\n", GetLastError());
1422
1423 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1424 ok(ret, "ExtTextOut error %d\n", GetLastError());
1425
1426 ret = EndPath(hdcMetafile);
1427 ok(ret, "EndPath error %d\n", GetLastError());
1428
1429 hMetafile = CloseEnhMetaFile(hdcMetafile);
1430 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1431
1432 /* this doesn't succeed yet: EMF has correct size, all EMF records
1433 * are there, but their contents don't match for different reasons.
1434 */
1435 if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
1436 "emf_TextOut_on_path", TRUE) != 0)
1437 {
1438 dump_emf_bits(hMetafile, "emf_TextOut_on_path");
1439 dump_emf_records(hMetafile, "emf_TextOut_on_path");
1440 }
1441
1442 ret = DeleteEnhMetaFile(hMetafile);
1443 ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
1444 ret = ReleaseDC(hwnd, hdcDisplay);
1445 ok(ret, "ReleaseDC error %d\n", GetLastError());
1446 DestroyWindow(hwnd);
1447 }
1448
1449 static const unsigned char EMF_CLIPPING[] =
1450 {
1451 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1453 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1455 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
1456 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1457 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1458 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1460 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1461 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1463 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1464 0xe0, 0x93, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
1465 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1466 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
1467 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1468 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1469 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1470 0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1471 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1472 0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1473 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1474 0x00, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1475 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1476 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1477 };
1478
1479 static void translate( POINT *pt, UINT count, const XFORM *xform )
1480 {
1481 while (count--)
1482 {
1483 FLOAT x = (FLOAT)pt->x;
1484 FLOAT y = (FLOAT)pt->y;
1485 pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
1486 pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
1487 pt++;
1488 }
1489 }
1490
1491 static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
1492 const ENHMETARECORD *emr, int n_objs, LPARAM param)
1493 {
1494 if (emr->iType == EMR_EXTSELECTCLIPRGN)
1495 {
1496 const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
1497 union _rgn
1498 {
1499 RGNDATA data;
1500 char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
1501 };
1502 const union _rgn *rgn1;
1503 union _rgn rgn2;
1504 RECT rect, rc_transformed;
1505 const RECT *rc = (const RECT *)param;
1506 HRGN hrgn;
1507 XFORM xform;
1508 INT ret;
1509 BOOL is_win9x;
1510
1511 trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
1512 clip->cbRgnData, clip->iMode);
1513
1514 ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
1515 ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
1516 "too small data block: %u bytes\n", clip->cbRgnData);
1517 if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
1518 return 0;
1519
1520 rgn1 = (const union _rgn *)clip->RgnData;
1521
1522 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1523 rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
1524 rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
1525 rgn1->data.rdh.rcBound.left, rgn1->data.rdh.rcBound.top,
1526 rgn1->data.rdh.rcBound.right, rgn1->data.rdh.rcBound.bottom);
1527
1528 ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
1529
1530 rect = *(const RECT *)rgn1->data.Buffer;
1531 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1532 ok(EqualRect(&rect, rc), "rects don't match\n");
1533
1534 ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize);
1535 ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
1536 ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
1537 ok(rgn1->data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
1538
1539 hrgn = CreateRectRgn(0, 0, 0, 0);
1540
1541 memset(&xform, 0, sizeof(xform));
1542 SetLastError(0xdeadbeef);
1543 ret = GetWorldTransform(hdc, &xform);
1544 is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1545 if (!is_win9x)
1546 ok(ret, "GetWorldTransform error %u\n", GetLastError());
1547
1548 trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
1549
1550 ret = GetClipRgn(hdc, hrgn);
1551 ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
1552
1553 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
1554
1555 ret = GetClipRgn(hdc, hrgn);
1556 ok(ret == 1, "GetClipRgn returned %d, expected 0\n", ret);
1557
1558 /* Win9x returns empty clipping region */
1559 if (is_win9x) return 1;
1560
1561 ret = GetRegionData(hrgn, 0, NULL);
1562 ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
1563
1564 ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
1565
1566 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1567 rgn2.data.rdh.dwSize, rgn2.data.rdh.iType,
1568 rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
1569 rgn2.data.rdh.rcBound.left, rgn2.data.rdh.rcBound.top,
1570 rgn2.data.rdh.rcBound.right, rgn2.data.rdh.rcBound.bottom);
1571
1572 rect = rgn2.data.rdh.rcBound;
1573 rc_transformed = *rc;
1574 translate((POINT *)&rc_transformed, 2, &xform);
1575 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1576 rc_transformed.right, rc_transformed.bottom);
1577 ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
1578
1579 rect = *(const RECT *)rgn2.data.Buffer;
1580 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1581 rc_transformed = *rc;
1582 translate((POINT *)&rc_transformed, 2, &xform);
1583 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1584 rc_transformed.right, rc_transformed.bottom);
1585 ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
1586
1587 ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize);
1588 ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
1589 ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
1590 ok(rgn2.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
1591
1592 DeleteObject(hrgn);
1593 }
1594 return 1;
1595 }
1596
1597 static void test_emf_clipping(void)
1598 {
1599 static const RECT rc = { 0, 0, 100, 100 };
1600 RECT rc_clip = { 100, 100, 1024, 1024 };
1601 HWND hwnd;
1602 HDC hdc;
1603 HENHMETAFILE hemf;
1604 HRGN hrgn;
1605 INT ret;
1606
1607 SetLastError(0xdeadbeef);
1608 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1609 ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1610
1611 /* Need to write something to the emf, otherwise Windows won't play it back */
1612 LineTo(hdc, 1, 1);
1613
1614 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
1615 ret = SelectClipRgn(hdc, hrgn);
1616 ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
1617
1618 SetLastError(0xdeadbeef);
1619 hemf = CloseEnhMetaFile(hdc);
1620 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1621
1622 if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
1623 "emf_clipping", TRUE) != 0)
1624 {
1625 dump_emf_bits(hemf, "emf_clipping");
1626 dump_emf_records(hemf, "emf_clipping");
1627 }
1628
1629 DeleteObject(hrgn);
1630
1631 /* Win9x doesn't play EMFs on invisible windows */
1632 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1633 0, 0, 200, 200, 0, 0, 0, NULL);
1634 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1635
1636 hdc = GetDC(hwnd);
1637
1638 ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
1639 ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
1640
1641 DeleteEnhMetaFile(hemf);
1642 ReleaseDC(hwnd, hdc);
1643 DestroyWindow(hwnd);
1644 }
1645
1646 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
1647 {
1648 LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
1649 POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
1650 /* When using MM_TEXT Win9x does not update the mapping mode
1651 * until a record is played which actually outputs something */
1652 PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
1653 LPtoDP(hdc, mapping, 2);
1654 trace("EMF record: iType %d, nSize %d, (%d,%d)-(%d,%d)\n",
1655 lpEMFR->iType, lpEMFR->nSize,
1656 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
1657
1658 if (lpEMFR->iType == EMR_LINETO)
1659 {
1660 INT x0, y0, x1, y1;
1661 if (!lpMFP || lpMFP->mm == MM_TEXT)
1662 {
1663 x0 = 0;
1664 y0 = 0;
1665 x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
1666 y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
1667 }
1668 else
1669 {
1670 ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
1671
1672 x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1673 y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1674 x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1675 y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1676 }
1677 ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
1678 "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
1679 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
1680 x0, y0, x1, y1);
1681 }
1682 return TRUE;
1683 }
1684
1685 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
1686 {
1687 HDC hdcMf;
1688 HMETAFILE hmf;
1689 BOOL ret;
1690 UINT size;
1691 LPBYTE pBits;
1692
1693 hdcMf = CreateMetaFile(NULL);
1694 ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
1695 ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
1696 ok(ret, "LineTo failed with error %d\n", GetLastError());
1697 hmf = CloseMetaFile(hdcMf);
1698 ok(hmf != NULL, "CloseMetaFile failed with error %d\n", GetLastError());
1699
1700 if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
1701 {
1702 dump_mf_bits(hmf, "mf_LineTo");
1703 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1704 }
1705
1706 size = GetMetaFileBitsEx(hmf, 0, NULL);
1707 ok(size, "GetMetaFileBitsEx failed with error %d\n", GetLastError());
1708 pBits = HeapAlloc(GetProcessHeap(), 0, size);
1709 GetMetaFileBitsEx(hmf, size, pBits);
1710 DeleteMetaFile(hmf);
1711 return SetWinMetaFileBits(size, pBits, NULL, mfp);
1712 }
1713
1714 static void test_mf_conversions(void)
1715 {
1716 trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
1717 {
1718 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1719 HENHMETAFILE hemf;
1720 METAFILEPICT mfp;
1721 RECT rect = { 0, 0, 100, 100 };
1722 mfp.mm = MM_ANISOTROPIC;
1723 mfp.xExt = 100;
1724 mfp.yExt = 100;
1725 mfp.hMF = NULL;
1726 hemf = create_converted_emf(&mfp);
1727
1728 if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
1729 "emf_LineTo MM_ANISOTROPIC", TRUE) != 0)
1730 {
1731 dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
1732 dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
1733 }
1734
1735 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1736
1737 DeleteEnhMetaFile(hemf);
1738 DeleteDC(hdcOffscreen);
1739 }
1740
1741 trace("Testing MF->EMF conversion (MM_TEXT)\n");
1742 {
1743 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1744 HENHMETAFILE hemf;
1745 METAFILEPICT mfp;
1746 RECT rect = { 0, 0, 100, 100 };
1747 mfp.mm = MM_TEXT;
1748 mfp.xExt = 0;
1749 mfp.yExt = 0;
1750 mfp.hMF = NULL;
1751 hemf = create_converted_emf(&mfp);
1752
1753 if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
1754 "emf_LineTo MM_TEXT", TRUE) != 0)
1755 {
1756 dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
1757 dump_emf_records(hemf, "emf_LineTo MM_TEXT");
1758 }
1759
1760 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1761
1762 DeleteEnhMetaFile(hemf);
1763 DeleteDC(hdcOffscreen);
1764 }
1765
1766 trace("Testing MF->EMF conversion (NULL mfp)\n");
1767 {
1768 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1769 HENHMETAFILE hemf;
1770 RECT rect = { 0, 0, 100, 100 };
1771 hemf = create_converted_emf(NULL);
1772
1773 if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
1774 "emf_LineTo NULL", TRUE) != 0)
1775 {
1776 dump_emf_bits(hemf, "emf_LineTo NULL");
1777 dump_emf_records(hemf, "emf_LineTo NULL");
1778 }
1779
1780 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
1781
1782 DeleteEnhMetaFile(hemf);
1783 DeleteDC(hdcOffscreen);
1784 }
1785 }
1786
1787 static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1788 LONG mm, LONG xExt, LONG yExt,
1789 RECTL * rclBounds, RECTL * rclFrame)
1790 {
1791 METAFILEPICT mfp;
1792 METAFILEPICT * mfpPtr = NULL;
1793 HENHMETAFILE emf;
1794 ENHMETAHEADER header;
1795 UINT res;
1796
1797 if (!mfpIsNull)
1798 {
1799 mfp.mm = mm;
1800 mfp.xExt = xExt;
1801 mfp.yExt = yExt;
1802 mfpPtr = &mfp;
1803 }
1804
1805 emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
1806 ok(emf != NULL, "SetWinMetaFileBits failed\n");
1807 if (!emf) return FALSE;
1808 res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
1809 ok(res != 0, "GetEnhMetaHeader failed\n");
1810 DeleteEnhMetaFile(emf);
1811 if (!res) return FALSE;
1812
1813 *rclBounds = header.rclBounds;
1814 *rclFrame = header.rclFrame;
1815 return TRUE;
1816 }
1817
1818 static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1819 LONG mm, LONG xExt, LONG yExt,
1820 RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
1821 {
1822 RECTL rclBounds, rclFrame;
1823
1824 if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
1825 {
1826 const char * msg;
1827 char buf[64];
1828
1829 if (mfpIsNull)
1830 {
1831 msg = "mfp == NULL";
1832 }
1833 else
1834 {
1835 const char * mm_str;
1836 switch (mm)
1837 {
1838 case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
1839 case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
1840 default: mm_str = "Unexpected";
1841 }
1842 sprintf(buf, "mm=%s, xExt=%d, yExt=%d", mm_str, xExt, yExt);
1843 msg = buf;
1844 }
1845
1846 ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
1847 ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
1848 ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
1849 ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
1850 ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
1851 ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
1852 ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
1853 ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
1854 }
1855 }
1856
1857 static void test_SetWinMetaFileBits(void)
1858 {
1859 HMETAFILE wmf;
1860 HDC wmfDC;
1861 BYTE * buffer;
1862 UINT buffer_size;
1863 RECT rect;
1864 UINT res;
1865 RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
1866 RECTL rclBoundsIsotropic, rclFrameIsotropic;
1867 RECTL rclBounds, rclFrame;
1868 HDC dc;
1869 LONG diffx, diffy;
1870
1871 wmfDC = CreateMetaFile(NULL);
1872 ok(wmfDC != NULL, "CreateMetaFile failed\n");
1873 if (!wmfDC) return;
1874
1875 SetWindowExtEx(wmfDC, 100, 100, NULL);
1876 rect.left = rect.top = 0;
1877 rect.right = rect.bottom = 50;
1878 FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
1879 wmf = CloseMetaFile(wmfDC);
1880 ok(wmf != NULL, "Metafile creation failed\n");
1881 if (!wmf) return;
1882
1883 buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
1884 ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
1885 if (buffer_size == 0)
1886 {
1887 DeleteMetaFile(wmf);
1888 return;
1889 }
1890
1891 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
1892 ok(buffer != NULL, "HeapAlloc failed\n");
1893 if (!buffer)
1894 {
1895 DeleteMetaFile(wmf);
1896 return;
1897 }
1898
1899 res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
1900 ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
1901 DeleteMetaFile(wmf);
1902 if (res != buffer_size)
1903 {
1904 HeapFree(GetProcessHeap(), 0, buffer);
1905 return;
1906 }
1907
1908 /* Get the reference bounds and frame */
1909 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1910 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1911
1912 ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
1913 rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
1914 "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
1915
1916 ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
1917 ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
1918 diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
1919 if (diffx < 0) diffx = -diffx;
1920 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
1921
1922 dc = CreateCompatibleDC(NULL);
1923 todo_wine
1924 {
1925 ok(rclBoundsAnisotropic.right == GetDeviceCaps(dc, HORZRES) / 2 - 1 &&
1926 rclBoundsAnisotropic.bottom == GetDeviceCaps(dc, VERTRES) / 2 - 1,
1927 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
1928 GetDeviceCaps(dc, HORZRES) / 2 - 1, GetDeviceCaps(dc, VERTRES) / 2 - 1, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
1929 }
1930
1931 /* Allow 1 mm difference (rounding errors) */
1932 diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
1933 diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
1934 if (diffx < 0) diffx = -diffx;
1935 if (diffy < 0) diffy = -diffy;
1936 todo_wine
1937 {
1938 ok(diffx <= 1 && diffy <= 1,
1939 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
1940 GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
1941 }
1942 DeleteDC(dc);
1943
1944 /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
1945 checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1946
1947 /* If xExt or yExt is zero or negative, the whole device surface is used */
1948 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1949 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1950 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1951 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1952 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1953 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1954 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1955 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1956 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1957 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1958 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1959 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1960
1961 /* MSDN says that negative xExt and yExt values specify a ratio.
1962 Check that this is wrong and the whole device surface is used */
1963 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1964 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
1965
1966 /* Ordinary conversions */
1967
1968 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
1969 {
1970 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
1971 "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
1972 ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
1973 "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
1974 }
1975
1976 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
1977 {
1978 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
1979 "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
1980 ok(rclBounds.left == 0 && rclBounds.top == 0,
1981 "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
1982
1983 /* Wine has a rounding error */
1984 diffx = rclBounds.right - rclBounds.bottom;
1985 if (diffx < 0) diffx = -diffx;
1986 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
1987 }
1988
1989 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
1990 {
1991 ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
1992 "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
1993 }
1994
1995 HeapFree(GetProcessHeap(), 0, buffer);
1996 }
1997
1998 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
1999 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
2000 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
2001
2002 static void test_gdiis(void)
2003 {
2004 RECT rect = {0,0,100,100};
2005 HDC hdc, hemfDC, hmfDC;
2006 HENHMETAFILE hemf;
2007 HMODULE hgdi32;
2008
2009 /* resolve all the functions */
2010 hgdi32 = GetModuleHandle("gdi32");
2011 pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
2012 pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
2013 pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
2014
2015 /* they should all exist or none should exist */
2016 if(!pGdiIsMetaPrintDC)
2017 return;
2018
2019 /* try with nothing */
2020 ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
2021 ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
2022 ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
2023
2024 /* try with a metafile */
2025 hmfDC = CreateMetaFile(NULL);
2026 ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
2027 ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
2028 ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
2029 DeleteMetaFile(CloseMetaFile(hmfDC));
2030
2031 /* try with an enhanced metafile */
2032 hdc = GetDC(NULL);
2033 hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
2034 ok(hemfDC != NULL, "failed to create emf\n");
2035
2036 ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
2037 ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
2038 ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
2039
2040 hemf = CloseEnhMetaFile(hemfDC);
2041 ok(hemf != NULL, "failed to close EMF\n");
2042 DeleteEnhMetaFile(hemf);
2043 ReleaseDC(NULL,hdc);
2044 }
2045
2046 static void test_SetEnhMetaFileBits(void)
2047 {
2048 BYTE data[256];
2049 HENHMETAFILE hemf;
2050 ENHMETAHEADER *emh;
2051
2052 memset(data, 0xAA, sizeof(data));
2053 SetLastError(0xdeadbeef);
2054 hemf = SetEnhMetaFileBits(sizeof(data), data);
2055 ok(!hemf, "SetEnhMetaFileBits should fail\n");
2056 ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA, got %u\n", GetLastError());
2057
2058 emh = (ENHMETAHEADER *)data;
2059 memset(emh, 0, sizeof(*emh));
2060
2061 emh->iType = EMR_HEADER;
2062 emh->nSize = sizeof(*emh);
2063 emh->dSignature = ENHMETA_SIGNATURE;
2064 /* emh->nVersion = 0x10000; XP doesn't care about version */
2065 emh->nBytes = sizeof(*emh);
2066 /* emh->nRecords = 1; XP doesn't care about records */
2067 emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
2068
2069 SetLastError(0xdeadbeef);
2070 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2071 ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
2072 DeleteEnhMetaFile(hemf);
2073
2074 /* XP refuses to load unaligned EMF */
2075 emh->nBytes++;
2076 SetLastError(0xdeadbeef);
2077 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2078 ok(!hemf, "SetEnhMetaFileBits should fail\n");
2079 /* XP doesn't set error in this case */
2080
2081 emh->dSignature = 0;
2082 emh->nBytes--;
2083 SetLastError(0xdeadbeef);
2084 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2085 ok(!hemf, "SetEnhMetaFileBits should fail\n");
2086 /* XP doesn't set error in this case */
2087 }
2088
2089 START_TEST(metafile)
2090 {
2091 init_function_pointers();
2092
2093 /* For enhanced metafiles (enhmfdrv) */
2094 test_ExtTextOut();
2095 test_SaveDC();
2096
2097 /* For win-format metafiles (mfdrv) */
2098 test_mf_Blank();
2099 test_mf_Graphics();
2100 test_mf_PatternBrush();
2101 test_CopyMetaFile();
2102 test_SetMetaFileBits();
2103 test_mf_ExtTextOut_on_path();
2104 test_emf_ExtTextOut_on_path();
2105 test_emf_clipping();
2106
2107 /* For metafile conversions */
2108 test_mf_conversions();
2109 test_SetWinMetaFileBits();
2110
2111 test_gdiis();
2112 test_SetEnhMetaFileBits();
2113 }