gdi32/tests: Fix a failure on NT4.
[wine/multimedia.git] / dlls / gdi32 / tests / metafile.c
blob21e676788440422a0b52fdda1d7dc7939d8f3e82
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 SetLastError(0xdeadbeef);
125 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
126 ok( ret == sizeof(device_lf) ||
127 broken(ret == (sizeof(device_lf) - LF_FACESIZE + strlen(device_lf.lfFaceName) + 1)), /* NT4 */
128 "GetObjectA error %d\n", GetLastError());
130 /* compare up to lfOutPrecision, other values are not interesting,
131 * and in fact sometimes arbitrary adapted by Win9x.
133 ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
134 ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
136 for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
138 ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
139 n_record, i, dx[i], orig_dx[i]);
141 n_record++;
142 emr_processed = TRUE;
143 break;
146 default:
147 break;
150 return 1;
153 static void test_ExtTextOut(void)
155 HWND hwnd;
156 HDC hdcDisplay, hdcMetafile;
157 HENHMETAFILE hMetafile;
158 HFONT hFont;
159 static const char text[] = "Simple text to test ExtTextOut on metafiles";
160 INT i, len, dx[256];
161 static const RECT rc = { 0, 0, 100, 100 };
162 BOOL ret;
164 assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
166 /* Win9x doesn't play EMFs on invisible windows */
167 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
168 0, 0, 200, 200, 0, 0, 0, NULL);
169 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
171 hdcDisplay = GetDC(hwnd);
172 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
174 trace("hdcDisplay %p\n", hdcDisplay);
176 SetMapMode(hdcDisplay, MM_TEXT);
178 memset(&orig_lf, 0, sizeof(orig_lf));
180 orig_lf.lfCharSet = ANSI_CHARSET;
181 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
182 orig_lf.lfWeight = FW_DONTCARE;
183 orig_lf.lfHeight = 7;
184 orig_lf.lfQuality = DEFAULT_QUALITY;
185 lstrcpyA(orig_lf.lfFaceName, "Arial");
186 hFont = CreateFontIndirectA(&orig_lf);
187 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
189 hFont = SelectObject(hdcDisplay, hFont);
191 len = lstrlenA(text);
192 for (i = 0; i < len; i++)
194 ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
195 ok( ret, "GetCharWidthA error %d\n", GetLastError());
197 hFont = SelectObject(hdcDisplay, hFont);
199 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
200 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
202 trace("hdcMetafile %p\n", hdcMetafile);
204 ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
205 "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
207 hFont = SelectObject(hdcMetafile, hFont);
209 /* 1. pass NULL lpDx */
210 ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
211 ok( ret, "ExtTextOutA error %d\n", GetLastError());
213 /* 2. pass custom lpDx */
214 ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
215 ok( ret, "ExtTextOutA error %d\n", GetLastError());
217 hFont = SelectObject(hdcMetafile, hFont);
218 ret = DeleteObject(hFont);
219 ok( ret, "DeleteObject error %d\n", GetLastError());
221 hMetafile = CloseEnhMetaFile(hdcMetafile);
222 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
224 ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
226 ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
227 ok( ret, "PlayEnhMetaFile error %d\n", GetLastError());
229 SetTextAlign(hdcDisplay, TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING );
230 SetBkColor(hdcDisplay, RGB(0xff, 0, 0));
231 SetTextColor(hdcDisplay, RGB(0, 0xff, 0));
232 SetROP2(hdcDisplay, R2_NOT);
233 SetArcDirection(hdcDisplay, AD_CLOCKWISE);
234 SetPolyFillMode(hdcDisplay, WINDING);
235 SetStretchBltMode(hdcDisplay, HALFTONE);
237 if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
238 SetBkMode(hdcDisplay, OPAQUE);
240 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
241 ok( ret, "EnumEnhMetaFile error %d\n", GetLastError());
243 ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
244 "text align %08x\n", GetTextAlign(hdcDisplay));
245 ok( GetBkColor(hdcDisplay) == RGB(0xff, 0, 0), "bk color %08x\n", GetBkColor(hdcDisplay));
246 ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08x\n", GetTextColor(hdcDisplay));
247 ok( GetROP2(hdcDisplay) == R2_NOT, "rop2 %d\n", GetROP2(hdcDisplay));
248 ok( GetArcDirection(hdcDisplay) == AD_CLOCKWISE, "arc dir %d\n", GetArcDirection(hdcDisplay));
249 ok( GetPolyFillMode(hdcDisplay) == WINDING, "poly fill %d\n", GetPolyFillMode(hdcDisplay));
250 ok( GetStretchBltMode(hdcDisplay) == HALFTONE, "stretchblt mode %d\n", GetStretchBltMode(hdcDisplay));
252 ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
254 ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
255 "A valid hdc has to require a valid rc\n");
257 ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
258 "A null hdc does not require a valid rc\n");
260 ret = DeleteEnhMetaFile(hMetafile);
261 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
262 ret = ReleaseDC(hwnd, hdcDisplay);
263 ok( ret, "ReleaseDC error %d\n", GetLastError());
264 DestroyWindow(hwnd);
267 static void check_dc_state(HDC hdc, int restore_no,
268 int wnd_org_x, int wnd_org_y, int wnd_ext_x, int wnd_ext_y,
269 int vp_org_x, int vp_org_y, int vp_ext_x, int vp_ext_y)
271 BOOL ret;
272 XFORM xform;
273 POINT vp_org, win_org;
274 SIZE vp_size, win_size;
275 FLOAT xscale, yscale, edx, edy;
277 SetLastError(0xdeadbeef);
278 ret = GetWorldTransform(hdc, &xform);
279 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) goto win9x_here;
280 ok(ret, "GetWorldTransform error %u\n", GetLastError());
282 trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
284 ok(xform.eM12 == 0.0, "%d: expected eM12 0.0, got %f\n", restore_no, xform.eM12);
285 ok(xform.eM21 == 0.0, "%d: expected eM21 0.0, got %f\n", restore_no, xform.eM21);
287 xscale = (FLOAT)vp_ext_x / (FLOAT)wnd_ext_x;
288 trace("x scale %f\n", xscale);
289 ok(fabs(xscale - xform.eM11) < 0.01, "%d: vp_ext_x %d, wnd_ext_cx %d, eM11 %f\n",
290 restore_no, vp_ext_x, wnd_ext_x, xform.eM11);
292 yscale = (FLOAT)vp_ext_y / (FLOAT)wnd_ext_y;
293 trace("y scale %f\n", yscale);
294 ok(fabs(yscale - xform.eM22) < 0.01, "%d: vp_ext_y %d, wnd_ext_y %d, eM22 %f\n",
295 restore_no, vp_ext_y, wnd_ext_y, xform.eM22);
297 edx = (FLOAT)vp_org_x - xform.eM11 * (FLOAT)wnd_org_x;
298 ok(fabs(edx - xform.eDx) < 0.01, "%d: edx %f != eDx %f\n", restore_no, edx, xform.eDx);
299 edy = (FLOAT)vp_org_y - xform.eM22 * (FLOAT)wnd_org_y;
300 ok(fabs(edy - xform.eDy) < 0.01, "%d: edy %f != eDy %f\n", restore_no, edy, xform.eDy);
302 return;
304 win9x_here:
306 GetWindowOrgEx(hdc, &win_org);
307 GetViewportOrgEx(hdc, &vp_org);
308 GetWindowExtEx(hdc, &win_size);
309 GetViewportExtEx(hdc, &vp_size);
311 ok(wnd_org_x == win_org.x, "%d: wnd_org_x: %d != %d\n", restore_no, wnd_org_x, win_org.x);
312 ok(wnd_org_y == win_org.y, "%d: wnd_org_y: %d != %d\n", restore_no, wnd_org_y, win_org.y);
314 ok(vp_org_x == vp_org.x, "%d: vport_org_x: %d != %d\n", restore_no, vp_org_x, vp_org.x);
315 ok(vp_org_y == vp_org.y, "%d: vport_org_y: %d != %d\n", restore_no, vp_org_y, vp_org.y);
317 ok(wnd_ext_x == win_size.cx, "%d: wnd_ext_x: %d != %d\n", restore_no, wnd_ext_x, win_size.cx);
318 ok(wnd_ext_y == win_size.cy, "%d: wnd_ext_y: %d != %d\n", restore_no, wnd_ext_y, win_size.cy);
320 ok(vp_ext_x == vp_size.cx, "%d: vport_ext_x: %d != %d\n", restore_no, vp_ext_x, vp_size.cx);
321 ok(vp_ext_y == vp_size.cy, "%d: vport_ext_y: %d != %d\n", restore_no, vp_ext_y, vp_size.cy);
324 static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
325 const ENHMETARECORD *emr, int n_objs, LPARAM param)
327 BOOL ret;
328 XFORM xform;
329 POINT pt;
330 SIZE size;
331 static int save_state;
332 static int restore_no;
334 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
335 hdc, emr->iType, emr->nSize, (void *)param);
337 trace("BEFORE:\n");
338 SetLastError(0xdeadbeef);
339 ret = GetWorldTransform(hdc, &xform);
340 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
342 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
343 trace("window org (%d,%d)\n", pt.x, pt.y);
344 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
345 trace("vport org (%d,%d)\n", pt.x, pt.y);
346 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
347 trace("window ext (%d,%d)\n", size.cx, size.cy);
348 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
349 trace("vport ext (%d,%d)\n", size.cx, size.cy);
351 else
353 ok(ret, "GetWorldTransform error %u\n", GetLastError());
354 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
357 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
359 switch (emr->iType)
361 case EMR_HEADER:
363 static RECT exp_bounds = { 0, 0, 150, 150 };
364 RECT bounds;
365 const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
367 trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
368 emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
369 emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
370 trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
371 emf->szlDevice.cx, emf->szlDevice.cy);
373 SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
374 ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
376 save_state = 0;
377 restore_no = 0;
378 check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
379 break;
382 case EMR_LINETO:
384 const EMRLINETO *line = (const EMRLINETO *)emr;
385 trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
386 break;
388 case EMR_SETWINDOWORGEX:
390 const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
391 trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
392 break;
394 case EMR_SETWINDOWEXTEX:
396 const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
397 trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
398 break;
400 case EMR_SETVIEWPORTORGEX:
402 const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
403 trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
404 break;
406 case EMR_SETVIEWPORTEXTEX:
408 const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
409 trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
410 break;
412 case EMR_SAVEDC:
413 save_state++;
414 trace("EMR_SAVEDC\n");
415 break;
417 case EMR_RESTOREDC:
419 const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
420 trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
422 switch(++restore_no)
424 case 1:
425 ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
426 check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
427 break;
428 case 2:
429 ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
430 check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
431 break;
432 case 3:
433 ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
434 check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
435 break;
437 ok(restore_no <= 3, "restore_no %d\n", restore_no);
438 save_state += restoredc->iRelative;
439 break;
441 case EMR_EOF:
442 ok(save_state == 0, "EOF save_state %d\n", save_state);
443 break;
446 trace("AFTER:\n");
447 SetLastError(0xdeadbeef);
448 ret = GetWorldTransform(hdc, &xform);
449 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
451 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
452 trace("window org (%d,%d)\n", pt.x, pt.y);
453 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
454 trace("vport org (%d,%d)\n", pt.x, pt.y);
455 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
456 trace("window ext (%d,%d)\n", size.cx, size.cy);
457 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
458 trace("vport ext (%d,%d)\n", size.cx, size.cy);
460 else
462 ok(ret, "GetWorldTransform error %u\n", GetLastError());
463 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
466 return 1;
469 static void test_SaveDC(void)
471 HDC hdcMetafile, hdcDisplay;
472 HENHMETAFILE hMetafile;
473 HWND hwnd;
474 int ret;
475 static const RECT rc = { 0, 0, 150, 150 };
477 /* Win9x doesn't play EMFs on invisible windows */
478 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
479 0, 0, 200, 200, 0, 0, 0, NULL);
480 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
482 hdcDisplay = GetDC(hwnd);
483 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
485 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
486 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
488 SetMapMode(hdcMetafile, MM_ANISOTROPIC);
490 /* Need to write something to the emf, otherwise Windows won't play it back */
491 LineTo(hdcMetafile, 150, 150);
493 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
494 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
495 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
496 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
498 /* Force Win9x to update DC state */
499 SetPixelV(hdcMetafile, 50, 50, 0);
501 ret = SaveDC(hdcMetafile);
502 ok(ret == 1, "ret = %d\n", ret);
504 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
505 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
506 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
507 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
509 /* Force Win9x to update DC state */
510 SetPixelV(hdcMetafile, 50, 50, 0);
512 ret = SaveDC(hdcMetafile);
513 ok(ret == 2, "ret = %d\n", ret);
515 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
516 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
517 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
518 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
520 /* Force Win9x to update DC state */
521 SetPixelV(hdcMetafile, 50, 50, 0);
523 ret = SaveDC(hdcMetafile);
524 ok(ret == 3, "ret = %d\n", ret);
526 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
527 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
528 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
529 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
531 /* Force Win9x to update DC state */
532 SetPixelV(hdcMetafile, 50, 50, 0);
534 ret = RestoreDC(hdcMetafile, -1);
535 ok(ret, "ret = %d\n", ret);
537 ret = SaveDC(hdcMetafile);
538 ok(ret == 3, "ret = %d\n", ret);
540 ret = RestoreDC(hdcMetafile, 1);
541 ok(ret, "ret = %d\n", ret);
543 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
544 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
545 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
546 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
548 /* Force Win9x to update DC state */
549 SetPixelV(hdcMetafile, 50, 50, 0);
551 ret = SaveDC(hdcMetafile);
552 ok(ret == 1, "ret = %d\n", ret);
554 ret = SaveDC(hdcMetafile);
555 ok(ret == 2, "ret = %d\n", ret);
557 hMetafile = CloseEnhMetaFile(hdcMetafile);
558 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
560 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
561 ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
563 ret = DeleteEnhMetaFile(hMetafile);
564 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
565 ret = ReleaseDC(hwnd, hdcDisplay);
566 ok( ret, "ReleaseDC error %d\n", GetLastError());
567 DestroyWindow(hwnd);
570 /* Win-format metafile (mfdrv) tests */
571 /* These tests compare the generated metafiles byte-by-byte */
572 /* with the nominal results. */
574 /* Maximum size of sample metafiles in bytes. */
575 #define MF_BUFSIZE 512
577 /* 8x8 bitmap data for a pattern brush */
578 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
579 0x01, 0x00, 0x02, 0x00,
580 0x03, 0x00, 0x04, 0x00,
581 0x05, 0x00, 0x06, 0x00,
582 0x07, 0x00, 0x08, 0x00
585 /* Sample metafiles to be compared to the outputs of the
586 * test functions.
589 static const unsigned char MF_BLANK_BITS[] = {
590 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
592 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
595 static const unsigned char MF_GRAPHICS_BITS[] = {
596 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
599 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
600 0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
601 0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
602 0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
603 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
604 0x00, 0x00, 0x00, 0x00
607 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
608 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
609 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
611 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
612 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
613 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
618 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
619 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
620 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
621 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
622 0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
623 0x00, 0x00
626 static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
628 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
629 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
630 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
631 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
632 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
633 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
634 0x00, 0x00
637 static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
639 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
644 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
645 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
646 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
649 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
652 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
653 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
654 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
656 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
657 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
658 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
659 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
661 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
662 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
663 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
664 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
665 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
666 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
667 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
669 0x14, 0x00, 0x00, 0x00
672 static const unsigned char MF_LINETO_BITS[] = {
673 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
674 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
675 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
676 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
677 0x00, 0x00
680 static const unsigned char EMF_LINETO_BITS[] = {
681 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
686 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
687 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
688 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
691 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
694 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
695 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
696 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
697 0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
698 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
699 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
700 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
701 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
702 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
703 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
704 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
705 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
706 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
707 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
708 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
709 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
710 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
711 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
712 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
713 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
714 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
715 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
716 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
717 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
718 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
719 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
722 static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
723 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
725 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
726 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
727 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
728 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
729 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
730 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
732 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
733 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
734 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
735 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
736 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
737 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
738 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
739 0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
740 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
741 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
743 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
744 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
745 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
746 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
747 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
748 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
749 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
750 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
751 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
752 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
753 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
754 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
755 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
756 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
757 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
758 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
760 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
761 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
764 static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
765 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
770 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
771 0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
772 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
775 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
778 0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
779 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
780 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
781 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
782 0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
783 0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
784 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
785 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
786 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
787 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
788 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
789 0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
790 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
791 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
792 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
793 0x14, 0x00, 0x00, 0x00
796 /* For debugging or dumping the raw metafiles produced by
797 * new test functions.
799 static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
800 INT nobj, LPARAM param)
802 trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, param %p\n",
803 hdc, mr->rdFunction, mr->rdSize, (void *)param);
804 return TRUE;
807 /* For debugging or dumping the raw metafiles produced by
808 * new test functions.
811 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
813 BYTE buf[MF_BUFSIZE];
814 UINT mfsize, i;
816 if (!winetest_debug) return;
818 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
819 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
821 printf ("MetaFile %s has bits:\n{\n ", desc);
822 for (i=0; i<mfsize; i++)
824 printf ("0x%02x", buf[i]);
825 if (i == mfsize-1)
826 printf ("\n");
827 else if (i % 8 == 7)
828 printf (",\n ");
829 else
830 printf (", ");
832 printf ("};\n");
835 /* Compare the metafile produced by a test function with the
836 * expected raw metafile data in "bits".
837 * Return value is 0 for a perfect match,
838 * -1 if lengths aren't equal,
839 * otherwise returns the number of non-matching bytes.
842 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
843 const char *desc)
845 unsigned char buf[MF_BUFSIZE];
846 UINT mfsize, i;
847 int diff;
849 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
850 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
851 if (mfsize < MF_BUFSIZE)
852 ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
853 desc, mfsize, bsize);
854 else
855 ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
856 desc, mfsize, bsize);
857 if (mfsize != bsize)
858 return -1;
860 diff = 0;
861 for (i=0; i<bsize; i++)
863 if (buf[i] != bits[i])
864 diff++;
866 ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
867 desc, mfsize, bsize, diff);
869 return diff;
872 static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
874 unsigned char buf[MF_BUFSIZE];
875 DWORD mfsize, rd_size, i;
876 int diff;
877 HANDLE hfile;
878 BOOL ret;
880 hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
881 assert(hfile != INVALID_HANDLE_VALUE);
883 mfsize = GetFileSize(hfile, NULL);
884 assert(mfsize <= MF_BUFSIZE);
886 ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
887 ok( ret && rd_size == mfsize, "ReadFile: error %d\n", GetLastError());
889 CloseHandle(hfile);
891 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n", desc, mfsize, bsize);
893 if (mfsize != bsize)
894 return -1;
896 diff = 0;
897 for (i=0; i<bsize; i++)
899 if (buf[i] != bits[i])
900 diff++;
902 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
903 desc, mfsize, bsize, diff);
905 return diff;
908 /* For debugging or dumping the raw EMFs produced by
909 * new test functions.
911 static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
913 BYTE buf[MF_BUFSIZE];
914 UINT mfsize, i;
916 if (!winetest_debug) return;
918 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
919 ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
921 printf("EMF %s has bits:\n{\n ", desc);
922 for (i = 0; i < mfsize; i++)
924 printf ("0x%02x", buf[i]);
925 if (i == mfsize-1)
926 printf ("\n");
927 else if (i % 8 == 7)
928 printf (",\n ");
929 else
930 printf (", ");
932 printf ("};\n");
935 static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
937 BYTE *emf;
938 BYTE buf[MF_BUFSIZE];
939 UINT mfsize, offset;
941 if (!winetest_debug) return;
943 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
944 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
946 printf("EMF %s has records:\n", desc);
948 emf = buf;
949 offset = 0;
950 while(offset < mfsize)
952 EMR *emr = (EMR *)(emf + offset);
953 printf("emr->iType %d, emr->nSize %u\n", emr->iType, emr->nSize);
954 /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
955 offset += emr->nSize;
959 static void dump_emf_record(const ENHMETARECORD *emr, const char *desc)
961 const BYTE *buf;
962 DWORD i;
964 if (!winetest_debug) return;
966 printf ("%s: EMF record %u has bits:\n{\n", desc, emr->iType);
967 buf = (const BYTE *)emr;
968 for (i = 0; i < emr->nSize; i++)
970 printf ("0x%02x", buf[i]);
971 if (i == emr->nSize - 1)
972 printf ("\n");
973 else if (i % 8 == 7)
974 printf (",\n");
975 else
976 printf (", ");
978 printf ("};\n");
981 static void dump_EMREXTTEXTOUT(const EMREXTTEXTOUTW *eto)
983 trace("rclBounds %d,%d - %d,%d\n", eto->rclBounds.left, eto->rclBounds.top,
984 eto->rclBounds.right, eto->rclBounds.bottom);
985 trace("iGraphicsMode %u\n", eto->iGraphicsMode);
986 trace("exScale: %f\n", eto->exScale);
987 trace("eyScale: %f\n", eto->eyScale);
988 trace("emrtext.ptlReference %d,%d\n", eto->emrtext.ptlReference.x, eto->emrtext.ptlReference.y);
989 trace("emrtext.nChars %u\n", eto->emrtext.nChars);
990 trace("emrtext.offString %#x\n", eto->emrtext.offString);
991 trace("emrtext.fOptions %#x\n", eto->emrtext.fOptions);
992 trace("emrtext.rcl %d,%d - %d,%d\n", eto->emrtext.rcl.left, eto->emrtext.rcl.top,
993 eto->emrtext.rcl.right, eto->emrtext.rcl.bottom);
994 trace("emrtext.offDx %#x\n", eto->emrtext.offDx);
997 static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2,
998 const char *desc, BOOL ignore_scaling, BOOL todo)
1000 int diff;
1002 if (emr1->iType != emr2->iType && todo)
1004 todo_wine
1006 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
1007 desc, emr1->iType, emr2->iType);
1010 else
1011 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
1012 desc, emr1->iType, emr2->iType);
1014 if (emr1->nSize != emr2->nSize && todo)
1016 todo_wine
1018 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1019 desc, emr1->nSize, emr2->nSize);
1022 else
1023 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1024 desc, emr1->nSize, emr2->nSize);
1026 /* iType and nSize mismatches are fatal */
1027 if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE;
1029 /* contents of EMR_GDICOMMENT are not interesting */
1030 if (emr1->iType == EMR_GDICOMMENT) return TRUE;
1032 /* different Windows versions setup DC scaling differently when
1033 * converting an old style metafile to an EMF.
1035 if (ignore_scaling && (emr1->iType == EMR_SETWINDOWEXTEX ||
1036 emr1->iType == EMR_SETVIEWPORTEXTEX))
1037 return TRUE;
1039 if (emr1->iType == EMR_EXTTEXTOUTW || emr1->iType == EMR_EXTTEXTOUTA)
1041 EMREXTTEXTOUTW *eto1, *eto2;
1043 eto1 = HeapAlloc(GetProcessHeap(), 0, emr1->nSize);
1044 memcpy(eto1, emr1, emr1->nSize);
1045 eto2 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1046 memcpy(eto2, emr2, emr2->nSize);
1048 /* different Windows versions setup DC scaling differently */
1049 eto1->exScale = eto1->eyScale = 0.0;
1050 eto2->exScale = eto2->eyScale = 0.0;
1052 diff = memcmp(eto1, eto2, emr1->nSize);
1053 if (diff)
1055 dump_EMREXTTEXTOUT(eto1);
1056 dump_EMREXTTEXTOUT(eto2);
1058 HeapFree(GetProcessHeap(), 0, eto1);
1059 HeapFree(GetProcessHeap(), 0, eto2);
1061 else
1062 diff = memcmp(emr1, emr2, emr1->nSize);
1063 if (diff && todo)
1065 todo_wine
1066 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1068 else
1069 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1071 if (diff)
1073 dump_emf_record(emr1, "expected bits");
1074 dump_emf_record(emr2, "actual bits");
1077 return diff == 0 || todo; /* report all non-fatal record mismatches */
1080 /* Compare the EMF produced by a test function with the
1081 * expected raw EMF data in "bits".
1082 * Return value is 0 for a perfect match,
1083 * -1 if lengths aren't equal,
1084 * otherwise returns the number of non-matching bytes.
1086 static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
1087 UINT bsize, const char *desc,
1088 BOOL ignore_scaling, BOOL todo)
1090 unsigned char buf[MF_BUFSIZE];
1091 UINT mfsize, offset;
1092 const ENHMETAHEADER *emh1, *emh2;
1094 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1095 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1097 if (mfsize < MF_BUFSIZE)
1099 if (mfsize != bsize && todo)
1101 todo_wine
1102 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1104 else
1105 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1107 else
1108 ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
1109 desc, mfsize, bsize);
1111 /* basic things must match */
1112 emh1 = (const ENHMETAHEADER *)bits;
1113 emh2 = (const ENHMETAHEADER *)buf;
1114 ok(emh1->iType == EMR_HEADER, "expected EMR_HEADER, got %u\n", emh1->iType);
1115 ok(emh1->nSize == sizeof(ENHMETAHEADER), "expected sizeof(ENHMETAHEADER), got %u\n", emh1->nSize);
1116 ok(emh2->nBytes == mfsize, "expected emh->nBytes %u, got %u\n", mfsize, emh2->nBytes);
1117 ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature);
1119 ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType);
1120 ok(emh1->nSize == emh2->nSize, "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
1121 ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
1122 if (todo && emh1->nBytes != emh2->nBytes)
1124 todo_wine
1125 ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1127 else
1128 ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1129 if (todo && emh1->nRecords != emh2->nRecords)
1131 todo_wine
1132 ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
1134 else
1135 ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords);
1137 offset = emh1->nSize;
1138 while (offset < emh1->nBytes)
1140 const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset);
1141 const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset);
1143 trace("EMF record %u, size %u/record %u, size %u\n",
1144 emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
1146 if (!match_emf_record(emr1, emr2, desc, ignore_scaling, todo)) return -1;
1148 offset += emr1->nSize;
1150 return 0;
1153 /* Test a blank metafile. May be used as a template for new tests. */
1155 static void test_mf_Blank(void)
1157 HDC hdcMetafile;
1158 HMETAFILE hMetafile;
1159 INT caps;
1160 BOOL ret;
1161 INT type;
1163 hdcMetafile = CreateMetaFileA(NULL);
1164 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1165 trace("hdcMetafile %p\n", hdcMetafile);
1167 /* Tests on metafile initialization */
1168 caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
1169 ok (caps == DT_METAFILE,
1170 "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
1172 hMetafile = CloseMetaFile(hdcMetafile);
1173 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1174 type = GetObjectType(hMetafile);
1175 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1176 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1178 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1179 "mf_blank") != 0)
1181 dump_mf_bits(hMetafile, "mf_Blank");
1182 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1185 ret = DeleteMetaFile(hMetafile);
1186 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1189 static void test_CopyMetaFile(void)
1191 HDC hdcMetafile;
1192 HMETAFILE hMetafile, hmf_copy;
1193 BOOL ret;
1194 char temp_path[MAX_PATH];
1195 char mf_name[MAX_PATH];
1196 INT type;
1198 hdcMetafile = CreateMetaFileA(NULL);
1199 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1200 trace("hdcMetafile %p\n", hdcMetafile);
1202 hMetafile = CloseMetaFile(hdcMetafile);
1203 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1204 type = GetObjectType(hMetafile);
1205 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1207 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1208 "mf_blank") != 0)
1210 dump_mf_bits(hMetafile, "mf_Blank");
1211 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1214 GetTempPathA(MAX_PATH, temp_path);
1215 GetTempFileNameA(temp_path, "wmf", 0, mf_name);
1217 hmf_copy = CopyMetaFileA(hMetafile, mf_name);
1218 ok(hmf_copy != 0, "CopyMetaFile error %d\n", GetLastError());
1220 type = GetObjectType(hmf_copy);
1221 ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
1223 ret = DeleteMetaFile(hMetafile);
1224 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1226 if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
1228 dump_mf_bits(hMetafile, "mf_Blank");
1229 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1232 ret = DeleteMetaFile(hmf_copy);
1233 ok( ret, "DeleteMetaFile(%p) error %d\n", hmf_copy, GetLastError());
1235 DeleteFileA(mf_name);
1238 static void test_SetMetaFileBits(void)
1240 HMETAFILE hmf;
1241 INT type;
1242 BOOL ret;
1243 BYTE buf[256];
1244 METAHEADER *mh;
1246 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
1247 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1248 type = GetObjectType(hmf);
1249 ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
1251 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1253 dump_mf_bits(hmf, "mf_Graphics");
1254 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1257 ret = DeleteMetaFile(hmf);
1258 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1260 /* NULL data crashes XP SP1 */
1261 /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
1263 /* Now with not zero size */
1264 SetLastError(0xdeadbeef);
1265 hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
1266 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1267 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1269 /* Now with not even size */
1270 SetLastError(0xdeadbeef);
1271 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
1272 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1273 ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
1275 /* Now with zeroed out or faked some header fields */
1276 assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
1277 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1278 mh = (METAHEADER *)buf;
1279 /* corruption of any of the below fields leads to a failure */
1280 mh->mtType = 0;
1281 mh->mtVersion = 0;
1282 mh->mtHeaderSize = 0;
1283 SetLastError(0xdeadbeef);
1284 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1285 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1286 ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError());
1288 /* Now with corrupted mtSize field */
1289 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1290 mh = (METAHEADER *)buf;
1291 /* corruption of mtSize doesn't lead to a failure */
1292 mh->mtSize *= 2;
1293 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1294 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1296 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1298 dump_mf_bits(hmf, "mf_Graphics");
1299 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1302 ret = DeleteMetaFile(hmf);
1303 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1305 /* Now with zeroed out mtSize field */
1306 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1307 mh = (METAHEADER *)buf;
1308 /* zeroing mtSize doesn't lead to a failure */
1309 mh->mtSize = 0;
1310 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1311 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1313 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1315 dump_mf_bits(hmf, "mf_Graphics");
1316 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1319 ret = DeleteMetaFile(hmf);
1320 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1323 /* Simple APIs from mfdrv/graphics.c
1326 static void test_mf_Graphics(void)
1328 HDC hdcMetafile;
1329 HMETAFILE hMetafile;
1330 POINT oldpoint;
1331 BOOL ret;
1333 hdcMetafile = CreateMetaFileA(NULL);
1334 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1335 trace("hdcMetafile %p\n", hdcMetafile);
1337 ret = MoveToEx(hdcMetafile, 1, 1, NULL);
1338 ok( ret, "MoveToEx error %d.\n", GetLastError());
1339 ret = LineTo(hdcMetafile, 2, 2);
1340 ok( ret, "LineTo error %d.\n", GetLastError());
1341 ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
1342 ok( ret, "MoveToEx error %d.\n", GetLastError());
1344 /* oldpoint gets garbage under Win XP, so the following test would
1345 * work under Wine but fails under Windows:
1347 * ok((oldpoint.x == 2) && (oldpoint.y == 2),
1348 * "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
1349 * oldpoint.x, oldpoint.y);
1352 ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
1353 ok( ret, "Ellipse error %d.\n", GetLastError());
1355 hMetafile = CloseMetaFile(hdcMetafile);
1356 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1357 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1359 if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
1360 "mf_Graphics") != 0)
1362 dump_mf_bits(hMetafile, "mf_Graphics");
1363 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1366 ret = DeleteMetaFile(hMetafile);
1367 ok( ret, "DeleteMetaFile(%p) error %d\n",
1368 hMetafile, GetLastError());
1371 static void test_mf_PatternBrush(void)
1373 HDC hdcMetafile;
1374 HMETAFILE hMetafile;
1375 LOGBRUSH *orig_lb;
1376 HBRUSH hBrush;
1377 BOOL ret;
1379 orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
1381 orig_lb->lbStyle = BS_PATTERN;
1382 orig_lb->lbColor = RGB(0, 0, 0);
1383 orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
1384 ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
1386 hBrush = CreateBrushIndirect (orig_lb);
1387 ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
1389 hdcMetafile = CreateMetaFileA(NULL);
1390 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
1391 trace("hdcMetafile %p\n", hdcMetafile);
1393 hBrush = SelectObject(hdcMetafile, hBrush);
1394 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
1396 hMetafile = CloseMetaFile(hdcMetafile);
1397 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1398 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1400 if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
1401 "mf_Pattern_Brush") != 0)
1403 dump_mf_bits(hMetafile, "mf_Pattern_Brush");
1404 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1407 ret = DeleteMetaFile(hMetafile);
1408 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
1409 ret = DeleteObject(hBrush);
1410 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
1411 ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
1412 ok( ret, "DeleteObject(HBITMAP) error %d\n",
1413 GetLastError());
1414 HeapFree (GetProcessHeap(), 0, orig_lb);
1417 static void test_mf_ExtTextOut_on_path(void)
1419 HDC hdcMetafile;
1420 HMETAFILE hMetafile;
1421 BOOL ret;
1422 static const INT dx[4] = { 3, 5, 8, 12 };
1424 hdcMetafile = CreateMetaFileA(NULL);
1425 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1426 trace("hdcMetafile %p\n", hdcMetafile);
1428 ret = BeginPath(hdcMetafile);
1429 ok(!ret, "BeginPath on metafile DC should fail\n");
1431 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1432 ok(ret, "ExtTextOut error %d\n", GetLastError());
1434 ret = EndPath(hdcMetafile);
1435 ok(!ret, "EndPath on metafile DC should fail\n");
1437 hMetafile = CloseMetaFile(hdcMetafile);
1438 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1440 if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
1441 "mf_TextOut_on_path") != 0)
1443 dump_mf_bits(hMetafile, "mf_TextOut_on_path");
1444 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1447 ret = DeleteMetaFile(hMetafile);
1448 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1451 static void test_emf_ExtTextOut_on_path(void)
1453 HWND hwnd;
1454 HDC hdcDisplay, hdcMetafile;
1455 HENHMETAFILE hMetafile;
1456 BOOL ret;
1457 static const INT dx[4] = { 3, 5, 8, 12 };
1459 /* Win9x doesn't play EMFs on invisible windows */
1460 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1461 0, 0, 200, 200, 0, 0, 0, NULL);
1462 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1464 hdcDisplay = GetDC(hwnd);
1465 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
1467 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
1468 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1470 ret = BeginPath(hdcMetafile);
1471 ok(ret, "BeginPath error %d\n", GetLastError());
1473 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1474 ok(ret, "ExtTextOut error %d\n", GetLastError());
1476 ret = EndPath(hdcMetafile);
1477 ok(ret, "EndPath error %d\n", GetLastError());
1479 hMetafile = CloseEnhMetaFile(hdcMetafile);
1480 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1482 /* this doesn't succeed yet: EMF has correct size, all EMF records
1483 * are there, but their contents don't match for different reasons.
1485 if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
1486 "emf_TextOut_on_path", FALSE, FALSE) != 0)
1488 dump_emf_bits(hMetafile, "emf_TextOut_on_path");
1489 dump_emf_records(hMetafile, "emf_TextOut_on_path");
1492 ret = DeleteEnhMetaFile(hMetafile);
1493 ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
1494 ret = ReleaseDC(hwnd, hdcDisplay);
1495 ok(ret, "ReleaseDC error %d\n", GetLastError());
1496 DestroyWindow(hwnd);
1499 static const unsigned char EMF_CLIPPING[] =
1501 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1503 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1505 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
1506 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1507 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1508 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1510 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1511 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1513 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1514 0xe0, 0x93, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
1515 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1516 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
1517 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1518 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1519 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1520 0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1521 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1522 0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1523 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1524 0x00, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1525 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1526 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1529 static void translate( POINT *pt, UINT count, const XFORM *xform )
1531 while (count--)
1533 FLOAT x = (FLOAT)pt->x;
1534 FLOAT y = (FLOAT)pt->y;
1535 pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
1536 pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
1537 pt++;
1541 /* Compare rectangles allowing rounding errors */
1542 static BOOL is_equal_rect(const RECT *rc1, const RECT *rc2)
1544 return abs(rc1->left - rc2->left) <= 1 &&
1545 abs(rc1->top - rc2->top) <= 1 &&
1546 abs(rc1->right - rc2->right) <= 1 &&
1547 abs(rc1->bottom - rc2->bottom) <= 1;
1550 static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
1551 const ENHMETARECORD *emr, int n_objs, LPARAM param)
1553 if (emr->iType == EMR_EXTSELECTCLIPRGN)
1555 const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
1556 union _rgn
1558 RGNDATA data;
1559 char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
1561 const union _rgn *rgn1;
1562 union _rgn rgn2;
1563 RECT rect, rc_transformed;
1564 const RECT *rc = (const RECT *)param;
1565 HRGN hrgn;
1566 XFORM xform;
1567 INT ret;
1568 BOOL is_win9x;
1570 trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
1571 clip->cbRgnData, clip->iMode);
1573 ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
1574 ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
1575 "too small data block: %u bytes\n", clip->cbRgnData);
1576 if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
1577 return 0;
1579 rgn1 = (const union _rgn *)clip->RgnData;
1581 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1582 rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
1583 rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
1584 rgn1->data.rdh.rcBound.left, rgn1->data.rdh.rcBound.top,
1585 rgn1->data.rdh.rcBound.right, rgn1->data.rdh.rcBound.bottom);
1587 ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
1589 rect = *(const RECT *)rgn1->data.Buffer;
1590 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1591 ok(EqualRect(&rect, rc), "rects don't match\n");
1593 ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize);
1594 ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
1595 ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
1596 ok(rgn1->data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
1598 hrgn = CreateRectRgn(0, 0, 0, 0);
1600 memset(&xform, 0, sizeof(xform));
1601 SetLastError(0xdeadbeef);
1602 ret = GetWorldTransform(hdc, &xform);
1603 is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1604 if (!is_win9x)
1605 ok(ret, "GetWorldTransform error %u\n", GetLastError());
1607 trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
1609 ret = GetClipRgn(hdc, hrgn);
1610 ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
1612 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
1614 ret = GetClipRgn(hdc, hrgn);
1615 ok(ret == 1, "GetClipRgn returned %d, expected 0\n", ret);
1617 /* Win9x returns empty clipping region */
1618 if (is_win9x) return 1;
1620 ret = GetRegionData(hrgn, 0, NULL);
1621 ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
1623 ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
1625 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1626 rgn2.data.rdh.dwSize, rgn2.data.rdh.iType,
1627 rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
1628 rgn2.data.rdh.rcBound.left, rgn2.data.rdh.rcBound.top,
1629 rgn2.data.rdh.rcBound.right, rgn2.data.rdh.rcBound.bottom);
1631 rect = rgn2.data.rdh.rcBound;
1632 rc_transformed = *rc;
1633 translate((POINT *)&rc_transformed, 2, &xform);
1634 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1635 rc_transformed.right, rc_transformed.bottom);
1636 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
1638 rect = *(const RECT *)rgn2.data.Buffer;
1639 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1640 rc_transformed = *rc;
1641 translate((POINT *)&rc_transformed, 2, &xform);
1642 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1643 rc_transformed.right, rc_transformed.bottom);
1644 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
1646 ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize);
1647 ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
1648 ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
1649 ok(rgn2.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
1651 DeleteObject(hrgn);
1653 return 1;
1656 static void test_emf_clipping(void)
1658 static const RECT rc = { 0, 0, 100, 100 };
1659 RECT rc_clip = { 100, 100, 1024, 1024 };
1660 HWND hwnd;
1661 HDC hdc;
1662 HENHMETAFILE hemf;
1663 HRGN hrgn;
1664 INT ret;
1666 SetLastError(0xdeadbeef);
1667 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1668 ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1670 /* Need to write something to the emf, otherwise Windows won't play it back */
1671 LineTo(hdc, 1, 1);
1673 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
1674 ret = SelectClipRgn(hdc, hrgn);
1675 ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
1677 SetLastError(0xdeadbeef);
1678 hemf = CloseEnhMetaFile(hdc);
1679 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1681 if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
1682 "emf_clipping", FALSE, FALSE) != 0)
1684 dump_emf_bits(hemf, "emf_clipping");
1685 dump_emf_records(hemf, "emf_clipping");
1688 DeleteObject(hrgn);
1690 /* Win9x doesn't play EMFs on invisible windows */
1691 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1692 0, 0, 200, 200, 0, 0, 0, NULL);
1693 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1695 hdc = GetDC(hwnd);
1697 ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
1698 ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
1700 DeleteEnhMetaFile(hemf);
1701 ReleaseDC(hwnd, hdc);
1702 DestroyWindow(hwnd);
1705 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
1707 LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
1708 POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
1709 /* When using MM_TEXT Win9x does not update the mapping mode
1710 * until a record is played which actually outputs something */
1711 PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
1712 LPtoDP(hdc, mapping, 2);
1713 trace("EMF record: iType %d, nSize %d, (%d,%d)-(%d,%d)\n",
1714 lpEMFR->iType, lpEMFR->nSize,
1715 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
1717 if (lpEMFR->iType == EMR_LINETO)
1719 INT x0, y0, x1, y1;
1720 if (!lpMFP || lpMFP->mm == MM_TEXT)
1722 x0 = 0;
1723 y0 = 0;
1724 x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
1725 y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
1727 else
1729 ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
1731 x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1732 y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1733 x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1734 y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1736 ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
1737 "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
1738 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
1739 x0, y0, x1, y1);
1741 return TRUE;
1744 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
1746 HDC hdcMf;
1747 HMETAFILE hmf;
1748 HENHMETAFILE hemf;
1749 BOOL ret;
1750 UINT size;
1751 LPBYTE pBits;
1753 hdcMf = CreateMetaFile(NULL);
1754 ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
1755 ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
1756 ok(ret, "LineTo failed with error %d\n", GetLastError());
1757 hmf = CloseMetaFile(hdcMf);
1758 ok(hmf != NULL, "CloseMetaFile failed with error %d\n", GetLastError());
1760 if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
1762 dump_mf_bits(hmf, "mf_LineTo");
1763 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1766 size = GetMetaFileBitsEx(hmf, 0, NULL);
1767 ok(size, "GetMetaFileBitsEx failed with error %d\n", GetLastError());
1768 pBits = HeapAlloc(GetProcessHeap(), 0, size);
1769 GetMetaFileBitsEx(hmf, size, pBits);
1770 DeleteMetaFile(hmf);
1771 hemf = SetWinMetaFileBits(size, pBits, NULL, mfp);
1772 HeapFree(GetProcessHeap(), 0, pBits);
1773 return hemf;
1776 static void test_mf_conversions(void)
1778 trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
1780 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1781 HENHMETAFILE hemf;
1782 METAFILEPICT mfp;
1783 RECT rect = { 0, 0, 100, 100 };
1784 mfp.mm = MM_ANISOTROPIC;
1785 mfp.xExt = 100;
1786 mfp.yExt = 100;
1787 mfp.hMF = NULL;
1788 hemf = create_converted_emf(&mfp);
1790 if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
1791 "emf_LineTo MM_ANISOTROPIC", TRUE, FALSE) != 0)
1793 dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
1794 dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
1797 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1799 DeleteEnhMetaFile(hemf);
1800 DeleteDC(hdcOffscreen);
1803 trace("Testing MF->EMF conversion (MM_TEXT)\n");
1805 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1806 HENHMETAFILE hemf;
1807 METAFILEPICT mfp;
1808 RECT rect = { 0, 0, 100, 100 };
1809 mfp.mm = MM_TEXT;
1810 mfp.xExt = 0;
1811 mfp.yExt = 0;
1812 mfp.hMF = NULL;
1813 hemf = create_converted_emf(&mfp);
1815 if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
1816 "emf_LineTo MM_TEXT", TRUE, FALSE) != 0)
1818 dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
1819 dump_emf_records(hemf, "emf_LineTo MM_TEXT");
1822 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
1824 DeleteEnhMetaFile(hemf);
1825 DeleteDC(hdcOffscreen);
1828 trace("Testing MF->EMF conversion (NULL mfp)\n");
1830 HDC hdcOffscreen = CreateCompatibleDC(NULL);
1831 HENHMETAFILE hemf;
1832 RECT rect = { 0, 0, 100, 100 };
1833 hemf = create_converted_emf(NULL);
1835 if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
1836 "emf_LineTo NULL", TRUE, FALSE) != 0)
1838 dump_emf_bits(hemf, "emf_LineTo NULL");
1839 dump_emf_records(hemf, "emf_LineTo NULL");
1842 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
1844 DeleteEnhMetaFile(hemf);
1845 DeleteDC(hdcOffscreen);
1849 static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1850 LONG mm, LONG xExt, LONG yExt,
1851 RECTL * rclBounds, RECTL * rclFrame)
1853 METAFILEPICT mfp;
1854 METAFILEPICT * mfpPtr = NULL;
1855 HENHMETAFILE emf;
1856 ENHMETAHEADER header;
1857 UINT res;
1859 if (!mfpIsNull)
1861 mfp.mm = mm;
1862 mfp.xExt = xExt;
1863 mfp.yExt = yExt;
1864 mfpPtr = &mfp;
1867 emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
1868 ok(emf != NULL, "SetWinMetaFileBits failed\n");
1869 if (!emf) return FALSE;
1870 res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
1871 ok(res != 0, "GetEnhMetaHeader failed\n");
1872 DeleteEnhMetaFile(emf);
1873 if (!res) return FALSE;
1875 *rclBounds = header.rclBounds;
1876 *rclFrame = header.rclFrame;
1877 return TRUE;
1880 static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
1881 LONG mm, LONG xExt, LONG yExt,
1882 RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
1884 RECTL rclBounds, rclFrame;
1886 if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
1888 const char * msg;
1889 char buf[64];
1891 if (mfpIsNull)
1893 msg = "mfp == NULL";
1895 else
1897 const char * mm_str;
1898 switch (mm)
1900 case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
1901 case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
1902 default: mm_str = "Unexpected";
1904 sprintf(buf, "mm=%s, xExt=%d, yExt=%d", mm_str, xExt, yExt);
1905 msg = buf;
1908 ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
1909 ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
1910 ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
1911 ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
1912 ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
1913 ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
1914 ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
1915 ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
1919 static void test_SetWinMetaFileBits(void)
1921 HMETAFILE wmf;
1922 HDC wmfDC;
1923 BYTE * buffer;
1924 UINT buffer_size;
1925 RECT rect;
1926 UINT res;
1927 RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
1928 RECTL rclBoundsIsotropic, rclFrameIsotropic;
1929 RECTL rclBounds, rclFrame;
1930 HDC dc;
1931 LONG diffx, diffy;
1933 wmfDC = CreateMetaFile(NULL);
1934 ok(wmfDC != NULL, "CreateMetaFile failed\n");
1935 if (!wmfDC) return;
1937 SetWindowExtEx(wmfDC, 100, 100, NULL);
1938 rect.left = rect.top = 0;
1939 rect.right = rect.bottom = 50;
1940 FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
1941 wmf = CloseMetaFile(wmfDC);
1942 ok(wmf != NULL, "Metafile creation failed\n");
1943 if (!wmf) return;
1945 buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
1946 ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
1947 if (buffer_size == 0)
1949 DeleteMetaFile(wmf);
1950 return;
1953 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
1954 ok(buffer != NULL, "HeapAlloc failed\n");
1955 if (!buffer)
1957 DeleteMetaFile(wmf);
1958 return;
1961 res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
1962 ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
1963 DeleteMetaFile(wmf);
1964 if (res != buffer_size)
1966 HeapFree(GetProcessHeap(), 0, buffer);
1967 return;
1970 /* Get the reference bounds and frame */
1971 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
1972 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
1974 ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
1975 rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
1976 "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
1978 ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
1979 ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
1980 diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
1981 if (diffx < 0) diffx = -diffx;
1982 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
1984 dc = CreateCompatibleDC(NULL);
1986 /* Allow 1 mm difference (rounding errors) */
1987 diffx = rclBoundsAnisotropic.right - GetDeviceCaps(dc, HORZRES) / 2;
1988 diffy = rclBoundsAnisotropic.bottom - GetDeviceCaps(dc, VERTRES) / 2;
1989 if (diffx < 0) diffx = -diffx;
1990 if (diffy < 0) diffy = -diffy;
1991 todo_wine
1993 ok(diffx <= 1 && diffy <= 1,
1994 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
1995 GetDeviceCaps(dc, HORZRES) / 2, GetDeviceCaps(dc, VERTRES) / 2, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
1998 /* Allow 1 mm difference (rounding errors) */
1999 diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
2000 diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
2001 if (diffx < 0) diffx = -diffx;
2002 if (diffy < 0) diffy = -diffy;
2003 todo_wine
2005 ok(diffx <= 1 && diffy <= 1,
2006 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2007 GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
2009 DeleteDC(dc);
2011 /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
2012 checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2014 /* If xExt or yExt is zero or negative, the whole device surface is used */
2015 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2016 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2017 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2018 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2019 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2020 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2021 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2022 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2023 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2024 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2025 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2026 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2028 /* MSDN says that negative xExt and yExt values specify a ratio.
2029 Check that this is wrong and the whole device surface is used */
2030 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2031 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
2033 /* Ordinary conversions */
2035 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2037 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2038 "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
2039 ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
2040 "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
2043 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2045 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2046 "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
2047 ok(rclBounds.left == 0 && rclBounds.top == 0,
2048 "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
2050 /* Wine has a rounding error */
2051 diffx = rclBounds.right - rclBounds.bottom;
2052 if (diffx < 0) diffx = -diffx;
2053 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
2056 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
2058 ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
2059 "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
2062 HeapFree(GetProcessHeap(), 0, buffer);
2065 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
2066 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
2067 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
2069 static void test_gdiis(void)
2071 RECT rect = {0,0,100,100};
2072 HDC hdc, hemfDC, hmfDC;
2073 HENHMETAFILE hemf;
2074 HMODULE hgdi32;
2076 /* resolve all the functions */
2077 hgdi32 = GetModuleHandle("gdi32");
2078 pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
2079 pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
2080 pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
2082 if(!pGdiIsMetaPrintDC || !pGdiIsMetaFileDC || !pGdiIsPlayMetafileDC)
2084 win_skip("Needed GdiIs* functions are not available\n");
2085 return;
2088 /* try with nothing */
2089 ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
2090 ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
2091 ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
2093 /* try with a metafile */
2094 hmfDC = CreateMetaFile(NULL);
2095 ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
2096 ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
2097 ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
2098 DeleteMetaFile(CloseMetaFile(hmfDC));
2100 /* try with an enhanced metafile */
2101 hdc = GetDC(NULL);
2102 hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
2103 ok(hemfDC != NULL, "failed to create emf\n");
2105 ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
2106 ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
2107 ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
2109 hemf = CloseEnhMetaFile(hemfDC);
2110 ok(hemf != NULL, "failed to close EMF\n");
2111 DeleteEnhMetaFile(hemf);
2112 ReleaseDC(NULL,hdc);
2115 static void test_SetEnhMetaFileBits(void)
2117 BYTE data[256];
2118 HENHMETAFILE hemf;
2119 ENHMETAHEADER *emh;
2121 memset(data, 0xAA, sizeof(data));
2122 SetLastError(0xdeadbeef);
2123 hemf = SetEnhMetaFileBits(sizeof(data), data);
2124 ok(!hemf, "SetEnhMetaFileBits should fail\n");
2125 ok(GetLastError() == ERROR_INVALID_DATA ||
2126 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
2127 "expected ERROR_INVALID_DATA or ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2129 emh = (ENHMETAHEADER *)data;
2130 memset(emh, 0, sizeof(*emh));
2132 emh->iType = EMR_HEADER;
2133 emh->nSize = sizeof(*emh);
2134 emh->dSignature = ENHMETA_SIGNATURE;
2135 /* emh->nVersion = 0x10000; XP doesn't care about version */
2136 emh->nBytes = sizeof(*emh);
2137 /* emh->nRecords = 1; XP doesn't care about records */
2138 emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
2140 SetLastError(0xdeadbeef);
2141 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2142 ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
2143 DeleteEnhMetaFile(hemf);
2145 /* XP refuses to load unaligned EMF */
2146 emh->nBytes++;
2147 SetLastError(0xdeadbeef);
2148 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2149 ok(!hemf ||
2150 broken(hemf != NULL), /* Win9x, WinMe */
2151 "SetEnhMetaFileBits should fail\n");
2152 todo_wine
2153 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2154 DeleteEnhMetaFile(hemf);
2156 emh->dSignature = 0;
2157 emh->nBytes--;
2158 SetLastError(0xdeadbeef);
2159 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2160 ok(!hemf ||
2161 broken(hemf != NULL), /* Win9x, WinMe */
2162 "SetEnhMetaFileBits should fail\n");
2163 todo_wine
2164 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2165 DeleteEnhMetaFile(hemf);
2168 START_TEST(metafile)
2170 init_function_pointers();
2172 /* For enhanced metafiles (enhmfdrv) */
2173 test_ExtTextOut();
2174 test_SaveDC();
2176 /* For win-format metafiles (mfdrv) */
2177 test_mf_Blank();
2178 test_mf_Graphics();
2179 test_mf_PatternBrush();
2180 test_CopyMetaFile();
2181 test_SetMetaFileBits();
2182 test_mf_ExtTextOut_on_path();
2183 test_emf_ExtTextOut_on_path();
2184 test_emf_clipping();
2186 /* For metafile conversions */
2187 test_mf_conversions();
2188 test_SetWinMetaFileBits();
2190 test_gdiis();
2191 test_SetEnhMetaFileBits();