push 9eb9af089d68d39110a91889d3a673043db63c4b
[wine/hacks.git] / dlls / gdi32 / tests / metafile.c
blob85bc5290abee397128aa2b4c2cb2c770af7829f9
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 static void dump_emf_record(const ENHMETARECORD *emr, const char *desc)
958 const BYTE *buf;
959 DWORD i;
961 if (!winetest_debug) return;
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++)
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 (", ");
975 printf ("};\n");
978 static void dump_EMREXTTEXTOUT(const EMREXTTEXTOUTW *eto)
980 trace("rclBounds %d,%d - %d,%d\n", eto->rclBounds.left, eto->rclBounds.top,
981 eto->rclBounds.right, eto->rclBounds.bottom);
982 trace("iGraphicsMode %u\n", eto->iGraphicsMode);
983 trace("exScale: %f\n", eto->exScale);
984 trace("eyScale: %f\n", eto->eyScale);
985 trace("emrtext.ptlReference %d,%d\n", eto->emrtext.ptlReference.x, eto->emrtext.ptlReference.y);
986 trace("emrtext.nChars %u\n", eto->emrtext.nChars);
987 trace("emrtext.offString %#x\n", eto->emrtext.offString);
988 trace("emrtext.fOptions %#x\n", eto->emrtext.fOptions);
989 trace("emrtext.rcl %d,%d - %d,%d\n", eto->emrtext.rcl.left, eto->emrtext.rcl.top,
990 eto->emrtext.rcl.right, eto->emrtext.rcl.bottom);
991 trace("emrtext.offDx %#x\n", eto->emrtext.offDx);
994 static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2,
995 const char *desc, BOOL ignore_scaling, BOOL todo)
997 int diff;
999 if (emr1->iType != emr2->iType && todo)
1001 todo_wine
1003 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
1004 desc, emr1->iType, emr2->iType);
1007 else
1008 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
1009 desc, emr1->iType, emr2->iType);
1011 if (emr1->nSize != emr2->nSize && todo)
1013 todo_wine
1015 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1016 desc, emr1->nSize, emr2->nSize);
1019 else
1020 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1021 desc, emr1->nSize, emr2->nSize);
1023 /* iType and nSize mismatches are fatal */
1024 if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE;
1026 /* contents of EMR_GDICOMMENT are not interesting */
1027 if (emr1->iType == EMR_GDICOMMENT) return TRUE;
1029 /* different Windows versions setup DC scaling differently when
1030 * converting an old style metafile to an EMF.
1032 if (ignore_scaling && (emr1->iType == EMR_SETWINDOWEXTEX ||
1033 emr1->iType == EMR_SETVIEWPORTEXTEX))
1034 return TRUE;
1036 if (emr1->iType == EMR_EXTTEXTOUTW || emr1->iType == EMR_EXTTEXTOUTA)
1038 EMREXTTEXTOUTW *eto1, *eto2;
1040 eto1 = HeapAlloc(GetProcessHeap(), 0, emr1->nSize);
1041 memcpy(eto1, emr1, emr1->nSize);
1042 eto2 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1043 memcpy(eto2, emr2, emr2->nSize);
1045 /* different Windows versions setup DC scaling differently */
1046 eto1->exScale = eto1->eyScale = 0.0;
1047 eto2->exScale = eto2->eyScale = 0.0;
1049 diff = memcmp(eto1, eto2, emr1->nSize);
1050 if (diff)
1052 dump_EMREXTTEXTOUT(eto1);
1053 dump_EMREXTTEXTOUT(eto2);
1055 HeapFree(GetProcessHeap(), 0, eto1);
1056 HeapFree(GetProcessHeap(), 0, eto2);
1058 else
1059 diff = memcmp(emr1, emr2, emr1->nSize);
1060 if (diff && todo)
1062 todo_wine
1063 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1065 else
1066 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1068 if (diff)
1070 dump_emf_record(emr1, "expected bits");
1071 dump_emf_record(emr2, "actual bits");
1074 return diff == 0 || todo; /* report all non-fatal record mismatches */
1077 /* Compare the EMF produced by a test function with the
1078 * expected raw EMF data in "bits".
1079 * Return value is 0 for a perfect match,
1080 * -1 if lengths aren't equal,
1081 * otherwise returns the number of non-matching bytes.
1083 static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
1084 UINT bsize, const char *desc,
1085 BOOL ignore_scaling, BOOL todo)
1087 unsigned char buf[MF_BUFSIZE];
1088 UINT mfsize, offset;
1089 const ENHMETAHEADER *emh1, *emh2;
1091 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1092 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1094 if (mfsize < MF_BUFSIZE)
1096 if (mfsize != bsize && todo)
1098 todo_wine
1099 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1101 else
1102 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1104 else
1105 ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
1106 desc, mfsize, bsize);
1108 /* basic things must match */
1109 emh1 = (const ENHMETAHEADER *)bits;
1110 emh2 = (const ENHMETAHEADER *)buf;
1111 ok(emh1->iType == EMR_HEADER, "expected EMR_HEADER, got %u\n", emh1->iType);
1112 ok(emh1->nSize == sizeof(ENHMETAHEADER), "expected sizeof(ENHMETAHEADER), got %u\n", emh1->nSize);
1113 ok(emh2->nBytes == mfsize, "expected emh->nBytes %u, got %u\n", mfsize, emh2->nBytes);
1114 ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature);
1116 ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType);
1117 ok(emh1->nSize == emh2->nSize, "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
1118 ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
1119 if (todo && emh1->nBytes != emh2->nBytes)
1121 todo_wine
1122 ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1124 else
1125 ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1126 if (todo && emh1->nRecords != emh2->nRecords)
1128 todo_wine
1129 ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
1131 else
1132 ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
1134 offset = emh1->nSize;
1135 while (offset < emh1->nBytes)
1137 const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset);
1138 const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset);
1140 trace("EMF record %u, size %u/record %u, size %u\n",
1141 emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
1143 if (!match_emf_record(emr1, emr2, desc, ignore_scaling, todo)) return -1;
1145 offset += emr1->nSize;
1147 return 0;
1150 /* Test a blank metafile. May be used as a template for new tests. */
1152 static void test_mf_Blank(void)
1154 HDC hdcMetafile;
1155 HMETAFILE hMetafile;
1156 INT caps;
1157 BOOL ret;
1158 INT type;
1160 hdcMetafile = CreateMetaFileA(NULL);
1161 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1162 trace("hdcMetafile %p\n", hdcMetafile);
1164 /* Tests on metafile initialization */
1165 caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
1166 ok (caps == DT_METAFILE,
1167 "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
1169 hMetafile = CloseMetaFile(hdcMetafile);
1170 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1171 type = GetObjectType(hMetafile);
1172 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1173 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1175 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1176 "mf_blank") != 0)
1178 dump_mf_bits(hMetafile, "mf_Blank");
1179 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1182 ret = DeleteMetaFile(hMetafile);
1183 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1186 static void test_CopyMetaFile(void)
1188 HDC hdcMetafile;
1189 HMETAFILE hMetafile, hmf_copy;
1190 BOOL ret;
1191 char temp_path[MAX_PATH];
1192 char mf_name[MAX_PATH];
1193 INT type;
1195 hdcMetafile = CreateMetaFileA(NULL);
1196 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1197 trace("hdcMetafile %p\n", hdcMetafile);
1199 hMetafile = CloseMetaFile(hdcMetafile);
1200 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1201 type = GetObjectType(hMetafile);
1202 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1204 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1205 "mf_blank") != 0)
1207 dump_mf_bits(hMetafile, "mf_Blank");
1208 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1211 GetTempPathA(MAX_PATH, temp_path);
1212 GetTempFileNameA(temp_path, "wmf", 0, mf_name);
1214 hmf_copy = CopyMetaFileA(hMetafile, mf_name);
1215 ok(hmf_copy != 0, "CopyMetaFile error %d\n", GetLastError());
1217 type = GetObjectType(hmf_copy);
1218 ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
1220 ret = DeleteMetaFile(hMetafile);
1221 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1223 if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
1225 dump_mf_bits(hMetafile, "mf_Blank");
1226 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1229 ret = DeleteMetaFile(hmf_copy);
1230 ok( ret, "DeleteMetaFile(%p) error %d\n", hmf_copy, GetLastError());
1232 DeleteFileA(mf_name);
1235 static void test_SetMetaFileBits(void)
1237 HMETAFILE hmf;
1238 INT type;
1239 BOOL ret;
1240 BYTE buf[256];
1241 METAHEADER *mh;
1243 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
1244 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1245 type = GetObjectType(hmf);
1246 ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
1248 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1250 dump_mf_bits(hmf, "mf_Graphics");
1251 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1254 ret = DeleteMetaFile(hmf);
1255 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1257 /* NULL data crashes XP SP1 */
1258 /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
1260 /* Now with not zero size */
1261 SetLastError(0xdeadbeef);
1262 hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
1263 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1264 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1266 /* Now with not even size */
1267 SetLastError(0xdeadbeef);
1268 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
1269 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1270 ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
1272 /* Now with zeroed out or faked some header fields */
1273 assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
1274 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1275 mh = (METAHEADER *)buf;
1276 /* corruption of any of the below fields leads to a failure */
1277 mh->mtType = 0;
1278 mh->mtVersion = 0;
1279 mh->mtHeaderSize = 0;
1280 SetLastError(0xdeadbeef);
1281 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1282 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1283 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1285 /* Now with corrupted mtSize field */
1286 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1287 mh = (METAHEADER *)buf;
1288 /* corruption of mtSize doesn't lead to a failure */
1289 mh->mtSize *= 2;
1290 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1291 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1293 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1295 dump_mf_bits(hmf, "mf_Graphics");
1296 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1299 ret = DeleteMetaFile(hmf);
1300 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1302 /* Now with zeroed out mtSize field */
1303 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1304 mh = (METAHEADER *)buf;
1305 /* zeroing mtSize doesn't lead to a failure */
1306 mh->mtSize = 0;
1307 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1308 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1310 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1312 dump_mf_bits(hmf, "mf_Graphics");
1313 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1316 ret = DeleteMetaFile(hmf);
1317 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1320 /* Simple APIs from mfdrv/graphics.c
1323 static void test_mf_Graphics(void)
1325 HDC hdcMetafile;
1326 HMETAFILE hMetafile;
1327 POINT oldpoint;
1328 BOOL ret;
1330 hdcMetafile = CreateMetaFileA(NULL);
1331 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1332 trace("hdcMetafile %p\n", hdcMetafile);
1334 ret = MoveToEx(hdcMetafile, 1, 1, NULL);
1335 ok( ret, "MoveToEx error %d.\n", GetLastError());
1336 ret = LineTo(hdcMetafile, 2, 2);
1337 ok( ret, "LineTo error %d.\n", GetLastError());
1338 ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
1339 ok( ret, "MoveToEx error %d.\n", GetLastError());
1341 /* oldpoint gets garbage under Win XP, so the following test would
1342 * work under Wine but fails under Windows:
1344 * ok((oldpoint.x == 2) && (oldpoint.y == 2),
1345 * "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
1346 * oldpoint.x, oldpoint.y);
1349 ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
1350 ok( ret, "Ellipse error %d.\n", GetLastError());
1352 hMetafile = CloseMetaFile(hdcMetafile);
1353 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1354 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1356 if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
1357 "mf_Graphics") != 0)
1359 dump_mf_bits(hMetafile, "mf_Graphics");
1360 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1363 ret = DeleteMetaFile(hMetafile);
1364 ok( ret, "DeleteMetaFile(%p) error %d\n",
1365 hMetafile, GetLastError());
1368 static void test_mf_PatternBrush(void)
1370 HDC hdcMetafile;
1371 HMETAFILE hMetafile;
1372 LOGBRUSH *orig_lb;
1373 HBRUSH hBrush;
1374 BOOL ret;
1376 orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
1378 orig_lb->lbStyle = BS_PATTERN;
1379 orig_lb->lbColor = RGB(0, 0, 0);
1380 orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
1381 ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
1383 hBrush = CreateBrushIndirect (orig_lb);
1384 ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
1386 hdcMetafile = CreateMetaFileA(NULL);
1387 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
1388 trace("hdcMetafile %p\n", hdcMetafile);
1390 hBrush = SelectObject(hdcMetafile, hBrush);
1391 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
1393 hMetafile = CloseMetaFile(hdcMetafile);
1394 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1395 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1397 if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
1398 "mf_Pattern_Brush") != 0)
1400 dump_mf_bits(hMetafile, "mf_Pattern_Brush");
1401 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1404 ret = DeleteMetaFile(hMetafile);
1405 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
1406 ret = DeleteObject(hBrush);
1407 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
1408 ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
1409 ok( ret, "DeleteObject(HBITMAP) error %d\n",
1410 GetLastError());
1411 HeapFree (GetProcessHeap(), 0, orig_lb);
1414 static void test_mf_ExtTextOut_on_path(void)
1416 HDC hdcMetafile;
1417 HMETAFILE hMetafile;
1418 BOOL ret;
1419 static const INT dx[4] = { 3, 5, 8, 12 };
1421 hdcMetafile = CreateMetaFileA(NULL);
1422 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1423 trace("hdcMetafile %p\n", hdcMetafile);
1425 ret = BeginPath(hdcMetafile);
1426 ok(!ret, "BeginPath on metafile DC should fail\n");
1428 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1429 ok(ret, "ExtTextOut error %d\n", GetLastError());
1431 ret = EndPath(hdcMetafile);
1432 ok(!ret, "EndPath on metafile DC should fail\n");
1434 hMetafile = CloseMetaFile(hdcMetafile);
1435 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1437 if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
1438 "mf_TextOut_on_path") != 0)
1440 dump_mf_bits(hMetafile, "mf_TextOut_on_path");
1441 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1444 ret = DeleteMetaFile(hMetafile);
1445 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1448 static void test_emf_ExtTextOut_on_path(void)
1450 HWND hwnd;
1451 HDC hdcDisplay, hdcMetafile;
1452 HENHMETAFILE hMetafile;
1453 BOOL ret;
1454 static const INT dx[4] = { 3, 5, 8, 12 };
1456 /* Win9x doesn't play EMFs on invisible windows */
1457 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1458 0, 0, 200, 200, 0, 0, 0, NULL);
1459 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1461 hdcDisplay = GetDC(hwnd);
1462 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
1464 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
1465 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1467 ret = BeginPath(hdcMetafile);
1468 ok(ret, "BeginPath error %d\n", GetLastError());
1470 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1471 ok(ret, "ExtTextOut error %d\n", GetLastError());
1473 ret = EndPath(hdcMetafile);
1474 ok(ret, "EndPath error %d\n", GetLastError());
1476 hMetafile = CloseEnhMetaFile(hdcMetafile);
1477 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1479 /* this doesn't succeed yet: EMF has correct size, all EMF records
1480 * are there, but their contents don't match for different reasons.
1482 if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
1483 "emf_TextOut_on_path", FALSE, FALSE) != 0)
1485 dump_emf_bits(hMetafile, "emf_TextOut_on_path");
1486 dump_emf_records(hMetafile, "emf_TextOut_on_path");
1489 ret = DeleteEnhMetaFile(hMetafile);
1490 ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
1491 ret = ReleaseDC(hwnd, hdcDisplay);
1492 ok(ret, "ReleaseDC error %d\n", GetLastError());
1493 DestroyWindow(hwnd);
1496 static const unsigned char EMF_CLIPPING[] =
1498 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1500 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1502 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
1503 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1504 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1505 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1507 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1508 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1510 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1511 0xe0, 0x93, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
1512 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1513 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
1514 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1515 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1516 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1517 0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1518 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1519 0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1520 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1521 0x00, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1522 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1523 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1526 static void translate( POINT *pt, UINT count, const XFORM *xform )
1528 while (count--)
1530 FLOAT x = (FLOAT)pt->x;
1531 FLOAT y = (FLOAT)pt->y;
1532 pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
1533 pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
1534 pt++;
1538 /* Compare rectangles allowing rounding errors */
1539 static BOOL is_equal_rect(const RECT *rc1, const RECT *rc2)
1541 return abs(rc1->left - rc2->left) <= 1 &&
1542 abs(rc1->top - rc2->top) <= 1 &&
1543 abs(rc1->right - rc2->right) <= 1 &&
1544 abs(rc1->bottom - rc2->bottom) <= 1;
1547 static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
1548 const ENHMETARECORD *emr, int n_objs, LPARAM param)
1550 if (emr->iType == EMR_EXTSELECTCLIPRGN)
1552 const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
1553 union _rgn
1555 RGNDATA data;
1556 char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
1558 const union _rgn *rgn1;
1559 union _rgn rgn2;
1560 RECT rect, rc_transformed;
1561 const RECT *rc = (const RECT *)param;
1562 HRGN hrgn;
1563 XFORM xform;
1564 INT ret;
1565 BOOL is_win9x;
1567 trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
1568 clip->cbRgnData, clip->iMode);
1570 ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
1571 ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
1572 "too small data block: %u bytes\n", clip->cbRgnData);
1573 if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
1574 return 0;
1576 rgn1 = (const union _rgn *)clip->RgnData;
1578 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1579 rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
1580 rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
1581 rgn1->data.rdh.rcBound.left, rgn1->data.rdh.rcBound.top,
1582 rgn1->data.rdh.rcBound.right, rgn1->data.rdh.rcBound.bottom);
1584 ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
1586 rect = *(const RECT *)rgn1->data.Buffer;
1587 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1588 ok(EqualRect(&rect, rc), "rects don't match\n");
1590 ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize);
1591 ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
1592 ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
1593 ok(rgn1->data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
1595 hrgn = CreateRectRgn(0, 0, 0, 0);
1597 memset(&xform, 0, sizeof(xform));
1598 SetLastError(0xdeadbeef);
1599 ret = GetWorldTransform(hdc, &xform);
1600 is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1601 if (!is_win9x)
1602 ok(ret, "GetWorldTransform error %u\n", GetLastError());
1604 trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
1606 ret = GetClipRgn(hdc, hrgn);
1607 ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
1609 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
1611 ret = GetClipRgn(hdc, hrgn);
1612 ok(ret == 1, "GetClipRgn returned %d, expected 0\n", ret);
1614 /* Win9x returns empty clipping region */
1615 if (is_win9x) return 1;
1617 ret = GetRegionData(hrgn, 0, NULL);
1618 ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
1620 ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
1622 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1623 rgn2.data.rdh.dwSize, rgn2.data.rdh.iType,
1624 rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
1625 rgn2.data.rdh.rcBound.left, rgn2.data.rdh.rcBound.top,
1626 rgn2.data.rdh.rcBound.right, rgn2.data.rdh.rcBound.bottom);
1628 rect = rgn2.data.rdh.rcBound;
1629 rc_transformed = *rc;
1630 translate((POINT *)&rc_transformed, 2, &xform);
1631 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1632 rc_transformed.right, rc_transformed.bottom);
1633 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
1635 rect = *(const RECT *)rgn2.data.Buffer;
1636 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1637 rc_transformed = *rc;
1638 translate((POINT *)&rc_transformed, 2, &xform);
1639 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1640 rc_transformed.right, rc_transformed.bottom);
1641 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
1643 ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize);
1644 ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
1645 ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
1646 ok(rgn2.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
1648 DeleteObject(hrgn);
1650 return 1;
1653 static void test_emf_clipping(void)
1655 static const RECT rc = { 0, 0, 100, 100 };
1656 RECT rc_clip = { 100, 100, 1024, 1024 };
1657 HWND hwnd;
1658 HDC hdc;
1659 HENHMETAFILE hemf;
1660 HRGN hrgn;
1661 INT ret;
1663 SetLastError(0xdeadbeef);
1664 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1665 ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1667 /* Need to write something to the emf, otherwise Windows won't play it back */
1668 LineTo(hdc, 1, 1);
1670 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
1671 ret = SelectClipRgn(hdc, hrgn);
1672 ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
1674 SetLastError(0xdeadbeef);
1675 hemf = CloseEnhMetaFile(hdc);
1676 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1678 if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
1679 "emf_clipping", FALSE, FALSE) != 0)
1681 dump_emf_bits(hemf, "emf_clipping");
1682 dump_emf_records(hemf, "emf_clipping");
1685 DeleteObject(hrgn);
1687 /* Win9x doesn't play EMFs on invisible windows */
1688 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1689 0, 0, 200, 200, 0, 0, 0, NULL);
1690 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1692 hdc = GetDC(hwnd);
1694 ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
1695 ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
1697 DeleteEnhMetaFile(hemf);
1698 ReleaseDC(hwnd, hdc);
1699 DestroyWindow(hwnd);
1702 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
1704 LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
1705 POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
1706 /* When using MM_TEXT Win9x does not update the mapping mode
1707 * until a record is played which actually outputs something */
1708 PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
1709 LPtoDP(hdc, mapping, 2);
1710 trace("EMF record: iType %d, nSize %d, (%d,%d)-(%d,%d)\n",
1711 lpEMFR->iType, lpEMFR->nSize,
1712 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
1714 if (lpEMFR->iType == EMR_LINETO)
1716 INT x0, y0, x1, y1;
1717 if (!lpMFP || lpMFP->mm == MM_TEXT)
1719 x0 = 0;
1720 y0 = 0;
1721 x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
1722 y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
1724 else
1726 ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
1728 x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1729 y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1730 x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1731 y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1733 ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
1734 "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
1735 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
1736 x0, y0, x1, y1);
1738 return TRUE;
1741 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
1743 HDC hdcMf;
1744 HMETAFILE hmf;
1745 HENHMETAFILE hemf;
1746 BOOL ret;
1747 UINT size;
1748 LPBYTE pBits;
1750 hdcMf = CreateMetaFile(NULL);
1751 ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
1752 ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
1753 ok(ret, "LineTo failed with error %d\n", GetLastError());
1754 hmf = CloseMetaFile(hdcMf);
1755 ok(hmf != NULL, "CloseMetaFile failed with error %d\n", GetLastError());
1757 if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
1759 dump_mf_bits(hmf, "mf_LineTo");
1760 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1763 size = GetMetaFileBitsEx(hmf, 0, NULL);
1764 ok(size, "GetMetaFileBitsEx failed with error %d\n", GetLastError());
1765 pBits = HeapAlloc(GetProcessHeap(), 0, size);
1766 GetMetaFileBitsEx(hmf, size, pBits);
1767 DeleteMetaFile(hmf);
1768 hemf = SetWinMetaFileBits(size, pBits, NULL, mfp);
1769 HeapFree(GetProcessHeap(), 0, pBits);
1770 return hemf;
1773 static void test_mf_conversions(void)
1775 trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
1777 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1778 HENHMETAFILE hemf;
1779 METAFILEPICT mfp;
1780 RECT rect = { 0, 0, 100, 100 };
1781 mfp.mm = MM_ANISOTROPIC;
1782 mfp.xExt = 100;
1783 mfp.yExt = 100;
1784 mfp.hMF = NULL;
1785 hemf = create_converted_emf(&mfp);
1787 if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
1788 "emf_LineTo MM_ANISOTROPIC", TRUE, FALSE) != 0)
1790 dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
1791 dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
1794 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1796 DeleteEnhMetaFile(hemf);
1797 DeleteDC(hdcOffscreen);
1800 trace("Testing MF->EMF conversion (MM_TEXT)\n");
1802 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1803 HENHMETAFILE hemf;
1804 METAFILEPICT mfp;
1805 RECT rect = { 0, 0, 100, 100 };
1806 mfp.mm = MM_TEXT;
1807 mfp.xExt = 0;
1808 mfp.yExt = 0;
1809 mfp.hMF = NULL;
1810 hemf = create_converted_emf(&mfp);
1812 if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
1813 "emf_LineTo MM_TEXT", TRUE, FALSE) != 0)
1815 dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
1816 dump_emf_records(hemf, "emf_LineTo MM_TEXT");
1819 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1821 DeleteEnhMetaFile(hemf);
1822 DeleteDC(hdcOffscreen);
1825 trace("Testing MF->EMF conversion (NULL mfp)\n");
1827 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1828 HENHMETAFILE hemf;
1829 RECT rect = { 0, 0, 100, 100 };
1830 hemf = create_converted_emf(NULL);
1832 if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
1833 "emf_LineTo NULL", TRUE, FALSE) != 0)
1835 dump_emf_bits(hemf, "emf_LineTo NULL");
1836 dump_emf_records(hemf, "emf_LineTo NULL");
1839 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
1841 DeleteEnhMetaFile(hemf);
1842 DeleteDC(hdcOffscreen);
1846 static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1847 LONG mm, LONG xExt, LONG yExt,
1848 RECTL * rclBounds, RECTL * rclFrame)
1850 METAFILEPICT mfp;
1851 METAFILEPICT * mfpPtr = NULL;
1852 HENHMETAFILE emf;
1853 ENHMETAHEADER header;
1854 UINT res;
1856 if (!mfpIsNull)
1858 mfp.mm = mm;
1859 mfp.xExt = xExt;
1860 mfp.yExt = yExt;
1861 mfpPtr = &mfp;
1864 emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
1865 ok(emf != NULL, "SetWinMetaFileBits failed\n");
1866 if (!emf) return FALSE;
1867 res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
1868 ok(res != 0, "GetEnhMetaHeader failed\n");
1869 DeleteEnhMetaFile(emf);
1870 if (!res) return FALSE;
1872 *rclBounds = header.rclBounds;
1873 *rclFrame = header.rclFrame;
1874 return TRUE;
1877 static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1878 LONG mm, LONG xExt, LONG yExt,
1879 RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
1881 RECTL rclBounds, rclFrame;
1883 if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
1885 const char * msg;
1886 char buf[64];
1888 if (mfpIsNull)
1890 msg = "mfp == NULL";
1892 else
1894 const char * mm_str;
1895 switch (mm)
1897 case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
1898 case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
1899 default: mm_str = "Unexpected";
1901 sprintf(buf, "mm=%s, xExt=%d, yExt=%d", mm_str, xExt, yExt);
1902 msg = buf;
1905 ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
1906 ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
1907 ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
1908 ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
1909 ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
1910 ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
1911 ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
1912 ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
1916 static void test_SetWinMetaFileBits(void)
1918 HMETAFILE wmf;
1919 HDC wmfDC;
1920 BYTE * buffer;
1921 UINT buffer_size;
1922 RECT rect;
1923 UINT res;
1924 RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
1925 RECTL rclBoundsIsotropic, rclFrameIsotropic;
1926 RECTL rclBounds, rclFrame;
1927 HDC dc;
1928 LONG diffx, diffy;
1930 wmfDC = CreateMetaFile(NULL);
1931 ok(wmfDC != NULL, "CreateMetaFile failed\n");
1932 if (!wmfDC) return;
1934 SetWindowExtEx(wmfDC, 100, 100, NULL);
1935 rect.left = rect.top = 0;
1936 rect.right = rect.bottom = 50;
1937 FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
1938 wmf = CloseMetaFile(wmfDC);
1939 ok(wmf != NULL, "Metafile creation failed\n");
1940 if (!wmf) return;
1942 buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
1943 ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
1944 if (buffer_size == 0)
1946 DeleteMetaFile(wmf);
1947 return;
1950 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
1951 ok(buffer != NULL, "HeapAlloc failed\n");
1952 if (!buffer)
1954 DeleteMetaFile(wmf);
1955 return;
1958 res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
1959 ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
1960 DeleteMetaFile(wmf);
1961 if (res != buffer_size)
1963 HeapFree(GetProcessHeap(), 0, buffer);
1964 return;
1967 /* Get the reference bounds and frame */
1968 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1969 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1971 ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
1972 rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
1973 "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
1975 ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
1976 ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
1977 diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
1978 if (diffx < 0) diffx = -diffx;
1979 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
1981 dc = CreateCompatibleDC(NULL);
1983 /* Allow 1 mm difference (rounding errors) */
1984 diffx = rclBoundsAnisotropic.right - GetDeviceCaps(dc, HORZRES) / 2;
1985 diffy = rclBoundsAnisotropic.bottom - GetDeviceCaps(dc, VERTRES) / 2;
1986 if (diffx < 0) diffx = -diffx;
1987 if (diffy < 0) diffy = -diffy;
1988 todo_wine
1990 ok(diffx <= 1 && diffy <= 1,
1991 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
1992 GetDeviceCaps(dc, HORZRES) / 2, GetDeviceCaps(dc, VERTRES) / 2, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
1995 /* Allow 1 mm difference (rounding errors) */
1996 diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
1997 diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
1998 if (diffx < 0) diffx = -diffx;
1999 if (diffy < 0) diffy = -diffy;
2000 todo_wine
2002 ok(diffx <= 1 && diffy <= 1,
2003 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2004 GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
2006 DeleteDC(dc);
2008 /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
2009 checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2011 /* If xExt or yExt is zero or negative, the whole device surface is used */
2012 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2013 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2014 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2015 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2016 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2017 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2018 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2019 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2020 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2021 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2022 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2023 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2025 /* MSDN says that negative xExt and yExt values specify a ratio.
2026 Check that this is wrong and the whole device surface is used */
2027 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2028 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
2030 /* Ordinary conversions */
2032 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2034 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2035 "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
2036 ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
2037 "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
2040 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2042 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2043 "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
2044 ok(rclBounds.left == 0 && rclBounds.top == 0,
2045 "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
2047 /* Wine has a rounding error */
2048 diffx = rclBounds.right - rclBounds.bottom;
2049 if (diffx < 0) diffx = -diffx;
2050 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
2053 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
2055 ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
2056 "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
2059 HeapFree(GetProcessHeap(), 0, buffer);
2062 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
2063 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
2064 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
2066 static void test_gdiis(void)
2068 RECT rect = {0,0,100,100};
2069 HDC hdc, hemfDC, hmfDC;
2070 HENHMETAFILE hemf;
2071 HMODULE hgdi32;
2073 /* resolve all the functions */
2074 hgdi32 = GetModuleHandle("gdi32");
2075 pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
2076 pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
2077 pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
2079 if(!pGdiIsMetaPrintDC || !pGdiIsMetaFileDC || !pGdiIsPlayMetafileDC)
2081 win_skip("Needed GdiIs* functions are not available\n");
2082 return;
2085 /* try with nothing */
2086 ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
2087 ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
2088 ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
2090 /* try with a metafile */
2091 hmfDC = CreateMetaFile(NULL);
2092 ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
2093 ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
2094 ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
2095 DeleteMetaFile(CloseMetaFile(hmfDC));
2097 /* try with an enhanced metafile */
2098 hdc = GetDC(NULL);
2099 hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
2100 ok(hemfDC != NULL, "failed to create emf\n");
2102 ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
2103 ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
2104 ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
2106 hemf = CloseEnhMetaFile(hemfDC);
2107 ok(hemf != NULL, "failed to close EMF\n");
2108 DeleteEnhMetaFile(hemf);
2109 ReleaseDC(NULL,hdc);
2112 static void test_SetEnhMetaFileBits(void)
2114 BYTE data[256];
2115 HENHMETAFILE hemf;
2116 ENHMETAHEADER *emh;
2118 memset(data, 0xAA, sizeof(data));
2119 SetLastError(0xdeadbeef);
2120 hemf = SetEnhMetaFileBits(sizeof(data), data);
2121 ok(!hemf, "SetEnhMetaFileBits should fail\n");
2122 ok(GetLastError() == ERROR_INVALID_DATA ||
2123 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
2124 "expected ERROR_INVALID_DATA or ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2126 emh = (ENHMETAHEADER *)data;
2127 memset(emh, 0, sizeof(*emh));
2129 emh->iType = EMR_HEADER;
2130 emh->nSize = sizeof(*emh);
2131 emh->dSignature = ENHMETA_SIGNATURE;
2132 /* emh->nVersion = 0x10000; XP doesn't care about version */
2133 emh->nBytes = sizeof(*emh);
2134 /* emh->nRecords = 1; XP doesn't care about records */
2135 emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
2137 SetLastError(0xdeadbeef);
2138 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2139 ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
2140 DeleteEnhMetaFile(hemf);
2142 /* XP refuses to load unaligned EMF */
2143 emh->nBytes++;
2144 SetLastError(0xdeadbeef);
2145 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2146 ok(!hemf ||
2147 broken(hemf != NULL), /* Win9x, WinMe */
2148 "SetEnhMetaFileBits should fail\n");
2149 todo_wine
2150 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2151 DeleteEnhMetaFile(hemf);
2153 emh->dSignature = 0;
2154 emh->nBytes--;
2155 SetLastError(0xdeadbeef);
2156 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2157 ok(!hemf ||
2158 broken(hemf != NULL), /* Win9x, WinMe */
2159 "SetEnhMetaFileBits should fail\n");
2160 todo_wine
2161 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2162 DeleteEnhMetaFile(hemf);
2165 START_TEST(metafile)
2167 init_function_pointers();
2169 /* For enhanced metafiles (enhmfdrv) */
2170 test_ExtTextOut();
2171 test_SaveDC();
2173 /* For win-format metafiles (mfdrv) */
2174 test_mf_Blank();
2175 test_mf_Graphics();
2176 test_mf_PatternBrush();
2177 test_CopyMetaFile();
2178 test_SetMetaFileBits();
2179 test_mf_ExtTextOut_on_path();
2180 test_emf_ExtTextOut_on_path();
2181 test_emf_clipping();
2183 /* For metafile conversions */
2184 test_mf_conversions();
2185 test_SetWinMetaFileBits();
2187 test_gdiis();
2188 test_SetEnhMetaFileBits();