gdi32: Save/restore internal EMF playing state on EMR_SAVEDC/EMR_RESTOREDC, add a...
[wine.git] / dlls / gdi32 / tests / metafile.c
blob0b50d586a729256d115bcba631b17f44f5105ba4
1 /*
2 * Unit tests for metafile functions
4 * Copyright (c) 2002 Dmitry Timoshkov
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.
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.
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
21 #include <assert.h>
22 #include <stdio.h>
23 #include <math.h>
25 #include "wine/test.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
31 static LOGFONTA orig_lf;
32 static BOOL emr_processed = FALSE;
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
38 static INT (WINAPI * pGetRelAbs)(HDC, DWORD);
39 static INT (WINAPI * pSetRelAbs)(HDC, INT);
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); \
46 static void init_function_pointers(void)
48 HMODULE hGDI;
50 pGetRelAbs = NULL;
51 pSetRelAbs = NULL;
53 hGDI = GetModuleHandleA("gdi32.dll");
54 assert(hGDI);
55 GDI_GET_PROC(GetRelAbs);
56 GDI_GET_PROC(SetRelAbs);
59 static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
60 const ENHMETARECORD *emr, int n_objs, LPARAM param)
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;
69 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
70 hdc, emr->iType, emr->nSize, (void *)param);
72 if(!hdc) return 1;
74 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
76 switch (emr->iType)
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));
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));
92 n_record = 0;
93 break;
95 case EMR_EXTTEXTOUTA:
97 const EMREXTTEXTOUTA *emr_ExtTextOutA = (const EMREXTTEXTOUTA *)emr;
98 dx = (const INT *)((const char *)emr + emr_ExtTextOutA->emrtext.offDx);
100 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
101 ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError());
103 /* compare up to lfOutPrecision, other values are not interesting,
104 * and in fact sometimes arbitrary adapted by Win9x.
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");
109 for(i = 0; i < emr_ExtTextOutA->emrtext.nChars; i++)
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]);
114 n_record++;
115 emr_processed = TRUE;
116 break;
119 case EMR_EXTTEXTOUTW:
121 const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr;
122 dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx);
124 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
125 ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError());
127 /* compare up to lfOutPrecision, other values are not interesting,
128 * and in fact sometimes arbitrary adapted by Win9x.
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");
133 for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
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]);
138 n_record++;
139 emr_processed = TRUE;
140 break;
143 default:
144 break;
147 return 1;
150 static void test_ExtTextOut(void)
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;
161 assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
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());
168 hdcDisplay = GetDC(hwnd);
169 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
171 trace("hdcDisplay %p\n", hdcDisplay);
173 SetMapMode(hdcDisplay, MM_TEXT);
175 memset(&orig_lf, 0, sizeof(orig_lf));
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());
186 hFont = SelectObject(hdcDisplay, hFont);
188 len = lstrlenA(text);
189 for (i = 0; i < len; i++)
191 ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
192 ok( ret, "GetCharWidthA error %d\n", GetLastError());
194 hFont = SelectObject(hdcDisplay, hFont);
196 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
197 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
199 trace("hdcMetafile %p\n", hdcMetafile);
201 ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
202 "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
204 hFont = SelectObject(hdcMetafile, hFont);
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());
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());
214 hFont = SelectObject(hdcMetafile, hFont);
215 ret = DeleteObject(hFont);
216 ok( ret, "DeleteObject error %d\n", GetLastError());
218 hMetafile = CloseEnhMetaFile(hdcMetafile);
219 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
221 ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
223 ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
224 ok( ret, "PlayEnhMetaFile error %d\n", GetLastError());
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);
234 if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
235 SetBkMode(hdcDisplay, OPAQUE);
237 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
238 ok( ret, "EnumEnhMetaFile error %d\n", GetLastError());
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));
249 ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
251 ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
252 "A valid hdc has to require a valid rc\n");
254 ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
255 "A null hdc does not require a valid rc\n");
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);
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)
268 BOOL ret;
269 XFORM xform;
270 POINT vp_org, win_org;
271 SIZE vp_size, win_size;
272 FLOAT xscale, yscale, edx, edy;
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());
279 trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
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);
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);
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);
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);
299 return;
301 win9x_here:
303 GetWindowOrgEx(hdc, &win_org);
304 GetViewportOrgEx(hdc, &vp_org);
305 GetWindowExtEx(hdc, &win_size);
306 GetViewportExtEx(hdc, &vp_size);
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);
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);
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);
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);
321 static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
322 const ENHMETARECORD *emr, int n_objs, LPARAM param)
324 BOOL ret;
325 XFORM xform;
326 POINT pt;
327 SIZE size;
328 static int save_state;
329 static int restore_no;
331 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
332 hdc, emr->iType, emr->nSize, (void *)param);
334 trace("BEFORE:\n");
335 SetLastError(0xdeadbeef);
336 ret = GetWorldTransform(hdc, &xform);
337 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
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);
348 else
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);
354 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
356 switch (emr->iType)
358 case EMR_HEADER:
360 static RECT exp_bounds = { 0, 0, 150, 150 };
361 RECT bounds;
362 const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
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);
370 SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
371 ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
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;
379 case EMR_LINETO:
381 const EMRLINETO *line = (const EMRLINETO *)emr;
382 trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
383 break;
385 case EMR_SETWINDOWORGEX:
387 const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
388 trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
389 break;
391 case EMR_SETWINDOWEXTEX:
393 const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
394 trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
395 break;
397 case EMR_SETVIEWPORTORGEX:
399 const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
400 trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
401 break;
403 case EMR_SETVIEWPORTEXTEX:
405 const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
406 trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
407 break;
409 case EMR_SAVEDC:
410 save_state++;
411 trace("EMR_SAVEDC\n");
412 break;
414 case EMR_RESTOREDC:
416 const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
417 trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
419 switch(++restore_no)
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;
434 ok(restore_no <= 3, "restore_no %d\n", restore_no);
435 save_state += restoredc->iRelative;
436 break;
438 case EMR_EOF:
439 ok(save_state == 0, "EOF save_state %d\n", save_state);
440 break;
443 trace("AFTER:\n");
444 SetLastError(0xdeadbeef);
445 ret = GetWorldTransform(hdc, &xform);
446 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
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);
457 else
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);
463 return 1;
466 static void test_SaveDC(void)
468 HDC hdcMetafile, hdcDisplay;
469 HENHMETAFILE hMetafile;
470 HWND hwnd;
471 int ret;
472 static const RECT rc = { 0, 0, 150, 150 };
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());
479 hdcDisplay = GetDC(hwnd);
480 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
482 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
483 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
485 SetMapMode(hdcMetafile, MM_ANISOTROPIC);
487 /* Need to write something to the emf, otherwise Windows won't play it back */
488 LineTo(hdcMetafile, 150, 150);
490 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
491 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
492 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
493 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
495 /* Force Win9x to update DC state */
496 SetPixelV(hdcMetafile, 50, 50, 0);
498 ret = SaveDC(hdcMetafile);
499 ok(ret == 1, "ret = %d\n", ret);
501 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
502 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
503 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
504 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
506 /* Force Win9x to update DC state */
507 SetPixelV(hdcMetafile, 50, 50, 0);
509 ret = SaveDC(hdcMetafile);
510 ok(ret == 2, "ret = %d\n", ret);
512 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
513 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
514 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
515 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
517 /* Force Win9x to update DC state */
518 SetPixelV(hdcMetafile, 50, 50, 0);
520 ret = SaveDC(hdcMetafile);
521 ok(ret == 3, "ret = %d\n", ret);
523 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
524 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
525 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
526 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
528 /* Force Win9x to update DC state */
529 SetPixelV(hdcMetafile, 50, 50, 0);
531 ret = RestoreDC(hdcMetafile, -1);
532 ok(ret, "ret = %d\n", ret);
534 ret = SaveDC(hdcMetafile);
535 ok(ret == 3, "ret = %d\n", ret);
537 ret = RestoreDC(hdcMetafile, 1);
538 ok(ret, "ret = %d\n", ret);
540 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
541 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
542 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
543 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
545 /* Force Win9x to update DC state */
546 SetPixelV(hdcMetafile, 50, 50, 0);
548 ret = SaveDC(hdcMetafile);
549 ok(ret == 1, "ret = %d\n", ret);
551 ret = SaveDC(hdcMetafile);
552 ok(ret == 2, "ret = %d\n", ret);
554 hMetafile = CloseEnhMetaFile(hdcMetafile);
555 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
557 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
558 ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
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);
567 /* Win-format metafile (mfdrv) tests */
568 /* These tests compare the generated metafiles byte-by-byte */
569 /* with the nominal results. */
571 /* Maximum size of sample metafiles in bytes. */
572 #define MF_BUFSIZE 512
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
582 /* Sample metafiles to be compared to the outputs of the
583 * test functions.
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,
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
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
623 static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
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
634 static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
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
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
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
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
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
793 /* For debugging or dumping the raw metafiles produced by
794 * new test functions.
796 static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
797 INT nobj, LPARAM param)
799 trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, param %p\n",
800 hdc, mr->rdFunction, mr->rdSize, (void *)param);
801 return TRUE;
804 /* For debugging or dumping the raw metafiles produced by
805 * new test functions.
808 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
810 BYTE buf[MF_BUFSIZE];
811 UINT mfsize, i;
813 if (!winetest_debug) return;
815 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
816 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
818 printf ("MetaFile %s has bits:\n{\n ", desc);
819 for (i=0; i<mfsize; i++)
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 (", ");
829 printf ("};\n");
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.
839 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
840 const char *desc)
842 unsigned char buf[MF_BUFSIZE];
843 UINT mfsize, i;
844 int diff;
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;
857 diff = 0;
858 for (i=0; i<bsize; i++)
860 if (buf[i] != bits[i])
861 diff++;
863 ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
864 desc, mfsize, bsize, diff);
866 return diff;
869 static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
871 unsigned char buf[MF_BUFSIZE];
872 DWORD mfsize, rd_size, i;
873 int diff;
874 HANDLE hfile;
875 BOOL ret;
877 hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
878 assert(hfile != INVALID_HANDLE_VALUE);
880 mfsize = GetFileSize(hfile, NULL);
881 assert(mfsize <= MF_BUFSIZE);
883 ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
884 ok( ret && rd_size == mfsize, "ReadFile: error %d\n", GetLastError());
886 CloseHandle(hfile);
888 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n", desc, mfsize, bsize);
890 if (mfsize != bsize)
891 return -1;
893 diff = 0;
894 for (i=0; i<bsize; i++)
896 if (buf[i] != bits[i])
897 diff++;
899 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
900 desc, mfsize, bsize, diff);
902 return diff;
905 /* For debugging or dumping the raw EMFs produced by
906 * new test functions.
908 static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
910 BYTE buf[MF_BUFSIZE];
911 UINT mfsize, i;
913 if (!winetest_debug) return;
915 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
916 ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
918 printf("EMF %s has bits:\n{\n ", desc);
919 for (i = 0; i < mfsize; i++)
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 (", ");
929 printf ("};\n");
932 static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
934 BYTE *emf;
935 BYTE buf[MF_BUFSIZE];
936 UINT mfsize, offset;
938 if (!winetest_debug) return;
940 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
941 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
943 printf("EMF %s has records:\n", desc);
945 emf = buf;
946 offset = 0;
947 while(offset < mfsize)
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;
956 /* Compare the EMF produced by a test function with the
957 * expected raw EMF data in "bits".
958 * Return value is 0 for a perfect match,
959 * -1 if lengths aren't equal,
960 * otherwise returns the number of non-matching bytes.
962 static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
963 UINT bsize, const char *desc, BOOL todo)
965 unsigned char buf[MF_BUFSIZE];
966 UINT mfsize, i;
967 int diff;
969 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
970 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
972 if (mfsize < MF_BUFSIZE)
974 if (mfsize != bsize && todo)
976 todo_wine
977 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
979 else
980 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
982 else
983 ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
984 desc, mfsize, bsize);
986 if (mfsize != bsize)
987 return -1;
989 diff = 0;
990 for (i = 0; i < bsize; i++)
992 if (buf[i] != bits[i])
993 diff++;
995 if (diff != 0 && todo)
997 todo_wine
999 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1000 desc, mfsize, bsize, diff);
1002 return diff;
1004 else
1006 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1007 desc, mfsize, bsize, diff);
1009 return diff;
1013 /* Test a blank metafile. May be used as a template for new tests. */
1015 static void test_mf_Blank(void)
1017 HDC hdcMetafile;
1018 HMETAFILE hMetafile;
1019 INT caps;
1020 BOOL ret;
1021 INT type;
1023 hdcMetafile = CreateMetaFileA(NULL);
1024 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1025 trace("hdcMetafile %p\n", hdcMetafile);
1027 /* Tests on metafile initialization */
1028 caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
1029 ok (caps == DT_METAFILE,
1030 "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
1032 hMetafile = CloseMetaFile(hdcMetafile);
1033 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1034 type = GetObjectType(hMetafile);
1035 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1036 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1038 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1039 "mf_blank") != 0)
1041 dump_mf_bits(hMetafile, "mf_Blank");
1042 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1045 ret = DeleteMetaFile(hMetafile);
1046 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1049 static void test_CopyMetaFile(void)
1051 HDC hdcMetafile;
1052 HMETAFILE hMetafile, hmf_copy;
1053 BOOL ret;
1054 char temp_path[MAX_PATH];
1055 char mf_name[MAX_PATH];
1056 INT type;
1058 hdcMetafile = CreateMetaFileA(NULL);
1059 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1060 trace("hdcMetafile %p\n", hdcMetafile);
1062 hMetafile = CloseMetaFile(hdcMetafile);
1063 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1064 type = GetObjectType(hMetafile);
1065 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1067 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1068 "mf_blank") != 0)
1070 dump_mf_bits(hMetafile, "mf_Blank");
1071 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1074 GetTempPathA(MAX_PATH, temp_path);
1075 GetTempFileNameA(temp_path, "wmf", 0, mf_name);
1077 hmf_copy = CopyMetaFileA(hMetafile, mf_name);
1078 ok(hmf_copy != 0, "CopyMetaFile error %d\n", GetLastError());
1080 type = GetObjectType(hmf_copy);
1081 ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
1083 ret = DeleteMetaFile(hMetafile);
1084 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1086 if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
1088 dump_mf_bits(hMetafile, "mf_Blank");
1089 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1092 ret = DeleteMetaFile(hmf_copy);
1093 ok( ret, "DeleteMetaFile(%p) error %d\n", hmf_copy, GetLastError());
1095 DeleteFileA(mf_name);
1098 static void test_SetMetaFileBits(void)
1100 HMETAFILE hmf;
1101 INT type;
1102 BOOL ret;
1103 BYTE buf[256];
1104 METAHEADER *mh;
1106 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
1107 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1108 type = GetObjectType(hmf);
1109 ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
1111 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1113 dump_mf_bits(hmf, "mf_Graphics");
1114 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1117 ret = DeleteMetaFile(hmf);
1118 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1120 /* NULL data crashes XP SP1 */
1121 /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
1123 /* Now with not zero size */
1124 SetLastError(0xdeadbeef);
1125 hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
1126 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1127 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1129 /* Now with not even size */
1130 SetLastError(0xdeadbeef);
1131 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
1132 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1133 ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
1135 /* Now with zeroed out or faked some header fields */
1136 assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
1137 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1138 mh = (METAHEADER *)buf;
1139 /* corruption of any of the below fields leads to a failure */
1140 mh->mtType = 0;
1141 mh->mtVersion = 0;
1142 mh->mtHeaderSize = 0;
1143 SetLastError(0xdeadbeef);
1144 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1145 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1146 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1148 /* Now with corrupted mtSize field */
1149 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1150 mh = (METAHEADER *)buf;
1151 /* corruption of mtSize doesn't lead to a failure */
1152 mh->mtSize *= 2;
1153 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1154 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1156 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1158 dump_mf_bits(hmf, "mf_Graphics");
1159 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1162 ret = DeleteMetaFile(hmf);
1163 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1165 /* Now with zeroed out mtSize field */
1166 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1167 mh = (METAHEADER *)buf;
1168 /* zeroing mtSize doesn't lead to a failure */
1169 mh->mtSize = 0;
1170 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1171 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1173 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1175 dump_mf_bits(hmf, "mf_Graphics");
1176 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1179 ret = DeleteMetaFile(hmf);
1180 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1183 /* Simple APIs from mfdrv/graphics.c
1186 static void test_mf_Graphics(void)
1188 HDC hdcMetafile;
1189 HMETAFILE hMetafile;
1190 POINT oldpoint;
1191 BOOL ret;
1193 hdcMetafile = CreateMetaFileA(NULL);
1194 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1195 trace("hdcMetafile %p\n", hdcMetafile);
1197 ret = MoveToEx(hdcMetafile, 1, 1, NULL);
1198 ok( ret, "MoveToEx error %d.\n", GetLastError());
1199 ret = LineTo(hdcMetafile, 2, 2);
1200 ok( ret, "LineTo error %d.\n", GetLastError());
1201 ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
1202 ok( ret, "MoveToEx error %d.\n", GetLastError());
1204 /* oldpoint gets garbage under Win XP, so the following test would
1205 * work under Wine but fails under Windows:
1207 * ok((oldpoint.x == 2) && (oldpoint.y == 2),
1208 * "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
1209 * oldpoint.x, oldpoint.y);
1212 ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
1213 ok( ret, "Ellipse error %d.\n", GetLastError());
1215 hMetafile = CloseMetaFile(hdcMetafile);
1216 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1217 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1219 if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
1220 "mf_Graphics") != 0)
1222 dump_mf_bits(hMetafile, "mf_Graphics");
1223 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1226 ret = DeleteMetaFile(hMetafile);
1227 ok( ret, "DeleteMetaFile(%p) error %d\n",
1228 hMetafile, GetLastError());
1231 static void test_mf_PatternBrush(void)
1233 HDC hdcMetafile;
1234 HMETAFILE hMetafile;
1235 LOGBRUSH *orig_lb;
1236 HBRUSH hBrush;
1237 BOOL ret;
1239 orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
1241 orig_lb->lbStyle = BS_PATTERN;
1242 orig_lb->lbColor = RGB(0, 0, 0);
1243 orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
1244 ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
1246 hBrush = CreateBrushIndirect (orig_lb);
1247 ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
1249 hdcMetafile = CreateMetaFileA(NULL);
1250 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
1251 trace("hdcMetafile %p\n", hdcMetafile);
1253 hBrush = SelectObject(hdcMetafile, hBrush);
1254 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
1256 hMetafile = CloseMetaFile(hdcMetafile);
1257 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1258 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1260 if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
1261 "mf_Pattern_Brush") != 0)
1263 dump_mf_bits(hMetafile, "mf_Pattern_Brush");
1264 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1267 ret = DeleteMetaFile(hMetafile);
1268 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
1269 ret = DeleteObject(hBrush);
1270 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
1271 ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
1272 ok( ret, "DeleteObject(HBITMAP) error %d\n",
1273 GetLastError());
1274 HeapFree (GetProcessHeap(), 0, orig_lb);
1277 static void test_mf_ExtTextOut_on_path(void)
1279 HDC hdcMetafile;
1280 HMETAFILE hMetafile;
1281 BOOL ret;
1282 static const INT dx[4] = { 3, 5, 8, 12 };
1284 hdcMetafile = CreateMetaFileA(NULL);
1285 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1286 trace("hdcMetafile %p\n", hdcMetafile);
1288 ret = BeginPath(hdcMetafile);
1289 ok(!ret, "BeginPath on metafile DC should fail\n");
1291 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1292 ok(ret, "ExtTextOut error %d\n", GetLastError());
1294 ret = EndPath(hdcMetafile);
1295 ok(!ret, "EndPath on metafile DC should fail\n");
1297 hMetafile = CloseMetaFile(hdcMetafile);
1298 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1300 if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
1301 "mf_TextOut_on_path") != 0)
1303 dump_mf_bits(hMetafile, "mf_TextOut_on_path");
1304 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1307 ret = DeleteMetaFile(hMetafile);
1308 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1311 static void test_emf_ExtTextOut_on_path(void)
1313 HWND hwnd;
1314 HDC hdcDisplay, hdcMetafile;
1315 HENHMETAFILE hMetafile;
1316 BOOL ret;
1317 static const INT dx[4] = { 3, 5, 8, 12 };
1319 /* Win9x doesn't play EMFs on invisible windows */
1320 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1321 0, 0, 200, 200, 0, 0, 0, NULL);
1322 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1324 hdcDisplay = GetDC(hwnd);
1325 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
1327 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
1328 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1330 ret = BeginPath(hdcMetafile);
1331 ok(ret, "BeginPath error %d\n", GetLastError());
1333 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1334 ok(ret, "ExtTextOut error %d\n", GetLastError());
1336 ret = EndPath(hdcMetafile);
1337 ok(ret, "EndPath error %d\n", GetLastError());
1339 hMetafile = CloseEnhMetaFile(hdcMetafile);
1340 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1342 /* this doesn't succeed yet: EMF has correct size, all EMF records
1343 * are there, but their contents don't match for different reasons.
1345 if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
1346 "emf_TextOut_on_path", TRUE) != 0)
1348 dump_emf_bits(hMetafile, "emf_TextOut_on_path");
1349 dump_emf_records(hMetafile, "emf_TextOut_on_path");
1352 ret = DeleteEnhMetaFile(hMetafile);
1353 ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
1354 ret = ReleaseDC(hwnd, hdcDisplay);
1355 ok(ret, "ReleaseDC error %d\n", GetLastError());
1356 DestroyWindow(hwnd);
1359 static const unsigned char EMF_CLIPPING[] =
1361 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1363 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1365 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
1366 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1367 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1368 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1370 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1371 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1372 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1373 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1374 0xe0, 0x93, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
1375 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1376 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
1377 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1378 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1379 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1380 0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1381 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1382 0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1383 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1384 0x00, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1385 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1386 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1389 static void translate( POINT *pt, UINT count, const XFORM *xform )
1391 while (count--)
1393 FLOAT x = (FLOAT)pt->x;
1394 FLOAT y = (FLOAT)pt->y;
1395 pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
1396 pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
1397 pt++;
1401 static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
1402 const ENHMETARECORD *emr, int n_objs, LPARAM param)
1404 if (emr->iType == EMR_EXTSELECTCLIPRGN)
1406 const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
1407 union _rgn
1409 RGNDATA data;
1410 char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
1412 const union _rgn *rgn1;
1413 union _rgn rgn2;
1414 RECT rect, rc_transformed;
1415 const RECT *rc = (const RECT *)param;
1416 HRGN hrgn;
1417 XFORM xform;
1418 INT ret;
1419 BOOL is_win9x;
1421 trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
1422 clip->cbRgnData, clip->iMode);
1424 ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
1425 ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
1426 "too small data block: %u bytes\n", clip->cbRgnData);
1427 if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
1428 return 0;
1430 rgn1 = (const union _rgn *)clip->RgnData;
1432 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1433 rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
1434 rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
1435 rgn1->data.rdh.rcBound.left, rgn1->data.rdh.rcBound.top,
1436 rgn1->data.rdh.rcBound.right, rgn1->data.rdh.rcBound.bottom);
1438 ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
1440 rect = *(const RECT *)rgn1->data.Buffer;
1441 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1442 ok(EqualRect(&rect, rc), "rects don't match\n");
1444 ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u", rgn1->data.rdh.dwSize);
1445 ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
1446 ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
1447 ok(rgn1->data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
1449 hrgn = CreateRectRgn(0, 0, 0, 0);
1451 memset(&xform, 0, sizeof(xform));
1452 SetLastError(0xdeadbeef);
1453 ret = GetWorldTransform(hdc, &xform);
1454 is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1455 if (!is_win9x)
1456 ok(ret, "GetWorldTransform error %u\n", GetLastError());
1458 trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
1460 ret = GetClipRgn(hdc, hrgn);
1461 ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
1463 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
1465 ret = GetClipRgn(hdc, hrgn);
1466 ok(ret == 1, "GetClipRgn returned %d, expected 0\n", ret);
1468 /* Win9x returns empty clipping region */
1469 if (is_win9x) return 1;
1471 ret = GetRegionData(hrgn, 0, NULL);
1472 ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
1474 ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
1476 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1477 rgn2.data.rdh.dwSize, rgn2.data.rdh.iType,
1478 rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
1479 rgn2.data.rdh.rcBound.left, rgn2.data.rdh.rcBound.top,
1480 rgn2.data.rdh.rcBound.right, rgn2.data.rdh.rcBound.bottom);
1482 rect = rgn2.data.rdh.rcBound;
1483 rc_transformed = *rc;
1484 translate((POINT *)&rc_transformed, 2, &xform);
1485 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1486 rc_transformed.right, rc_transformed.bottom);
1487 ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
1489 rect = *(const RECT *)rgn2.data.Buffer;
1490 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1491 rc_transformed = *rc;
1492 translate((POINT *)&rc_transformed, 2, &xform);
1493 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1494 rc_transformed.right, rc_transformed.bottom);
1495 ok(EqualRect(&rect, &rc_transformed), "rects don't match\n");
1497 ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u", rgn2.data.rdh.dwSize);
1498 ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
1499 ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
1500 ok(rgn2.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
1502 DeleteObject(hrgn);
1504 return 1;
1507 static void test_emf_clipping(void)
1509 static const RECT rc = { 0, 0, 100, 100 };
1510 RECT rc_clip = { 100, 100, 1024, 1024 };
1511 HWND hwnd;
1512 HDC hdc;
1513 HENHMETAFILE hemf;
1514 HRGN hrgn;
1515 INT ret;
1517 SetLastError(0xdeadbeef);
1518 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1519 ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1521 /* Need to write something to the emf, otherwise Windows won't play it back */
1522 LineTo(hdc, 1, 1);
1524 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
1525 ret = SelectClipRgn(hdc, hrgn);
1526 ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
1528 SetLastError(0xdeadbeef);
1529 hemf = CloseEnhMetaFile(hdc);
1530 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1532 if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
1533 "emf_clipping", TRUE) != 0)
1535 dump_emf_bits(hemf, "emf_clipping");
1536 dump_emf_records(hemf, "emf_clipping");
1539 DeleteObject(hrgn);
1541 /* Win9x doesn't play EMFs on invisible windows */
1542 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1543 0, 0, 200, 200, 0, 0, 0, NULL);
1544 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1546 hdc = GetDC(hwnd);
1548 ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
1549 ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
1551 DeleteEnhMetaFile(hemf);
1552 ReleaseDC(hwnd, hdc);
1553 DestroyWindow(hwnd);
1556 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
1558 LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
1559 POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
1560 /* When using MM_TEXT Win9x does not update the mapping mode
1561 * until a record is played which actually outputs something */
1562 PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
1563 LPtoDP(hdc, mapping, 2);
1564 trace("Meta record: iType %d, nSize %d, (%d,%d)-(%d,%d)\n",
1565 lpEMFR->iType, lpEMFR->nSize,
1566 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
1568 if (lpEMFR->iType == EMR_LINETO)
1570 INT x0, y0, x1, y1;
1571 if (!lpMFP || lpMFP->mm == MM_TEXT)
1573 x0 = 0;
1574 y0 = 0;
1575 x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
1576 y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
1578 else
1580 ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
1582 x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1583 y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1584 x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1585 y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1587 ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
1588 "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
1589 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
1590 x0, y0, x1, y1);
1592 return TRUE;
1595 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
1597 HDC hdcMf;
1598 HMETAFILE hmf;
1599 BOOL ret;
1600 UINT size;
1601 LPBYTE pBits;
1603 hdcMf = CreateMetaFile(NULL);
1604 ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
1605 ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
1606 ok(ret, "LineTo failed with error %d\n", GetLastError());
1607 hmf = CloseMetaFile(hdcMf);
1608 ok(hmf != NULL, "CloseMetaFile failed with error %d\n", GetLastError());
1610 if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
1612 dump_mf_bits(hmf, "mf_LineTo");
1613 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1616 size = GetMetaFileBitsEx(hmf, 0, NULL);
1617 ok(size, "GetMetaFileBitsEx failed with error %d\n", GetLastError());
1618 pBits = HeapAlloc(GetProcessHeap(), 0, size);
1619 GetMetaFileBitsEx(hmf, size, pBits);
1620 DeleteMetaFile(hmf);
1621 return SetWinMetaFileBits(size, pBits, NULL, mfp);
1624 static void test_mf_conversions(void)
1626 trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
1628 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1629 HENHMETAFILE hemf;
1630 METAFILEPICT mfp;
1631 RECT rect = { 0, 0, 100, 100 };
1632 mfp.mm = MM_ANISOTROPIC;
1633 mfp.xExt = 100;
1634 mfp.yExt = 100;
1635 mfp.hMF = NULL;
1636 hemf = create_converted_emf(&mfp);
1638 if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
1639 "emf_LineTo MM_ANISOTROPIC", TRUE) != 0)
1641 dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
1642 dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
1645 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1647 DeleteEnhMetaFile(hemf);
1648 DeleteDC(hdcOffscreen);
1651 trace("Testing MF->EMF conversion (MM_TEXT)\n");
1653 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1654 HENHMETAFILE hemf;
1655 METAFILEPICT mfp;
1656 RECT rect = { 0, 0, 100, 100 };
1657 mfp.mm = MM_TEXT;
1658 mfp.xExt = 0;
1659 mfp.yExt = 0;
1660 mfp.hMF = NULL;
1661 hemf = create_converted_emf(&mfp);
1663 if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
1664 "emf_LineTo MM_TEXT", TRUE) != 0)
1666 dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
1667 dump_emf_records(hemf, "emf_LineTo MM_TEXT");
1670 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1672 DeleteEnhMetaFile(hemf);
1673 DeleteDC(hdcOffscreen);
1676 trace("Testing MF->EMF conversion (NULL mfp)\n");
1678 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1679 HENHMETAFILE hemf;
1680 RECT rect = { 0, 0, 100, 100 };
1681 hemf = create_converted_emf(NULL);
1683 if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
1684 "emf_LineTo NULL", TRUE) != 0)
1686 dump_emf_bits(hemf, "emf_LineTo NULL");
1687 dump_emf_records(hemf, "emf_LineTo NULL");
1690 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
1692 DeleteEnhMetaFile(hemf);
1693 DeleteDC(hdcOffscreen);
1697 static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1698 LONG mm, LONG xExt, LONG yExt,
1699 RECTL * rclBounds, RECTL * rclFrame)
1701 METAFILEPICT mfp;
1702 METAFILEPICT * mfpPtr = NULL;
1703 HENHMETAFILE emf;
1704 ENHMETAHEADER header;
1705 UINT res;
1707 if (!mfpIsNull)
1709 mfp.mm = mm;
1710 mfp.xExt = xExt;
1711 mfp.yExt = yExt;
1712 mfpPtr = &mfp;
1715 emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
1716 ok(emf != NULL, "SetWinMetaFileBits failed\n");
1717 if (!emf) return FALSE;
1718 res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
1719 ok(res != 0, "GetEnhMetaHeader failed\n");
1720 DeleteEnhMetaFile(emf);
1721 if (!res) return FALSE;
1723 *rclBounds = header.rclBounds;
1724 *rclFrame = header.rclFrame;
1725 return TRUE;
1728 static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1729 LONG mm, LONG xExt, LONG yExt,
1730 RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
1732 RECTL rclBounds, rclFrame;
1734 if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
1736 const char * msg;
1737 char buf[64];
1739 if (mfpIsNull)
1741 msg = "mfp == NULL";
1743 else
1745 const char * mm_str;
1746 switch (mm)
1748 case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
1749 case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
1750 default: mm_str = "Unexpected";
1752 sprintf(buf, "mm=%s, xExt=%d, yExt=%d", mm_str, xExt, yExt);
1753 msg = buf;
1756 ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
1757 ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
1758 ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
1759 ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
1760 ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
1761 ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
1762 ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
1763 ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
1767 static void test_SetWinMetaFileBits(void)
1769 HMETAFILE wmf;
1770 HDC wmfDC;
1771 BYTE * buffer;
1772 UINT buffer_size;
1773 RECT rect;
1774 UINT res;
1775 RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
1776 RECTL rclBoundsIsotropic, rclFrameIsotropic;
1777 RECTL rclBounds, rclFrame;
1778 HDC dc;
1779 LONG diffx, diffy;
1781 wmfDC = CreateMetaFile(NULL);
1782 ok(wmfDC != NULL, "CreateMetaFile failed\n");
1783 if (!wmfDC) return;
1785 SetWindowExtEx(wmfDC, 100, 100, NULL);
1786 rect.left = rect.top = 0;
1787 rect.right = rect.bottom = 50;
1788 FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
1789 wmf = CloseMetaFile(wmfDC);
1790 ok(wmf != NULL, "Metafile creation failed\n");
1791 if (!wmf) return;
1793 buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
1794 ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
1795 if (buffer_size == 0)
1797 DeleteMetaFile(wmf);
1798 return;
1801 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
1802 ok(buffer != NULL, "HeapAlloc failed\n");
1803 if (!buffer)
1805 DeleteMetaFile(wmf);
1806 return;
1809 res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
1810 ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
1811 DeleteMetaFile(wmf);
1812 if (res != buffer_size)
1814 HeapFree(GetProcessHeap(), 0, buffer);
1815 return;
1818 /* Get the reference bounds and frame */
1819 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1820 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1822 ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
1823 rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
1824 "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
1826 ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
1827 ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
1828 diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
1829 if (diffx < 0) diffx = -diffx;
1830 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
1832 dc = CreateCompatibleDC(NULL);
1833 todo_wine
1835 ok(rclBoundsAnisotropic.right == GetDeviceCaps(dc, HORZRES) / 2 - 1 &&
1836 rclBoundsAnisotropic.bottom == GetDeviceCaps(dc, VERTRES) / 2 - 1,
1837 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
1838 GetDeviceCaps(dc, HORZRES) / 2 - 1, GetDeviceCaps(dc, VERTRES) / 2 - 1, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
1841 /* Allow 1 mm difference (rounding errors) */
1842 diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
1843 diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
1844 if (diffx < 0) diffx = -diffx;
1845 if (diffy < 0) diffy = -diffy;
1846 todo_wine
1848 ok(diffx <= 1 && diffy <= 1,
1849 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
1850 GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
1852 DeleteDC(dc);
1854 /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
1855 checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1857 /* If xExt or yExt is zero or negative, the whole device surface is used */
1858 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1859 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1860 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1861 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1862 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1863 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1864 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1865 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1866 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1867 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1868 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1869 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
1871 /* MSDN says that negative xExt and yExt values specify a ratio.
1872 Check that this is wrong and the whole device surface is used */
1873 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1874 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
1876 /* Ordinary conversions */
1878 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
1880 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
1881 "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
1882 ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
1883 "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
1886 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
1888 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
1889 "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
1890 ok(rclBounds.left == 0 && rclBounds.top == 0,
1891 "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
1893 /* Wine has a rounding error */
1894 diffx = rclBounds.right - rclBounds.bottom;
1895 if (diffx < 0) diffx = -diffx;
1896 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
1899 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
1901 ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
1902 "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
1905 HeapFree(GetProcessHeap(), 0, buffer);
1908 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
1909 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
1910 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
1912 static void test_gdiis(void)
1914 RECT rect = {0,0,100,100};
1915 HDC hdc, hemfDC, hmfDC;
1916 HENHMETAFILE hemf;
1917 HMODULE hgdi32;
1919 /* resolve all the functions */
1920 hgdi32 = GetModuleHandle("gdi32");
1921 pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
1922 pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
1923 pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
1925 /* they should all exist or none should exist */
1926 if(!pGdiIsMetaPrintDC)
1927 return;
1929 /* try with nothing */
1930 ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
1931 ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
1932 ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
1934 /* try with a metafile */
1935 hmfDC = CreateMetaFile(NULL);
1936 ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
1937 ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
1938 ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
1939 DeleteMetaFile(CloseMetaFile(hmfDC));
1941 /* try with an enhanced metafile */
1942 hdc = GetDC(NULL);
1943 hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
1944 ok(hemfDC != NULL, "failed to create emf\n");
1946 ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
1947 ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
1948 ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
1950 hemf = CloseEnhMetaFile(hemfDC);
1951 ok(hemf != NULL, "failed to close EMF\n");
1952 DeleteEnhMetaFile(hemf);
1953 ReleaseDC(NULL,hdc);
1956 static void test_SetEnhMetaFileBits(void)
1958 BYTE data[256];
1959 HENHMETAFILE hemf;
1960 ENHMETAHEADER *emh;
1962 memset(data, 0xAA, sizeof(data));
1963 SetLastError(0xdeadbeef);
1964 hemf = SetEnhMetaFileBits(sizeof(data), data);
1965 ok(!hemf, "SetEnhMetaFileBits should fail\n");
1966 ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA, got %u\n", GetLastError());
1968 emh = (ENHMETAHEADER *)data;
1969 memset(emh, 0, sizeof(*emh));
1971 emh->iType = EMR_HEADER;
1972 emh->nSize = sizeof(*emh);
1973 emh->dSignature = ENHMETA_SIGNATURE;
1974 /* emh->nVersion = 0x10000; XP doesn't care about version */
1975 emh->nBytes = sizeof(*emh);
1976 /* emh->nRecords = 1; XP doesn't care about records */
1977 emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
1979 SetLastError(0xdeadbeef);
1980 hemf = SetEnhMetaFileBits(emh->nBytes, data);
1981 ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
1982 DeleteEnhMetaFile(hemf);
1984 /* XP refuses to load unaligned EMF */
1985 emh->nBytes++;
1986 SetLastError(0xdeadbeef);
1987 hemf = SetEnhMetaFileBits(emh->nBytes, data);
1988 ok(!hemf, "SetEnhMetaFileBits should fail\n");
1989 /* XP doesn't set error in this case */
1991 emh->dSignature = 0;
1992 emh->nBytes--;
1993 SetLastError(0xdeadbeef);
1994 hemf = SetEnhMetaFileBits(emh->nBytes, data);
1995 ok(!hemf, "SetEnhMetaFileBits should fail\n");
1996 /* XP doesn't set error in this case */
1999 START_TEST(metafile)
2001 init_function_pointers();
2003 /* For enhanced metafiles (enhmfdrv) */
2004 test_ExtTextOut();
2005 test_SaveDC();
2007 /* For win-format metafiles (mfdrv) */
2008 test_mf_Blank();
2009 test_mf_Graphics();
2010 test_mf_PatternBrush();
2011 test_CopyMetaFile();
2012 test_SetMetaFileBits();
2013 test_mf_ExtTextOut_on_path();
2014 test_emf_ExtTextOut_on_path();
2015 test_emf_clipping();
2017 /* For metafile conversions */
2018 test_mf_conversions();
2019 test_SetWinMetaFileBits();
2021 test_gdiis();
2022 test_SetEnhMetaFileBits();