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
25 #include "wine/test.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 */
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); \
44 trace("GetProcAddress(hGDI, \"%s\") failed\n", #func); \
46 static void init_function_pointers(void)
53 hGDI = GetModuleHandleA("gdi32.dll");
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)
65 INT *orig_dx = (INT *)param;
69 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
70 hdc, emr->iType, emr->nSize, (void *)param);
74 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
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));
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]);
115 emr_processed = TRUE;
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]);
142 emr_processed = TRUE;
153 static void test_ExtTextOut(void)
156 HDC hdcDisplay, hdcMetafile;
157 HENHMETAFILE hMetafile;
159 static const char text[] = "Simple text to test ExtTextOut on metafiles";
161 static const RECT rc = { 0, 0, 100, 100 };
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());
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)
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);
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)
331 static int save_state;
332 static int restore_no;
333 static int select_no;
335 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
336 hdc, emr->iType, emr->nSize, (void *)param);
339 SetLastError(0xdeadbeef);
340 ret = GetWorldTransform(hdc, &xform);
341 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
343 ret = GetWindowOrgEx(hdc, &pt);
344 ok(ret, "GetWindowOrgEx error %u\n", GetLastError());
345 trace("window org (%d,%d)\n", pt.x, pt.y);
346 ret = GetViewportOrgEx(hdc, &pt);
347 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
348 trace("vport org (%d,%d)\n", pt.x, pt.y);
349 ret = GetWindowExtEx(hdc, &size);
350 ok(ret, "GetWindowExtEx error %u\n", GetLastError());
351 trace("window ext (%d,%d)\n", size.cx, size.cy);
352 ret = GetViewportExtEx(hdc, &size);
353 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
354 trace("vport ext (%d,%d)\n", size.cx, size.cy);
358 ok(ret, "GetWorldTransform error %u\n", GetLastError());
359 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
362 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
368 static RECT exp_bounds = { 0, 0, 150, 150 };
370 const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
372 trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
373 emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
374 emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
375 trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
376 emf->szlDevice.cx, emf->szlDevice.cy);
378 SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
379 ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
384 check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
390 const EMRLINETO *line = (const EMRLINETO *)emr;
391 trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
394 case EMR_SETWINDOWORGEX:
396 const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
397 trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
400 case EMR_SETWINDOWEXTEX:
402 const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
403 trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
406 case EMR_SETVIEWPORTORGEX:
408 const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
409 trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
412 case EMR_SETVIEWPORTEXTEX:
414 const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
415 trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
420 trace("EMR_SAVEDC\n");
425 const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
426 trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
431 ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
432 check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
435 ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
436 check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
439 ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
440 check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
443 ok(restore_no <= 3, "restore_no %d\n", restore_no);
444 save_state += restoredc->iRelative;
447 case EMR_SELECTOBJECT:
449 const EMRSELECTOBJECT *selectobj = (const EMRSELECTOBJECT*)emr;
450 trace("EMR_SELECTOBJECT: %x\n",selectobj->ihObject);
455 ok(save_state == 0, "EOF save_state %d\n", save_state);
456 ok(select_no == 3, "Too many/few selects %i\n",select_no);
461 SetLastError(0xdeadbeef);
462 ret = GetWorldTransform(hdc, &xform);
463 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
465 ret = GetWindowOrgEx(hdc, &pt);
466 ok(ret, "GetWindowOrgEx error %u\n", GetLastError());
467 trace("window org (%d,%d)\n", pt.x, pt.y);
468 ret = GetViewportOrgEx(hdc, &pt);
469 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
470 trace("vport org (%d,%d)\n", pt.x, pt.y);
471 ret = GetWindowExtEx(hdc, &size);
472 ok(ret, "GetWindowExtEx error %u\n", GetLastError());
473 trace("window ext (%d,%d)\n", size.cx, size.cy);
474 ret = GetViewportExtEx(hdc, &size);
475 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
476 trace("vport ext (%d,%d)\n", size.cx, size.cy);
480 ok(ret, "GetWorldTransform error %u\n", GetLastError());
481 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
487 static void test_SaveDC(void)
489 HDC hdcMetafile, hdcDisplay;
490 HENHMETAFILE hMetafile;
495 HFONT hFont,hFont2,hFontOld,hFontCheck;
496 static const RECT rc = { 0, 0, 150, 150 };
498 /* Win9x doesn't play EMFs on invisible windows */
499 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
500 0, 0, 200, 200, 0, 0, 0, NULL);
501 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
503 hdcDisplay = GetDC(hwnd);
504 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
506 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
507 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
509 SetMapMode(hdcMetafile, MM_ANISOTROPIC);
511 /* Need to write something to the emf, otherwise Windows won't play it back */
512 LineTo(hdcMetafile, 150, 150);
514 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
515 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
516 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
517 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
519 /* Force Win9x to update DC state */
520 SetPixelV(hdcMetafile, 50, 50, 0);
522 ret = GetViewportOrgEx(hdcMetafile, &pt);
523 ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
524 ret = GetViewportExtEx(hdcMetafile, &size);
525 ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
526 ret = SaveDC(hdcMetafile);
527 ok(ret == 1, "ret = %d\n", ret);
529 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
530 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
531 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
532 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
534 /* Force Win9x to update DC state */
535 SetPixelV(hdcMetafile, 50, 50, 0);
537 ret = GetViewportOrgEx(hdcMetafile, &pt);
538 ok(pt.x == 10,"Expecting ViewportOrg x of 10, got %i\n",pt.x);
539 ret = GetViewportExtEx(hdcMetafile, &size);
540 ok(size.cx == 200,"Expecting ViewportExt cx of 200, got %i\n",size.cx);
541 ret = SaveDC(hdcMetafile);
542 ok(ret == 2, "ret = %d\n", ret);
544 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
545 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
546 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
547 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
548 SetPolyFillMode( hdcMetafile, ALTERNATE );
549 SetBkColor( hdcMetafile, 0 );
551 /* Force Win9x to update DC state */
552 SetPixelV(hdcMetafile, 50, 50, 0);
554 ret = GetViewportOrgEx(hdcMetafile, &pt);
555 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
556 ret = GetViewportExtEx(hdcMetafile, &size);
557 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
558 ret = SaveDC(hdcMetafile);
559 ok(ret == 3, "ret = %d\n", ret);
561 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
562 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
563 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
564 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
566 SetPolyFillMode( hdcMetafile, WINDING );
567 SetBkColor( hdcMetafile, 0x123456 );
568 ok( GetPolyFillMode( hdcMetafile ) == WINDING, "PolyFillMode not restored\n" );
569 ok( GetBkColor( hdcMetafile ) == 0x123456, "Background color not restored\n" );
571 /* Force Win9x to update DC state */
572 SetPixelV(hdcMetafile, 50, 50, 0);
574 ret = GetViewportOrgEx(hdcMetafile, &pt);
575 ok(pt.x == 30,"Expecting ViewportOrg x of 30, got %i\n",pt.x);
576 ret = GetViewportExtEx(hdcMetafile, &size);
577 ok(size.cx == 400,"Expecting ViewportExt cx of 400, got %i\n",size.cx);
578 ret = RestoreDC(hdcMetafile, -1);
579 ok(ret, "ret = %d\n", ret);
581 ret = GetViewportOrgEx(hdcMetafile, &pt);
582 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
583 ret = GetViewportExtEx(hdcMetafile, &size);
584 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
585 ok( GetPolyFillMode( hdcMetafile ) == ALTERNATE, "PolyFillMode not restored\n" );
586 ok( GetBkColor( hdcMetafile ) == 0, "Background color not restored\n" );
587 ret = SaveDC(hdcMetafile);
588 ok(ret == 3, "ret = %d\n", ret);
590 ret = GetViewportOrgEx(hdcMetafile, &pt);
591 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
592 ret = GetViewportExtEx(hdcMetafile, &size);
593 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
594 ret = RestoreDC(hdcMetafile, 1);
595 ok(ret, "ret = %d\n", ret);
596 ret = GetViewportOrgEx(hdcMetafile, &pt);
597 ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
598 ret = GetViewportExtEx(hdcMetafile, &size);
599 ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
601 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
602 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
603 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
604 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
606 /* Force Win9x to update DC state */
607 SetPixelV(hdcMetafile, 50, 50, 0);
609 ret = GetViewportOrgEx(hdcMetafile, &pt);
610 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
611 ret = GetViewportExtEx(hdcMetafile, &size);
612 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
613 ret = SaveDC(hdcMetafile);
614 ok(ret == 1, "ret = %d\n", ret);
616 ret = GetViewportOrgEx(hdcMetafile, &pt);
617 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
618 ret = GetViewportExtEx(hdcMetafile, &size);
619 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
620 ret = SaveDC(hdcMetafile);
621 ok(ret == 2, "ret = %d\n", ret);
623 memset(&orig_lf, 0, sizeof(orig_lf));
624 orig_lf.lfCharSet = ANSI_CHARSET;
625 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
626 orig_lf.lfWeight = FW_DONTCARE;
627 orig_lf.lfHeight = 7;
628 orig_lf.lfQuality = DEFAULT_QUALITY;
629 lstrcpyA(orig_lf.lfFaceName, "Arial");
630 hFont = CreateFontIndirectA(&orig_lf);
631 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
633 hFontOld = SelectObject(hdcMetafile, hFont);
635 hFont2 = CreateFontIndirectA(&orig_lf);
636 ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
637 hFontCheck = SelectObject(hdcMetafile, hFont2);
638 ok(hFontCheck == hFont, "Font not selected\n");
640 /* Force Win9x to update DC state */
641 SetPixelV(hdcMetafile, 50, 50, 0);
643 ret = RestoreDC(hdcMetafile, 1);
644 ok(ret, "ret = %d\n", ret);
645 ret = GetViewportOrgEx(hdcMetafile, &pt);
646 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
647 ret = GetViewportExtEx(hdcMetafile, &size);
648 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
650 hFontCheck = SelectObject(hdcMetafile, hFontOld);
651 ok(hFontOld == hFontCheck && hFontCheck != hFont && hFontCheck != hFont2,
652 "Font not reverted with DC Restore\n");
654 ret = RestoreDC(hdcMetafile, -20);
655 ok(!ret, "ret = %d\n", ret);
656 ret = RestoreDC(hdcMetafile, 20);
657 ok(!ret, "ret = %d\n", ret);
659 hMetafile = CloseEnhMetaFile(hdcMetafile);
660 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
662 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
663 ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
665 ret = DeleteObject(hFont);
666 ok( ret, "DeleteObject error %d\n", GetLastError());
667 ret = DeleteObject(hFont2);
668 ok( ret, "DeleteObject error %d\n", GetLastError());
669 ret = DeleteEnhMetaFile(hMetafile);
670 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
671 ret = ReleaseDC(hwnd, hdcDisplay);
672 ok( ret, "ReleaseDC error %d\n", GetLastError());
676 static void test_mf_SaveDC(void)
683 HFONT hFont,hFont2,hFontOld,hFontCheck;
685 hdcMetafile = CreateMetaFileA(NULL);
686 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
688 ret = SetMapMode(hdcMetafile, MM_ANISOTROPIC);
689 ok (ret, "SetMapMode should not fail\n");
691 /* Need to write something to the emf, otherwise Windows won't play it back */
692 LineTo(hdcMetafile, 150, 150);
694 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
695 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
696 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
697 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
699 /* Force Win9x to update DC state */
700 SetPixelV(hdcMetafile, 50, 50, 0);
702 ret = GetViewportOrgEx(hdcMetafile, &pt);
703 todo_wine ok (!ret, "GetViewportOrgEx should fail\n");
704 ret = GetViewportExtEx(hdcMetafile, &size);
705 todo_wine ok (!ret, "GetViewportExtEx should fail\n");
706 ret = SaveDC(hdcMetafile);
707 ok(ret == 1, "ret = %d\n", ret);
709 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
710 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
711 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
712 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
714 /* Force Win9x to update DC state */
715 SetPixelV(hdcMetafile, 50, 50, 0);
717 ret = SaveDC(hdcMetafile);
718 ok(ret == 1, "ret = %d\n", ret);
720 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
721 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
722 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
723 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
725 /* Force Win9x to update DC state */
726 SetPixelV(hdcMetafile, 50, 50, 0);
727 SetPolyFillMode( hdcMetafile, ALTERNATE );
728 SetBkColor( hdcMetafile, 0 );
730 ret = SaveDC(hdcMetafile);
731 ok(ret == 1, "ret = %d\n", ret);
733 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
734 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
735 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
736 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
738 SetPolyFillMode( hdcMetafile, WINDING );
739 SetBkColor( hdcMetafile, 0x123456 );
740 todo_wine ok( !GetPolyFillMode( hdcMetafile ), "GetPolyFillMode succeeded\n" );
741 todo_wine ok( GetBkColor( hdcMetafile ) == CLR_INVALID, "GetBkColor succeeded\n" );
743 /* Force Win9x to update DC state */
744 SetPixelV(hdcMetafile, 50, 50, 0);
746 ret = RestoreDC(hdcMetafile, -1);
747 ok(ret, "ret = %d\n", ret);
749 ret = SaveDC(hdcMetafile);
750 ok(ret == 1, "ret = %d\n", ret);
752 ret = RestoreDC(hdcMetafile, 1);
753 ok(ret, "ret = %d\n", ret);
755 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
756 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
757 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
758 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
760 /* Force Win9x to update DC state */
761 SetPixelV(hdcMetafile, 50, 50, 0);
763 ret = SaveDC(hdcMetafile);
764 ok(ret == 1, "ret = %d\n", ret);
766 ret = SaveDC(hdcMetafile);
767 ok(ret == 1, "ret = %d\n", ret);
769 memset(&orig_lf, 0, sizeof(orig_lf));
770 orig_lf.lfCharSet = ANSI_CHARSET;
771 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
772 orig_lf.lfWeight = FW_DONTCARE;
773 orig_lf.lfHeight = 7;
774 orig_lf.lfQuality = DEFAULT_QUALITY;
775 lstrcpyA(orig_lf.lfFaceName, "Arial");
776 hFont = CreateFontIndirectA(&orig_lf);
777 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
779 hFontOld = SelectObject(hdcMetafile, hFont);
781 hFont2 = CreateFontIndirectA(&orig_lf);
782 ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
783 hFontCheck = SelectObject(hdcMetafile, hFont2);
784 ok(hFontCheck == hFont, "Font not selected\n");
786 /* Force Win9x to update DC state */
787 SetPixelV(hdcMetafile, 50, 50, 0);
789 ret = RestoreDC(hdcMetafile, 1);
790 ok(ret, "ret = %d\n", ret);
792 hFontCheck = SelectObject(hdcMetafile, hFontOld);
793 ok(hFontOld != hFontCheck && hFontCheck == hFont2, "Font incorrectly reverted with DC Restore\n");
795 /* restore level is ignored */
796 ret = RestoreDC(hdcMetafile, -20);
797 ok(ret, "ret = %d\n", ret);
798 ret = RestoreDC(hdcMetafile, 20);
799 ok(ret, "ret = %d\n", ret);
800 ret = RestoreDC(hdcMetafile, 0);
801 ok(ret, "ret = %d\n", ret);
803 hMetafile = CloseMetaFile(hdcMetafile);
804 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
806 ret = DeleteMetaFile(hMetafile);
807 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
808 ret = DeleteObject(hFont);
809 ok( ret, "DeleteObject error %d\n", GetLastError());
810 ret = DeleteObject(hFont2);
811 ok( ret, "DeleteObject error %d\n", GetLastError());
815 /* Win-format metafile (mfdrv) tests */
816 /* These tests compare the generated metafiles byte-by-byte */
817 /* with the nominal results. */
819 /* Maximum size of sample metafiles in bytes. */
820 #define MF_BUFSIZE 512
822 /* 8x8 bitmap data for a pattern brush */
823 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
824 0x01, 0x00, 0x02, 0x00,
825 0x03, 0x00, 0x04, 0x00,
826 0x05, 0x00, 0x06, 0x00,
827 0x07, 0x00, 0x08, 0x00
830 /* Sample metafiles to be compared to the outputs of the
834 static const unsigned char MF_BLANK_BITS[] = {
835 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
836 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
837 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
840 static const unsigned char MF_GRAPHICS_BITS[] = {
841 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
842 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
843 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
844 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
845 0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
846 0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
847 0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
848 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
849 0x00, 0x00, 0x00, 0x00
852 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
853 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
854 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
856 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
857 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
858 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
859 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
862 0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
863 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
864 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
865 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
866 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
867 0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
871 static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
873 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
874 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
875 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
876 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
877 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
878 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
882 static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
884 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
885 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
886 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
888 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
889 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
890 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
891 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
892 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
893 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
894 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
896 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
897 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
898 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
899 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
900 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
901 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
902 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
903 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
904 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
905 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
906 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
907 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
908 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
909 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
910 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
911 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
912 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
913 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
914 0x14, 0x00, 0x00, 0x00
917 static const unsigned char MF_LINETO_BITS[] = {
918 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
919 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
920 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
921 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
925 static const unsigned char EMF_LINETO_BITS[] = {
926 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
927 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
928 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
929 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
930 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
931 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
932 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
933 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
935 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
936 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
938 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
939 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
940 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
941 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
942 0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
943 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
944 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
945 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
946 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
947 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
948 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
949 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
950 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
951 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
952 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
953 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
954 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
955 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
956 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
957 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
958 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
959 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
960 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
961 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
962 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
963 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
964 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
967 static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
968 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
969 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
970 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
971 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
972 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
973 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
974 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
975 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
976 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
977 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
978 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
980 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
981 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
982 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
983 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
984 0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
985 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
986 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
987 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
988 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
989 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
990 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
991 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
992 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
993 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
994 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
995 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
996 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
997 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
998 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
999 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
1000 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1001 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1002 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
1003 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1004 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1005 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1006 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1009 static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
1010 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1011 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1012 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1013 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1014 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
1015 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1016 0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1017 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1019 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1020 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1021 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1022 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1023 0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
1024 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
1025 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1026 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
1027 0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
1028 0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
1029 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
1030 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
1031 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1032 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
1033 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
1034 0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1035 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1036 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1037 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1038 0x14, 0x00, 0x00, 0x00
1041 static const unsigned char EMF_BITBLT[] =
1043 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1045 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1047 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00,
1048 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1049 0xa0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1050 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1052 0x23, 0x04, 0x00, 0x00, 0x3b, 0x02, 0x00, 0x00,
1053 0x75, 0x01, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00,
1054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1055 0x00, 0x00, 0x00, 0x00, 0x08, 0xb1, 0x05, 0x00,
1056 0x28, 0x11, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
1057 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1058 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1059 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1060 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1061 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0xcc, 0x00,
1062 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1063 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
1064 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
1065 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1066 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
1067 0x64, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
1068 0x8c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1069 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1070 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00,
1071 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1072 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1074 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1077 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1078 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1079 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1080 0x4c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1081 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1082 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1083 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1084 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1085 0x62, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
1086 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
1087 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1088 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
1089 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1090 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1092 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1093 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1094 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1098 /* For debugging or dumping the raw metafiles produced by
1099 * new test functions.
1101 static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
1102 INT nobj, LPARAM param)
1104 trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, param %p\n",
1105 hdc, mr->rdFunction, mr->rdSize, (void *)param);
1109 /* For debugging or dumping the raw metafiles produced by
1110 * new test functions.
1113 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
1115 BYTE buf[MF_BUFSIZE];
1118 if (!winetest_debug) return;
1120 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
1121 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
1123 printf ("MetaFile %s has bits:\n{\n ", desc);
1124 for (i=0; i<mfsize; i++)
1126 printf ("0x%02x", buf[i]);
1129 else if (i % 8 == 7)
1137 /* Compare the metafile produced by a test function with the
1138 * expected raw metafile data in "bits".
1139 * Return value is 0 for a perfect match,
1140 * -1 if lengths aren't equal,
1141 * otherwise returns the number of non-matching bytes.
1144 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
1147 unsigned char buf[MF_BUFSIZE];
1151 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
1152 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
1153 if (mfsize < MF_BUFSIZE)
1154 ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
1155 desc, mfsize, bsize);
1157 ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
1158 desc, mfsize, bsize);
1159 if (mfsize != bsize)
1163 for (i=0; i<bsize; i++)
1165 if (buf[i] != bits[i])
1168 ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1169 desc, mfsize, bsize, diff);
1174 static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
1176 unsigned char buf[MF_BUFSIZE];
1177 DWORD mfsize, rd_size, i;
1182 hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1183 assert(hfile != INVALID_HANDLE_VALUE);
1185 mfsize = GetFileSize(hfile, NULL);
1186 assert(mfsize <= MF_BUFSIZE);
1188 ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
1189 ok( ret && rd_size == mfsize, "ReadFile: error %d\n", GetLastError());
1193 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n", desc, mfsize, bsize);
1195 if (mfsize != bsize)
1199 for (i=0; i<bsize; i++)
1201 if (buf[i] != bits[i])
1204 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1205 desc, mfsize, bsize, diff);
1210 /* For debugging or dumping the raw EMFs produced by
1211 * new test functions.
1213 static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
1215 BYTE buf[MF_BUFSIZE];
1218 if (!winetest_debug) return;
1220 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1221 ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
1223 printf("EMF %s has bits:\n{\n ", desc);
1224 for (i = 0; i < mfsize; i++)
1226 printf ("0x%02x", buf[i]);
1229 else if (i % 8 == 7)
1237 static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
1240 BYTE buf[MF_BUFSIZE];
1241 UINT mfsize, offset;
1243 if (!winetest_debug) return;
1245 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1246 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1248 printf("EMF %s has records:\n", desc);
1252 while(offset < mfsize)
1254 EMR *emr = (EMR *)(emf + offset);
1255 printf("emr->iType %d, emr->nSize %u\n", emr->iType, emr->nSize);
1256 /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
1257 offset += emr->nSize;
1261 static void dump_emf_record(const ENHMETARECORD *emr, const char *desc)
1266 if (!winetest_debug) return;
1268 printf ("%s: EMF record %u has bits:\n{\n", desc, emr->iType);
1269 buf = (const BYTE *)emr;
1270 for (i = 0; i < emr->nSize; i++)
1272 printf ("0x%02x", buf[i]);
1273 if (i == emr->nSize - 1)
1275 else if (i % 8 == 7)
1283 static void dump_EMREXTTEXTOUT(const EMREXTTEXTOUTW *eto)
1285 trace("rclBounds %d,%d - %d,%d\n", eto->rclBounds.left, eto->rclBounds.top,
1286 eto->rclBounds.right, eto->rclBounds.bottom);
1287 trace("iGraphicsMode %u\n", eto->iGraphicsMode);
1288 trace("exScale: %f\n", eto->exScale);
1289 trace("eyScale: %f\n", eto->eyScale);
1290 trace("emrtext.ptlReference %d,%d\n", eto->emrtext.ptlReference.x, eto->emrtext.ptlReference.y);
1291 trace("emrtext.nChars %u\n", eto->emrtext.nChars);
1292 trace("emrtext.offString %#x\n", eto->emrtext.offString);
1293 trace("emrtext.fOptions %#x\n", eto->emrtext.fOptions);
1294 trace("emrtext.rcl %d,%d - %d,%d\n", eto->emrtext.rcl.left, eto->emrtext.rcl.top,
1295 eto->emrtext.rcl.right, eto->emrtext.rcl.bottom);
1296 trace("emrtext.offDx %#x\n", eto->emrtext.offDx);
1299 static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2,
1300 const char *desc, BOOL ignore_scaling)
1304 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
1305 desc, emr1->iType, emr2->iType);
1307 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1308 desc, emr1->nSize, emr2->nSize);
1310 /* iType and nSize mismatches are fatal */
1311 if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE;
1313 /* contents of EMR_GDICOMMENT are not interesting */
1314 if (emr1->iType == EMR_GDICOMMENT) return TRUE;
1316 /* different Windows versions setup DC scaling differently when
1317 * converting an old style metafile to an EMF.
1319 if (ignore_scaling && (emr1->iType == EMR_SETWINDOWEXTEX ||
1320 emr1->iType == EMR_SETVIEWPORTEXTEX))
1323 if (emr1->iType == EMR_EXTTEXTOUTW || emr1->iType == EMR_EXTTEXTOUTA)
1325 EMREXTTEXTOUTW *eto1, *eto2;
1327 eto1 = HeapAlloc(GetProcessHeap(), 0, emr1->nSize);
1328 memcpy(eto1, emr1, emr1->nSize);
1329 eto2 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1330 memcpy(eto2, emr2, emr2->nSize);
1332 /* different Windows versions setup DC scaling differently */
1333 eto1->exScale = eto1->eyScale = 0.0;
1334 eto2->exScale = eto2->eyScale = 0.0;
1336 diff = memcmp(eto1, eto2, emr1->nSize);
1339 dump_EMREXTTEXTOUT(eto1);
1340 dump_EMREXTTEXTOUT(eto2);
1342 HeapFree(GetProcessHeap(), 0, eto1);
1343 HeapFree(GetProcessHeap(), 0, eto2);
1345 else if (emr1->iType == EMR_EXTSELECTCLIPRGN && !lstrcmpA(desc, "emf_clipping"))
1347 /* We have to take care of NT4 differences here */
1348 diff = memcmp(emr1, emr2, emr1->nSize);
1351 ENHMETARECORD *emr_nt4;
1353 emr_nt4 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1354 memcpy(emr_nt4, emr2, emr2->nSize);
1355 /* Correct the nRgnSize field */
1356 emr_nt4->dParm[5] = sizeof(RECT);
1358 diff = memcmp(emr1, emr_nt4, emr1->nSize);
1360 win_skip("Catered for NT4 differences\n");
1362 HeapFree(GetProcessHeap(), 0, emr_nt4);
1366 diff = memcmp(emr1, emr2, emr1->nSize);
1368 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1372 dump_emf_record(emr1, "expected bits");
1373 dump_emf_record(emr2, "actual bits");
1376 return diff == 0; /* report all non-fatal record mismatches */
1379 /* Compare the EMF produced by a test function with the
1380 * expected raw EMF data in "bits".
1381 * Return value is 0 for a perfect match,
1382 * -1 if lengths aren't equal,
1383 * otherwise returns the number of non-matching bytes.
1385 static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
1386 UINT bsize, const char *desc,
1387 BOOL ignore_scaling)
1389 unsigned char buf[MF_BUFSIZE];
1390 UINT mfsize, offset1, offset2, diff_nt4, diff_9x;
1391 const ENHMETAHEADER *emh1, *emh2;
1393 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1394 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1396 /* ENHMETAHEADER size could differ, depending on platform */
1397 diff_nt4 = sizeof(SIZEL);
1398 diff_9x = sizeof(SIZEL) + 3 * sizeof(DWORD);
1400 if (mfsize < MF_BUFSIZE)
1402 ok(mfsize == bsize ||
1403 broken(mfsize == bsize - diff_nt4) || /* NT4 */
1404 broken(mfsize == bsize - diff_9x), /* Win9x/WinME */
1405 "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1408 ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
1409 desc, mfsize, bsize);
1411 /* basic things must match */
1412 emh1 = (const ENHMETAHEADER *)bits;
1413 emh2 = (const ENHMETAHEADER *)buf;
1414 ok(emh1->iType == EMR_HEADER, "expected EMR_HEADER, got %u\n", emh1->iType);
1415 ok(emh1->nSize == sizeof(ENHMETAHEADER), "expected sizeof(ENHMETAHEADER), got %u\n", emh1->nSize);
1416 ok(emh2->nBytes == mfsize, "expected emh->nBytes %u, got %u\n", mfsize, emh2->nBytes);
1417 ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature);
1419 ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType);
1420 ok(emh1->nSize == emh2->nSize ||
1421 broken(emh1->nSize - diff_nt4 == emh2->nSize) ||
1422 broken(emh1->nSize - diff_9x == emh2->nSize),
1423 "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
1424 ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
1425 ok(emh1->nBytes == emh2->nBytes ||
1426 broken(emh1->nBytes - diff_nt4 == emh2->nBytes) ||
1427 broken(emh1->nBytes - diff_9x == emh2->nBytes),
1428 "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1429 ok(emh1->nRecords == emh2->nRecords, "expected nRecords %u, got %u\n", emh1->nRecords, emh2->nRecords);
1431 offset1 = emh1->nSize;
1432 offset2 = emh2->nSize; /* Needed for Win9x/WinME/NT4 */
1433 while (offset1 < emh1->nBytes)
1435 const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset1);
1436 const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset2);
1438 trace("%s: EMF record %u, size %u/record %u, size %u\n",
1439 desc, emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
1441 if (!match_emf_record(emr1, emr2, desc, ignore_scaling)) return -1;
1443 /* We have already bailed out if iType or nSize don't match */
1444 offset1 += emr1->nSize;
1445 offset2 += emr2->nSize;
1451 /* tests blitting to an EMF */
1452 static void test_emf_BitBlt(void)
1454 HDC hdcDisplay, hdcMetafile, hdcBitmap;
1455 HBITMAP hBitmap, hOldBitmap;
1456 HENHMETAFILE hMetafile;
1458 BITMAPINFOHEADER bmih =
1460 sizeof(BITMAPINFOHEADER),
1461 BMP_DIM,/* biWidth */
1462 BMP_DIM,/* biHeight */
1464 24, /* biBitCount */
1465 BI_RGB, /* biCompression */
1466 0, /* biXPelsPerMeter */
1467 0, /* biYPelsPerMeter */
1469 0, /* biClrImportant */
1474 hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL);
1475 ok( hdcDisplay != 0, "CreateDCA error %d\n", GetLastError() );
1477 hdcBitmap = CreateCompatibleDC(hdcDisplay);
1478 ok( hdcBitmap != 0, "CreateCompatibleDC failed\n" );
1479 bmih.biXPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSX), 100, 3937);
1480 bmih.biYPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSY), 100, 3937);
1481 hBitmap = CreateDIBSection(hdcDisplay, (const BITMAPINFO *)&bmih,
1482 DIB_RGB_COLORS, &bits, NULL, 0);
1483 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
1485 hdcMetafile = CreateEnhMetaFileA(hdcBitmap, NULL, NULL, NULL);
1486 ok( hdcMetafile != 0, "CreateEnhMetaFileA failed\n" );
1488 /* First fill the bitmap DC with something recognizable, like BLACKNESS */
1489 ret = BitBlt(hdcBitmap, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, BLACKNESS);
1490 ok( ret, "BitBlt(BLACKNESS) failed\n" );
1492 ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, hdcBitmap, 0, 0, SRCCOPY);
1493 ok( ret, "BitBlt(SRCCOPY) failed\n" );
1494 ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, WHITENESS);
1495 ok( ret, "BitBlt(WHITENESS) failed\n" );
1497 hMetafile = CloseEnhMetaFile(hdcMetafile);
1498 ok( hMetafile != 0, "CloseEnhMetaFile failed\n" );
1500 if(compare_emf_bits(hMetafile, EMF_BITBLT, sizeof(EMF_BITBLT),
1501 "emf_BitBlt", FALSE) != 0)
1503 dump_emf_bits(hMetafile, "emf_BitBlt");
1504 dump_emf_records(hMetafile, "emf_BitBlt");
1507 SelectObject(hdcBitmap, hOldBitmap);
1508 DeleteObject(hBitmap);
1509 DeleteDC(hdcBitmap);
1510 DeleteDC(hdcDisplay);
1514 /* Test a blank metafile. May be used as a template for new tests. */
1516 static void test_mf_Blank(void)
1519 HMETAFILE hMetafile;
1524 hdcMetafile = CreateMetaFileA(NULL);
1525 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1526 trace("hdcMetafile %p\n", hdcMetafile);
1528 /* Tests on metafile initialization */
1529 caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
1530 ok (caps == DT_METAFILE,
1531 "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
1533 hMetafile = CloseMetaFile(hdcMetafile);
1534 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1535 type = GetObjectType(hMetafile);
1536 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1537 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1539 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1542 dump_mf_bits(hMetafile, "mf_Blank");
1543 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1546 ret = DeleteMetaFile(hMetafile);
1547 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1550 static void test_CopyMetaFile(void)
1553 HMETAFILE hMetafile, hmf_copy;
1555 char temp_path[MAX_PATH];
1556 char mf_name[MAX_PATH];
1559 hdcMetafile = CreateMetaFileA(NULL);
1560 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1561 trace("hdcMetafile %p\n", hdcMetafile);
1563 hMetafile = CloseMetaFile(hdcMetafile);
1564 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1565 type = GetObjectType(hMetafile);
1566 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1568 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1571 dump_mf_bits(hMetafile, "mf_Blank");
1572 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1575 GetTempPathA(MAX_PATH, temp_path);
1576 GetTempFileNameA(temp_path, "wmf", 0, mf_name);
1578 hmf_copy = CopyMetaFileA(hMetafile, mf_name);
1579 ok(hmf_copy != 0, "CopyMetaFile error %d\n", GetLastError());
1581 type = GetObjectType(hmf_copy);
1582 ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
1584 ret = DeleteMetaFile(hMetafile);
1585 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1587 if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
1589 dump_mf_bits(hmf_copy, "mf_Blank");
1590 EnumMetaFile(0, hmf_copy, mf_enum_proc, 0);
1593 ret = DeleteMetaFile(hmf_copy);
1594 ok( ret, "DeleteMetaFile(%p) error %d\n", hmf_copy, GetLastError());
1596 DeleteFileA(mf_name);
1599 static void test_SetMetaFileBits(void)
1607 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
1608 trace("hmf %p\n", hmf);
1609 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1610 type = GetObjectType(hmf);
1611 ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
1613 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1615 dump_mf_bits(hmf, "mf_Graphics");
1616 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1619 ret = DeleteMetaFile(hmf);
1620 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1622 /* NULL data crashes XP SP1 */
1623 /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
1625 /* Now with zero size */
1626 SetLastError(0xdeadbeef);
1627 hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
1628 trace("hmf %p\n", hmf);
1629 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1630 ok(GetLastError() == ERROR_INVALID_DATA ||
1631 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
1632 "wrong error %d\n", GetLastError());
1634 /* Now with odd size */
1635 SetLastError(0xdeadbeef);
1636 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
1637 trace("hmf %p\n", hmf);
1638 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1639 ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
1641 /* Now with zeroed out header fields */
1642 assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
1643 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1644 mh = (METAHEADER *)buf;
1645 /* corruption of any of the below fields leads to a failure */
1648 mh->mtHeaderSize = 0;
1649 SetLastError(0xdeadbeef);
1650 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1651 trace("hmf %p\n", hmf);
1652 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1653 ok(GetLastError() == ERROR_INVALID_DATA ||
1654 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
1655 "wrong error %d\n", GetLastError());
1657 /* Now with corrupted mtSize field */
1658 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1659 mh = (METAHEADER *)buf;
1660 /* corruption of mtSize doesn't lead to a failure */
1662 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1663 trace("hmf %p\n", hmf);
1664 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1666 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1668 dump_mf_bits(hmf, "mf_Graphics");
1669 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1672 ret = DeleteMetaFile(hmf);
1673 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1675 #ifndef _WIN64 /* Generates access violation on XP x64 and Win2003 x64 */
1676 /* Now with zeroed out mtSize field */
1677 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1678 mh = (METAHEADER *)buf;
1679 /* zeroing mtSize doesn't lead to a failure */
1681 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1682 trace("hmf %p\n", hmf);
1683 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1685 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1687 dump_mf_bits(hmf, "mf_Graphics");
1688 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1691 ret = DeleteMetaFile(hmf);
1692 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1696 /* Simple APIs from mfdrv/graphics.c
1699 static void test_mf_Graphics(void)
1702 HMETAFILE hMetafile;
1706 hdcMetafile = CreateMetaFileA(NULL);
1707 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1708 trace("hdcMetafile %p\n", hdcMetafile);
1710 ret = MoveToEx(hdcMetafile, 1, 1, NULL);
1711 ok( ret, "MoveToEx error %d.\n", GetLastError());
1712 ret = LineTo(hdcMetafile, 2, 2);
1713 ok( ret, "LineTo error %d.\n", GetLastError());
1714 ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
1715 ok( ret, "MoveToEx error %d.\n", GetLastError());
1717 /* oldpoint gets garbage under Win XP, so the following test would
1718 * work under Wine but fails under Windows:
1720 * ok((oldpoint.x == 2) && (oldpoint.y == 2),
1721 * "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
1722 * oldpoint.x, oldpoint.y);
1725 ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
1726 ok( ret, "Ellipse error %d.\n", GetLastError());
1728 hMetafile = CloseMetaFile(hdcMetafile);
1729 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1730 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1732 if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
1733 "mf_Graphics") != 0)
1735 dump_mf_bits(hMetafile, "mf_Graphics");
1736 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1739 ret = DeleteMetaFile(hMetafile);
1740 ok( ret, "DeleteMetaFile(%p) error %d\n",
1741 hMetafile, GetLastError());
1744 static void test_mf_PatternBrush(void)
1747 HMETAFILE hMetafile;
1752 orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
1754 orig_lb->lbStyle = BS_PATTERN;
1755 orig_lb->lbColor = RGB(0, 0, 0);
1756 orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
1757 ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
1759 hBrush = CreateBrushIndirect (orig_lb);
1760 ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
1762 hdcMetafile = CreateMetaFileA(NULL);
1763 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
1764 trace("hdcMetafile %p\n", hdcMetafile);
1766 hBrush = SelectObject(hdcMetafile, hBrush);
1767 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
1769 hMetafile = CloseMetaFile(hdcMetafile);
1770 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1771 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1773 if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
1774 "mf_Pattern_Brush") != 0)
1776 dump_mf_bits(hMetafile, "mf_Pattern_Brush");
1777 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1780 ret = DeleteMetaFile(hMetafile);
1781 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
1782 ret = DeleteObject(hBrush);
1783 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
1784 ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
1785 ok( ret, "DeleteObject(HBITMAP) error %d\n",
1787 HeapFree (GetProcessHeap(), 0, orig_lb);
1790 static void test_mf_ExtTextOut_on_path(void)
1793 HMETAFILE hMetafile;
1795 static const INT dx[4] = { 3, 5, 8, 12 };
1797 hdcMetafile = CreateMetaFileA(NULL);
1798 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1799 trace("hdcMetafile %p\n", hdcMetafile);
1801 ret = BeginPath(hdcMetafile);
1802 ok(!ret, "BeginPath on metafile DC should fail\n");
1804 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1805 ok(ret, "ExtTextOut error %d\n", GetLastError());
1807 ret = EndPath(hdcMetafile);
1808 ok(!ret, "EndPath on metafile DC should fail\n");
1810 hMetafile = CloseMetaFile(hdcMetafile);
1811 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1813 if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
1814 "mf_TextOut_on_path") != 0)
1816 dump_mf_bits(hMetafile, "mf_TextOut_on_path");
1817 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1820 ret = DeleteMetaFile(hMetafile);
1821 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1824 static void test_emf_ExtTextOut_on_path(void)
1827 HDC hdcDisplay, hdcMetafile;
1828 HENHMETAFILE hMetafile;
1830 static const INT dx[4] = { 3, 5, 8, 12 };
1832 /* Win9x doesn't play EMFs on invisible windows */
1833 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1834 0, 0, 200, 200, 0, 0, 0, NULL);
1835 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1837 hdcDisplay = GetDC(hwnd);
1838 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
1840 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
1841 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1843 ret = BeginPath(hdcMetafile);
1844 ok(ret, "BeginPath error %d\n", GetLastError());
1846 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1847 ok(ret, "ExtTextOut error %d\n", GetLastError());
1849 ret = EndPath(hdcMetafile);
1850 ok(ret, "EndPath error %d\n", GetLastError());
1852 hMetafile = CloseEnhMetaFile(hdcMetafile);
1853 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1855 /* this doesn't succeed yet: EMF has correct size, all EMF records
1856 * are there, but their contents don't match for different reasons.
1858 if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
1859 "emf_TextOut_on_path", FALSE) != 0)
1861 dump_emf_bits(hMetafile, "emf_TextOut_on_path");
1862 dump_emf_records(hMetafile, "emf_TextOut_on_path");
1865 ret = DeleteEnhMetaFile(hMetafile);
1866 ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
1867 ret = ReleaseDC(hwnd, hdcDisplay);
1868 ok(ret, "ReleaseDC error %d\n", GetLastError());
1869 DestroyWindow(hwnd);
1872 static const unsigned char EMF_CLIPPING[] =
1874 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1875 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1876 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1877 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1878 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
1879 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1880 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1881 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1882 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1883 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1884 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1885 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1886 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1887 0xe0, 0x93, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
1888 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1889 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
1890 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1891 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1892 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1893 0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1894 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1895 0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1896 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1897 0x00, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1898 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1899 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1902 static void translate( POINT *pt, UINT count, const XFORM *xform )
1906 FLOAT x = (FLOAT)pt->x;
1907 FLOAT y = (FLOAT)pt->y;
1908 pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
1909 pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
1914 /* Compare rectangles allowing rounding errors */
1915 static BOOL is_equal_rect(const RECT *rc1, const RECT *rc2)
1917 return abs(rc1->left - rc2->left) <= 1 &&
1918 abs(rc1->top - rc2->top) <= 1 &&
1919 abs(rc1->right - rc2->right) <= 1 &&
1920 abs(rc1->bottom - rc2->bottom) <= 1;
1923 static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
1924 const ENHMETARECORD *emr, int n_objs, LPARAM param)
1926 if (emr->iType == EMR_EXTSELECTCLIPRGN)
1928 const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
1932 char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
1934 const union _rgn *rgn1;
1936 RECT rect, rc_transformed;
1937 const RECT *rc = (const RECT *)param;
1943 trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
1944 clip->cbRgnData, clip->iMode);
1946 ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
1947 ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
1948 "too small data block: %u bytes\n", clip->cbRgnData);
1949 if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
1952 rgn1 = (const union _rgn *)clip->RgnData;
1954 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1955 rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
1956 rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
1957 rgn1->data.rdh.rcBound.left, rgn1->data.rdh.rcBound.top,
1958 rgn1->data.rdh.rcBound.right, rgn1->data.rdh.rcBound.bottom);
1960 ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
1962 rect = *(const RECT *)rgn1->data.Buffer;
1963 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1964 ok(EqualRect(&rect, rc), "rects don't match\n");
1966 ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize);
1967 ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
1968 ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
1969 ok(rgn1->data.rdh.nRgnSize == sizeof(RECT) ||
1970 broken(rgn1->data.rdh.nRgnSize == 168), /* NT4 */
1971 "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
1973 hrgn = CreateRectRgn(0, 0, 0, 0);
1975 memset(&xform, 0, sizeof(xform));
1976 SetLastError(0xdeadbeef);
1977 ret = GetWorldTransform(hdc, &xform);
1978 is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1980 ok(ret, "GetWorldTransform error %u\n", GetLastError());
1982 trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
1984 ret = GetClipRgn(hdc, hrgn);
1985 ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
1987 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
1989 ret = GetClipRgn(hdc, hrgn);
1990 ok(ret == 1, "GetClipRgn returned %d, expected 1\n", ret);
1992 /* Win9x returns empty clipping region */
1993 if (is_win9x) return 1;
1995 ret = GetRegionData(hrgn, 0, NULL);
1996 ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
1998 ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
2000 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
2001 rgn2.data.rdh.dwSize, rgn2.data.rdh.iType,
2002 rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
2003 rgn2.data.rdh.rcBound.left, rgn2.data.rdh.rcBound.top,
2004 rgn2.data.rdh.rcBound.right, rgn2.data.rdh.rcBound.bottom);
2006 rect = rgn2.data.rdh.rcBound;
2007 rc_transformed = *rc;
2008 translate((POINT *)&rc_transformed, 2, &xform);
2009 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
2010 rc_transformed.right, rc_transformed.bottom);
2011 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
2013 rect = *(const RECT *)rgn2.data.Buffer;
2014 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
2015 rc_transformed = *rc;
2016 translate((POINT *)&rc_transformed, 2, &xform);
2017 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
2018 rc_transformed.right, rc_transformed.bottom);
2019 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
2021 ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize);
2022 ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
2023 ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
2024 ok(rgn2.data.rdh.nRgnSize == sizeof(RECT) ||
2025 broken(rgn2.data.rdh.nRgnSize == 168), /* NT4 */
2026 "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
2033 static void test_emf_clipping(void)
2035 static const RECT rc = { 0, 0, 100, 100 };
2036 RECT rc_clip = { 100, 100, 1024, 1024 };
2042 RECT rc_res, rc_sclip;
2044 SetLastError(0xdeadbeef);
2045 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
2046 ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
2048 /* Need to write something to the emf, otherwise Windows won't play it back */
2051 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
2052 ret = SelectClipRgn(hdc, hrgn);
2053 ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
2055 SetLastError(0xdeadbeef);
2056 hemf = CloseEnhMetaFile(hdc);
2057 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
2059 if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
2060 "emf_clipping", FALSE) != 0)
2062 dump_emf_bits(hemf, "emf_clipping");
2063 dump_emf_records(hemf, "emf_clipping");
2068 /* Win9x doesn't play EMFs on invisible windows */
2069 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
2070 0, 0, 200, 200, 0, 0, 0, NULL);
2071 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
2075 ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
2076 ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
2078 DeleteEnhMetaFile(hemf);
2079 ReleaseDC(hwnd, hdc);
2080 DestroyWindow(hwnd);
2082 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
2084 SetRect(&rc_sclip, 100, 100, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2085 hrgn = CreateRectRgn(rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom);
2086 SelectClipRgn(hdc, hrgn);
2087 ret = GetClipBox(hdc, &rc_res);
2089 ok(ret == SIMPLEREGION, "got %d\n", ret);
2090 if(ret == SIMPLEREGION)
2091 ok(EqualRect(&rc_res, &rc_sclip),
2092 "expected rc_res (%d, %d) - (%d, %d), got (%d, %d) - (%d, %d)\n",
2093 rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom,
2094 rc_res.left, rc_res.top, rc_res.right, rc_res.bottom);
2096 hemf = CloseEnhMetaFile(hdc);
2097 DeleteEnhMetaFile(hemf);
2102 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
2104 LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
2105 POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
2106 /* When using MM_TEXT Win9x does not update the mapping mode
2107 * until a record is played which actually outputs something */
2108 PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
2109 LPtoDP(hdc, mapping, 2);
2110 trace("EMF record: iType %d, nSize %d, (%d,%d)-(%d,%d)\n",
2111 lpEMFR->iType, lpEMFR->nSize,
2112 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
2114 if (lpEMFR->iType == EMR_LINETO)
2117 if (!lpMFP || lpMFP->mm == MM_TEXT)
2121 x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
2122 y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
2126 ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
2128 x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
2129 y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
2130 x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
2131 y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
2133 ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
2134 "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
2135 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
2141 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
2150 hdcMf = CreateMetaFile(NULL);
2151 ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
2152 ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
2153 ok(ret, "LineTo failed with error %d\n", GetLastError());
2154 hmf = CloseMetaFile(hdcMf);
2155 ok(hmf != NULL, "CloseMetaFile failed with error %d\n", GetLastError());
2157 if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
2159 dump_mf_bits(hmf, "mf_LineTo");
2160 EnumMetaFile(0, hmf, mf_enum_proc, 0);
2163 size = GetMetaFileBitsEx(hmf, 0, NULL);
2164 ok(size, "GetMetaFileBitsEx failed with error %d\n", GetLastError());
2165 pBits = HeapAlloc(GetProcessHeap(), 0, size);
2166 GetMetaFileBitsEx(hmf, size, pBits);
2167 DeleteMetaFile(hmf);
2168 hemf = SetWinMetaFileBits(size, pBits, NULL, mfp);
2169 HeapFree(GetProcessHeap(), 0, pBits);
2173 static void test_mf_conversions(void)
2175 trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
2177 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2180 RECT rect = { 0, 0, 100, 100 };
2181 mfp.mm = MM_ANISOTROPIC;
2185 hemf = create_converted_emf(&mfp);
2187 if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
2188 "emf_LineTo MM_ANISOTROPIC", TRUE) != 0)
2190 dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
2191 dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
2194 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
2196 DeleteEnhMetaFile(hemf);
2197 DeleteDC(hdcOffscreen);
2200 trace("Testing MF->EMF conversion (MM_TEXT)\n");
2202 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2205 RECT rect = { 0, 0, 100, 100 };
2210 hemf = create_converted_emf(&mfp);
2212 if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
2213 "emf_LineTo MM_TEXT", TRUE) != 0)
2215 dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
2216 dump_emf_records(hemf, "emf_LineTo MM_TEXT");
2219 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
2221 DeleteEnhMetaFile(hemf);
2222 DeleteDC(hdcOffscreen);
2225 trace("Testing MF->EMF conversion (NULL mfp)\n");
2227 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2229 RECT rect = { 0, 0, 100, 100 };
2230 hemf = create_converted_emf(NULL);
2232 if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
2233 "emf_LineTo NULL", TRUE) != 0)
2235 dump_emf_bits(hemf, "emf_LineTo NULL");
2236 dump_emf_records(hemf, "emf_LineTo NULL");
2239 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
2241 DeleteEnhMetaFile(hemf);
2242 DeleteDC(hdcOffscreen);
2246 static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
2247 LONG mm, LONG xExt, LONG yExt,
2248 RECTL * rclBounds, RECTL * rclFrame)
2251 METAFILEPICT * mfpPtr = NULL;
2253 ENHMETAHEADER header;
2264 emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
2265 ok(emf != NULL, "SetWinMetaFileBits failed\n");
2266 if (!emf) return FALSE;
2267 res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
2268 ok(res != 0, "GetEnhMetaHeader failed\n");
2269 DeleteEnhMetaFile(emf);
2270 if (!res) return FALSE;
2272 *rclBounds = header.rclBounds;
2273 *rclFrame = header.rclFrame;
2277 static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
2278 LONG mm, LONG xExt, LONG yExt,
2279 RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
2281 RECTL rclBounds, rclFrame;
2283 if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
2290 msg = "mfp == NULL";
2294 const char * mm_str;
2297 case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
2298 case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
2299 default: mm_str = "Unexpected";
2301 sprintf(buf, "mm=%s, xExt=%d, yExt=%d", mm_str, xExt, yExt);
2305 ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
2306 ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
2307 ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
2308 ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
2309 ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
2310 ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
2311 ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
2312 ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
2316 static void test_SetWinMetaFileBits(void)
2324 RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
2325 RECTL rclBoundsIsotropic, rclFrameIsotropic;
2326 RECTL rclBounds, rclFrame;
2330 wmfDC = CreateMetaFile(NULL);
2331 ok(wmfDC != NULL, "CreateMetaFile failed\n");
2334 SetWindowExtEx(wmfDC, 100, 100, NULL);
2335 rect.left = rect.top = 0;
2336 rect.right = rect.bottom = 50;
2337 FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
2338 wmf = CloseMetaFile(wmfDC);
2339 ok(wmf != NULL, "Metafile creation failed\n");
2342 buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
2343 ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
2344 if (buffer_size == 0)
2346 DeleteMetaFile(wmf);
2350 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
2351 ok(buffer != NULL, "HeapAlloc failed\n");
2354 DeleteMetaFile(wmf);
2358 res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
2359 ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
2360 DeleteMetaFile(wmf);
2361 if (res != buffer_size)
2363 HeapFree(GetProcessHeap(), 0, buffer);
2367 /* Get the reference bounds and frame */
2368 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2369 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2371 ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
2372 rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
2373 "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
2375 ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
2376 ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
2377 diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
2378 if (diffx < 0) diffx = -diffx;
2379 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
2381 dc = CreateCompatibleDC(NULL);
2383 /* Allow 1 mm difference (rounding errors) */
2384 diffx = rclBoundsAnisotropic.right - GetDeviceCaps(dc, HORZRES) / 2;
2385 diffy = rclBoundsAnisotropic.bottom - GetDeviceCaps(dc, VERTRES) / 2;
2386 if (diffx < 0) diffx = -diffx;
2387 if (diffy < 0) diffy = -diffy;
2390 ok(diffx <= 1 && diffy <= 1,
2391 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2392 GetDeviceCaps(dc, HORZRES) / 2, GetDeviceCaps(dc, VERTRES) / 2, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
2395 /* Allow 1 mm difference (rounding errors) */
2396 diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
2397 diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
2398 if (diffx < 0) diffx = -diffx;
2399 if (diffy < 0) diffy = -diffy;
2402 ok(diffx <= 1 && diffy <= 1,
2403 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2404 GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
2408 /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
2409 checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2411 /* If xExt or yExt is zero or negative, the whole device surface is used */
2412 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2413 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2414 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2415 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2416 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2417 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2418 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2419 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2420 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2421 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2422 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2423 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2425 /* MSDN says that negative xExt and yExt values specify a ratio.
2426 Check that this is wrong and the whole device surface is used */
2427 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2428 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
2430 /* Ordinary conversions */
2432 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2434 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2435 "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
2436 ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
2437 "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
2440 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2442 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2443 "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
2444 ok(rclBounds.left == 0 && rclBounds.top == 0,
2445 "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
2447 /* Wine has a rounding error */
2448 diffx = rclBounds.right - rclBounds.bottom;
2449 if (diffx < 0) diffx = -diffx;
2450 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
2453 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
2455 ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
2456 "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
2459 HeapFree(GetProcessHeap(), 0, buffer);
2462 static BOOL near_match(int x, int y)
2464 int epsilon = min(abs(x), abs(y));
2466 epsilon = max(epsilon/100, 2);
2468 if(x < y - epsilon || x > y + epsilon) return FALSE;
2472 static void getwinmetafilebits(UINT mode, int scale, RECT *rc)
2475 HDC display_dc, emf_dc;
2476 ENHMETAHEADER *enh_header;
2477 UINT size, emf_size, i;
2480 METAHEADER *mh = NULL;
2482 INT horz_res, vert_res, horz_size, vert_size;
2484 display_dc = GetDC(NULL);
2485 ok(display_dc != NULL, "display_dc is NULL\n");
2487 horz_res = GetDeviceCaps(display_dc, HORZRES);
2488 vert_res = GetDeviceCaps(display_dc, VERTRES);
2489 horz_size = GetDeviceCaps(display_dc, HORZSIZE);
2490 vert_size = GetDeviceCaps(display_dc, VERTSIZE);
2492 emf_dc = CreateEnhMetaFileA(display_dc, NULL, rc, NULL);
2493 ok(emf_dc != NULL, "emf_dc is NULL\n");
2494 for(i = 0; i < 3000; i++) /* This is enough to take emf_size > 0xffff */
2495 Rectangle(emf_dc, 0, 0, 1000, 20);
2496 emf = CloseEnhMetaFile(emf_dc);
2497 ok(emf != NULL, "emf is NULL\n");
2499 emf_size = GetEnhMetaFileBits(emf, 0, NULL);
2500 enh_header = HeapAlloc(GetProcessHeap(), 0, emf_size);
2501 emf_size = GetEnhMetaFileBits(emf, emf_size, (BYTE*)enh_header);
2502 DeleteEnhMetaFile(emf);
2503 /* multiply szlDevice.cx by scale, when scale != 1 the recording and playback dcs
2504 have different resolutions */
2505 enh_header->szlDevice.cx *= scale;
2506 emf = SetEnhMetaFileBits(emf_size, (BYTE*)enh_header);
2507 ok(emf != NULL, "emf is NULL\n");
2508 ok(EqualRect((RECT*)&enh_header->rclFrame, rc), "Frame rectangles differ\n");
2510 size = GetWinMetaFileBits(emf, 0, NULL, mode, display_dc);
2512 broken(size == 0), /* some versions of winxp fail for some reason */
2513 "GetWinMetaFileBits returns 0\n");
2515 mh = HeapAlloc(GetProcessHeap(), 0, size);
2516 GetWinMetaFileBits(emf, size, (BYTE*)mh, mode, display_dc);
2518 for(i = 0; i < size / 2; i++) check += ((WORD*)mh)[i];
2519 ok(check == 0, "check %04x\n", check);
2521 rec = (METARECORD*)(mh + 1);
2523 while(rec->rdSize && rec->rdFunction)
2525 const DWORD chunk_size = 0x2000;
2526 DWORD mfcomment_chunks = (emf_size + chunk_size - 1) / chunk_size;
2528 if(rec_num < mfcomment_chunks)
2530 DWORD this_chunk_size = chunk_size;
2532 if(rec_num == mfcomment_chunks - 1)
2533 this_chunk_size = emf_size - rec_num * chunk_size;
2535 ok(rec->rdSize == (this_chunk_size + 44) / 2, "%04x: got %04x expected %04x\n", rec_num, rec->rdSize, (this_chunk_size + 44) / 2);
2536 ok(rec->rdFunction == META_ESCAPE, "%04x: got %04x\n", rec_num, rec->rdFunction);
2537 if(rec->rdSize < (this_chunk_size + 44) / 2) break;
2538 ok(rec->rdParm[0] == MFCOMMENT, "got %04x\n", rec->rdParm[0]);
2539 ok(rec->rdParm[1] == this_chunk_size + 34, "got %04x %x\n", rec->rdParm[1], emf_size + 34);
2540 ok(rec->rdParm[2] == 0x4d57, "got %04x\n", rec->rdParm[2]); /* WMFC */
2541 ok(rec->rdParm[3] == 0x4346, "got %04x\n", rec->rdParm[3]); /* " */
2542 ok(rec->rdParm[4] == 1, "got %04x\n", rec->rdParm[4]);
2543 ok(rec->rdParm[5] == 0, "got %04x\n", rec->rdParm[5]);
2544 ok(rec->rdParm[6] == 0, "got %04x\n", rec->rdParm[6]);
2545 ok(rec->rdParm[7] == 1, "got %04x\n", rec->rdParm[7]);
2546 /* parm[8] is the checksum, tested above */
2547 if(rec_num > 0) ok(rec->rdParm[8] == 0, "got %04x\n", rec->rdParm[8]);
2548 ok(rec->rdParm[9] == 0, "got %04x\n", rec->rdParm[9]);
2549 ok(rec->rdParm[10] == 0, "got %04x\n", rec->rdParm[10]);
2550 ok(rec->rdParm[11] == mfcomment_chunks, "got %04x\n", rec->rdParm[11]); /* num chunks */
2551 ok(rec->rdParm[12] == 0, "got %04x\n", rec->rdParm[12]);
2552 ok(rec->rdParm[13] == this_chunk_size, "got %04x expected %04x\n", rec->rdParm[13], this_chunk_size);
2553 ok(rec->rdParm[14] == 0, "got %04x\n", rec->rdParm[14]);
2554 ok(*(DWORD*)(rec->rdParm + 15) == emf_size - this_chunk_size - rec_num * chunk_size, "got %08x\n", *(DWORD*)(rec->rdParm + 15)); /* DWORD size remaining after current chunk */
2555 ok(*(DWORD*)(rec->rdParm + 17) == emf_size, "got %08x emf_size %08x\n", *(DWORD*)(rec->rdParm + 17), emf_size);
2556 ok(!memcmp(rec->rdParm + 19, (char*)enh_header + rec_num * chunk_size, this_chunk_size), "bits mismatch\n");
2559 else if(rec_num == mfcomment_chunks)
2561 ok(rec->rdFunction == META_SETMAPMODE, "got %04x\n", rec->rdFunction);
2562 ok(rec->rdParm[0] == mode, "got %04x\n", rec->rdParm[0]);
2564 else if(rec_num == mfcomment_chunks + 1)
2567 ok(rec->rdFunction == META_SETWINDOWORG, "got %04x\n", rec->rdFunction);
2572 case MM_ANISOTROPIC:
2573 pt.y = MulDiv(rc->top, vert_res, vert_size * 100) + 1;
2574 pt.x = MulDiv(rc->left, horz_res, horz_size * 100);
2577 pt.y = MulDiv(-rc->top, 1, 10) + 1;
2578 pt.x = MulDiv( rc->left, 1, 10);
2581 pt.y = -rc->top + 1;
2582 pt.x = (rc->left >= 0) ? rc->left : rc->left + 1; /* strange but true */
2585 pt.y = MulDiv(-rc->top, 10, 254) + 1;
2586 pt.x = MulDiv( rc->left, 10, 254);
2589 pt.y = MulDiv(-rc->top, 100, 254) + 1;
2590 pt.x = MulDiv( rc->left, 100, 254);
2593 pt.y = MulDiv(-rc->top, 72 * 20, 2540) + 1;
2594 pt.x = MulDiv( rc->left, 72 * 20, 2540);
2599 ok(near_match((short)rec->rdParm[0], pt.y), "got %d expect %d\n", (short)rec->rdParm[0], pt.y);
2600 ok(near_match((short)rec->rdParm[1], pt.x), "got %d expect %d\n", (short)rec->rdParm[1], pt.x);
2602 if(rec_num == mfcomment_chunks + 2)
2604 ok(rec->rdFunction == META_SETWINDOWEXT, "got %04x\n", rec->rdFunction);
2605 ok(near_match((short)rec->rdParm[0], MulDiv(rc->bottom - rc->top, vert_res, vert_size * 100)),
2606 "got %d\n", (short)rec->rdParm[0]);
2607 ok(near_match((short)rec->rdParm[1], MulDiv(rc->right - rc->left, horz_res, horz_size * 100)),
2608 "got %d\n", (short)rec->rdParm[1]);
2612 rec = (METARECORD*)((WORD*)rec + rec->rdSize);
2616 HeapFree(GetProcessHeap(), 0, mh);
2617 HeapFree(GetProcessHeap(), 0, enh_header);
2618 DeleteEnhMetaFile(emf);
2620 ReleaseDC(NULL, display_dc);
2623 static void test_GetWinMetaFileBits(void)
2628 { 1000, 2000, 3000, 6000},
2629 {-1000, 2000, 3000, 6000},
2630 { 1000, -2000, 3000, 6000},
2631 { 1005, 2005, 3000, 6000},
2632 {-1005, -2005, 3000, 6000},
2633 {-1005, -2010, 3000, 6000},
2634 {-1005, 2010, 3000, 6000},
2640 for(mode = MM_MIN; mode <= MM_MAX; mode++)
2643 trace("mode %d\n", mode);
2645 for(rc = frames; rc->right - rc->left > 0; rc++)
2647 trace("frame %d,%d - %d,%d\n", rc->left, rc->top, rc->right, rc->bottom);
2648 getwinmetafilebits(mode, 1, rc);
2649 getwinmetafilebits(mode, 2, rc);
2654 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
2655 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
2656 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
2658 static void test_gdiis(void)
2660 RECT rect = {0,0,100,100};
2661 HDC hdc, hemfDC, hmfDC;
2665 /* resolve all the functions */
2666 hgdi32 = GetModuleHandle("gdi32");
2667 pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
2668 pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
2669 pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
2671 if(!pGdiIsMetaPrintDC || !pGdiIsMetaFileDC || !pGdiIsPlayMetafileDC)
2673 win_skip("Needed GdiIs* functions are not available\n");
2677 /* try with nothing */
2678 ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
2679 ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
2680 ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
2682 /* try with a metafile */
2683 hmfDC = CreateMetaFile(NULL);
2684 ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
2685 ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
2686 ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
2687 DeleteMetaFile(CloseMetaFile(hmfDC));
2689 /* try with an enhanced metafile */
2691 hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
2692 ok(hemfDC != NULL, "failed to create emf\n");
2694 ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
2695 ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
2696 ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
2698 hemf = CloseEnhMetaFile(hemfDC);
2699 ok(hemf != NULL, "failed to close EMF\n");
2700 DeleteEnhMetaFile(hemf);
2701 ReleaseDC(NULL,hdc);
2704 static void test_SetEnhMetaFileBits(void)
2710 memset(data, 0xAA, sizeof(data));
2711 SetLastError(0xdeadbeef);
2712 hemf = SetEnhMetaFileBits(sizeof(data), data);
2713 ok(!hemf, "SetEnhMetaFileBits should fail\n");
2714 ok(GetLastError() == ERROR_INVALID_DATA ||
2715 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
2716 "expected ERROR_INVALID_DATA or ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2718 emh = (ENHMETAHEADER *)data;
2719 memset(emh, 0, sizeof(*emh));
2721 emh->iType = EMR_HEADER;
2722 emh->nSize = sizeof(*emh);
2723 emh->dSignature = ENHMETA_SIGNATURE;
2724 /* emh->nVersion = 0x10000; XP doesn't care about version */
2725 emh->nBytes = sizeof(*emh);
2726 /* emh->nRecords = 1; XP doesn't care about records */
2727 emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
2729 SetLastError(0xdeadbeef);
2730 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2731 ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
2732 DeleteEnhMetaFile(hemf);
2734 /* XP refuses to load unaligned EMF */
2736 SetLastError(0xdeadbeef);
2737 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2739 broken(hemf != NULL), /* Win9x, WinMe */
2740 "SetEnhMetaFileBits should fail\n");
2741 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2742 DeleteEnhMetaFile(hemf);
2744 emh->dSignature = 0;
2746 SetLastError(0xdeadbeef);
2747 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2749 broken(hemf != NULL), /* Win9x, WinMe */
2750 "SetEnhMetaFileBits should fail\n");
2751 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2752 DeleteEnhMetaFile(hemf);
2755 START_TEST(metafile)
2757 init_function_pointers();
2759 /* For enhanced metafiles (enhmfdrv) */
2764 /* For win-format metafiles (mfdrv) */
2768 test_mf_PatternBrush();
2769 test_CopyMetaFile();
2770 test_SetMetaFileBits();
2771 test_mf_ExtTextOut_on_path();
2772 test_emf_ExtTextOut_on_path();
2773 test_emf_clipping();
2775 /* For metafile conversions */
2776 test_mf_conversions();
2777 test_SetWinMetaFileBits();
2778 test_GetWinMetaFileBits();
2781 test_SetEnhMetaFileBits();