[GDI32_WINETEST]
[reactos.git] / rostests / winetests / gdi32 / metafile.c
1 /*
2 * Unit tests for metafile functions
3 *
4 * Copyright (c) 2002 Dmitry Timoshkov
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <math.h>
24
25 #include "wine/test.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30
31 static LOGFONTA orig_lf;
32 static BOOL emr_processed = FALSE;
33
34 /* Arbitrarily chosen values for the second co-ordinate of a metafile line */
35 #define LINE_X 55.0f
36 #define LINE_Y 15.0f
37
38 static INT (WINAPI * pGetRelAbs)(HDC, DWORD);
39 static INT (WINAPI * pSetRelAbs)(HDC, INT);
40 static COLORREF (WINAPI *pSetDCBrushColor)(HDC,COLORREF);
41 static COLORREF (WINAPI *pSetDCPenColor)(HDC,COLORREF);
42
43 #define GDI_GET_PROC(func) \
44 p ## func = (void *)GetProcAddress(hGDI, #func); \
45 if(!p ## func) \
46 trace("GetProcAddress(hGDI, \"%s\") failed\n", #func); \
47
48 static void init_function_pointers(void)
49 {
50 HMODULE hGDI;
51
52 pGetRelAbs = NULL;
53 pSetRelAbs = NULL;
54
55 hGDI = GetModuleHandleA("gdi32.dll");
56 assert(hGDI);
57 GDI_GET_PROC(GetRelAbs);
58 GDI_GET_PROC(SetRelAbs);
59 GDI_GET_PROC(SetDCBrushColor);
60 GDI_GET_PROC(SetDCPenColor);
61 }
62
63 static DWORD rgn_rect_count(HRGN hrgn)
64 {
65 DWORD size;
66 RGNDATA *data;
67
68 if (!hrgn) return 0;
69 if (!(size = GetRegionData(hrgn, 0, NULL))) return 0;
70 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return 0;
71 GetRegionData(hrgn, size, data);
72 size = data->rdh.nCount;
73 HeapFree(GetProcessHeap(), 0, data);
74 return size;
75 }
76
77 static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
78 const ENHMETARECORD *emr, int n_objs, LPARAM param)
79 {
80 static int n_record;
81 DWORD i;
82 const INT *dx;
83 INT *orig_dx = (INT *)param;
84 LOGFONTA device_lf;
85 INT ret;
86
87 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
88 hdc, emr->iType, emr->nSize, (void *)param);
89
90 if(!hdc) return 1;
91
92 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
93
94 switch (emr->iType)
95 {
96 case EMR_HEADER:
97 ok(GetTextAlign(hdc) == 0, "text align %08x\n", GetTextAlign(hdc));
98 ok(GetBkColor(hdc) == RGB(0xff, 0xff, 0xff), "bk color %08x\n", GetBkColor(hdc));
99 ok(GetTextColor(hdc) == RGB(0x0, 0x0, 0x0), "text color %08x\n", GetTextColor(hdc));
100 ok(GetROP2(hdc) == R2_COPYPEN, "rop %d\n", GetROP2(hdc));
101 ok(GetArcDirection(hdc) == AD_COUNTERCLOCKWISE, "arc dir %d\n", GetArcDirection(hdc));
102 ok(GetPolyFillMode(hdc) == ALTERNATE, "poly fill %d\n", GetPolyFillMode(hdc));
103 ok(GetStretchBltMode(hdc) == BLACKONWHITE, "stretchblt mode %d\n", GetStretchBltMode(hdc));
104
105 /* GetBkMode, GetRelAbs do not get reset to the default value */
106 ok(GetBkMode(hdc) == OPAQUE, "bk mode %d\n", GetBkMode(hdc));
107 if(pSetRelAbs && pGetRelAbs)
108 ok(pGetRelAbs(hdc, 0) == RELATIVE, "relabs %d\n", pGetRelAbs(hdc, 0));
109
110 n_record = 0;
111 break;
112
113 case EMR_EXTTEXTOUTA:
114 {
115 const EMREXTTEXTOUTA *emr_ExtTextOutA = (const EMREXTTEXTOUTA *)emr;
116 dx = (const INT *)((const char *)emr + emr_ExtTextOutA->emrtext.offDx);
117
118 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
119 ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError());
120
121 /* compare up to lfOutPrecision, other values are not interesting,
122 * and in fact sometimes arbitrary adapted by Win9x.
123 */
124 ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
125 ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
126
127 for(i = 0; i < emr_ExtTextOutA->emrtext.nChars; i++)
128 {
129 ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
130 n_record, i, dx[i], orig_dx[i]);
131 }
132 n_record++;
133 emr_processed = TRUE;
134 break;
135 }
136
137 case EMR_EXTTEXTOUTW:
138 {
139 const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr;
140 dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx);
141
142 SetLastError(0xdeadbeef);
143 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
144 ok( ret == sizeof(device_lf) ||
145 broken(ret == (sizeof(device_lf) - LF_FACESIZE + strlen(device_lf.lfFaceName) + 1)), /* NT4 */
146 "GetObjectA error %d\n", GetLastError());
147
148 /* compare up to lfOutPrecision, other values are not interesting,
149 * and in fact sometimes arbitrary adapted by Win9x.
150 */
151 ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
152 ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
153
154 for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
155 {
156 ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
157 n_record, i, dx[i], orig_dx[i]);
158 }
159 n_record++;
160 emr_processed = TRUE;
161 break;
162 }
163
164 default:
165 break;
166 }
167
168 return 1;
169 }
170
171 static void test_ExtTextOut(void)
172 {
173 HWND hwnd;
174 HDC hdcDisplay, hdcMetafile;
175 HENHMETAFILE hMetafile;
176 HFONT hFont;
177 static const char text[] = "Simple text to test ExtTextOut on metafiles";
178 INT i, len, dx[256];
179 static const RECT rc = { 0, 0, 100, 100 };
180 BOOL ret;
181
182 assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
183
184 /* Win9x doesn't play EMFs on invisible windows */
185 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
186 0, 0, 200, 200, 0, 0, 0, NULL);
187 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
188
189 hdcDisplay = GetDC(hwnd);
190 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
191
192 trace("hdcDisplay %p\n", hdcDisplay);
193
194 SetMapMode(hdcDisplay, MM_TEXT);
195
196 memset(&orig_lf, 0, sizeof(orig_lf));
197
198 orig_lf.lfCharSet = ANSI_CHARSET;
199 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
200 orig_lf.lfWeight = FW_DONTCARE;
201 orig_lf.lfHeight = 7;
202 orig_lf.lfQuality = DEFAULT_QUALITY;
203 lstrcpyA(orig_lf.lfFaceName, "Arial");
204 hFont = CreateFontIndirectA(&orig_lf);
205 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
206
207 hFont = SelectObject(hdcDisplay, hFont);
208
209 len = lstrlenA(text);
210 for (i = 0; i < len; i++)
211 {
212 ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
213 ok( ret, "GetCharWidthA error %d\n", GetLastError());
214 }
215 hFont = SelectObject(hdcDisplay, hFont);
216
217 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
218 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
219
220 trace("hdcMetafile %p\n", hdcMetafile);
221
222 ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
223 "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
224
225 hFont = SelectObject(hdcMetafile, hFont);
226
227 /* 1. pass NULL lpDx */
228 ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
229 ok( ret, "ExtTextOutA error %d\n", GetLastError());
230
231 /* 2. pass custom lpDx */
232 ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
233 ok( ret, "ExtTextOutA error %d\n", GetLastError());
234
235 hFont = SelectObject(hdcMetafile, hFont);
236 ret = DeleteObject(hFont);
237 ok( ret, "DeleteObject error %d\n", GetLastError());
238
239 hMetafile = CloseEnhMetaFile(hdcMetafile);
240 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
241
242 ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
243
244 ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
245 ok( ret, "PlayEnhMetaFile error %d\n", GetLastError());
246
247 SetTextAlign(hdcDisplay, TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING );
248 SetBkColor(hdcDisplay, RGB(0xff, 0, 0));
249 SetTextColor(hdcDisplay, RGB(0, 0xff, 0));
250 SetROP2(hdcDisplay, R2_NOT);
251 SetArcDirection(hdcDisplay, AD_CLOCKWISE);
252 SetPolyFillMode(hdcDisplay, WINDING);
253 SetStretchBltMode(hdcDisplay, HALFTONE);
254
255 if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
256 SetBkMode(hdcDisplay, OPAQUE);
257
258 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
259 ok( ret, "EnumEnhMetaFile error %d\n", GetLastError());
260
261 ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
262 "text align %08x\n", GetTextAlign(hdcDisplay));
263 ok( GetBkColor(hdcDisplay) == RGB(0xff, 0, 0), "bk color %08x\n", GetBkColor(hdcDisplay));
264 ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08x\n", GetTextColor(hdcDisplay));
265 ok( GetROP2(hdcDisplay) == R2_NOT, "rop2 %d\n", GetROP2(hdcDisplay));
266 ok( GetArcDirection(hdcDisplay) == AD_CLOCKWISE, "arc dir %d\n", GetArcDirection(hdcDisplay));
267 ok( GetPolyFillMode(hdcDisplay) == WINDING, "poly fill %d\n", GetPolyFillMode(hdcDisplay));
268 ok( GetStretchBltMode(hdcDisplay) == HALFTONE, "stretchblt mode %d\n", GetStretchBltMode(hdcDisplay));
269
270 ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
271
272 ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
273 "A valid hdc has to require a valid rc\n");
274
275 ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
276 "A null hdc does not require a valid rc\n");
277
278 ret = DeleteEnhMetaFile(hMetafile);
279 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
280 ret = ReleaseDC(hwnd, hdcDisplay);
281 ok( ret, "ReleaseDC error %d\n", GetLastError());
282 DestroyWindow(hwnd);
283 }
284
285 struct eto_scale_test_record
286 {
287 INT graphics_mode;
288 INT map_mode;
289 double ex_scale;
290 double ey_scale;
291 BOOL processed;
292 };
293
294 static int CALLBACK eto_scale_enum_proc(HDC hdc, HANDLETABLE *handle_table,
295 const ENHMETARECORD *emr, int n_objs, LPARAM param)
296 {
297 struct eto_scale_test_record *test = (struct eto_scale_test_record*)param;
298
299 if (emr->iType == EMR_EXTTEXTOUTW)
300 {
301 const EMREXTTEXTOUTW *pExtTextOutW = (const EMREXTTEXTOUTW *)emr;
302 trace("gm %d, mm %d, scale %f, %f, expected %f, %f\n",
303 test->graphics_mode, test->map_mode,
304 pExtTextOutW->exScale, pExtTextOutW->eyScale,
305 test->ex_scale, test->ey_scale);
306 ok(fabs(test->ex_scale - pExtTextOutW->exScale) < 0.001,
307 "Got exScale %f, expected %f\n", pExtTextOutW->exScale, test->ex_scale);
308 ok(fabs(test->ey_scale - pExtTextOutW->eyScale) < 0.001,
309 "Got eyScale %f, expected %f\n", pExtTextOutW->eyScale, test->ey_scale);
310 test->processed = TRUE;
311 }
312
313 return 1;
314 }
315
316 static void test_ExtTextOutScale(void)
317 {
318 const RECT rc = { 0, 0, 100, 100 };
319 const WCHAR str[] = {'a',0 };
320 struct eto_scale_test_record test;
321 HDC hdcDisplay, hdcMetafile;
322 HENHMETAFILE hMetafile;
323 HWND hwnd;
324 SIZE wndext, vportext;
325 int horzSize, vertSize, horzRes, vertRes;
326 int ret;
327 int i;
328
329 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
330 0, 0, 200, 200, 0, 0, 0, NULL);
331 ok(hwnd != 0, "CreateWindowExA failed\n");
332
333 hdcDisplay = GetDC(hwnd);
334 ok(hdcDisplay != 0, "GetDC failed\n");
335
336 horzSize = GetDeviceCaps(hdcDisplay, HORZSIZE);
337 horzRes = GetDeviceCaps(hdcDisplay, HORZRES);
338 vertSize = GetDeviceCaps(hdcDisplay, VERTSIZE);
339 vertRes = GetDeviceCaps(hdcDisplay, VERTRES);
340 ok(horzSize && horzRes && vertSize && vertRes, "GetDeviceCaps failed\n");
341
342 for (i = 0; i < 16; i++)
343 {
344 test.graphics_mode = i / 8 + 1;
345 test.map_mode = i % 8 + 1;
346
347 ret = SetGraphicsMode(hdcDisplay, test.graphics_mode);
348 ok(ret, "SetGraphicsMode failed\n");
349 ret = SetMapMode(hdcDisplay, test.map_mode);
350 ok(ret, "SetMapMode failed\n");
351
352 if ((test.map_mode == MM_ISOTROPIC) || (test.map_mode == MM_ANISOTROPIC))
353 {
354 ret = SetWindowExtEx(hdcDisplay, 1, 1, NULL);
355 ok(ret, "SetWindowExtEx failed\n");
356 ret = SetViewportExtEx(hdcDisplay, -20, -10, NULL);
357 ok(ret, "SetViewportExtEx failed\n");
358 }
359
360 ret = GetViewportExtEx(hdcDisplay, &vportext);
361 ok(ret, "GetViewportExtEx failed\n");
362 ret = GetWindowExtEx(hdcDisplay, &wndext);
363 ok(ret, "GetWindowExtEx failed\n");
364
365 trace("gm %d, mm %d, wnd %d,%d, vp %d,%d horz %d,%d vert %d,%d\n",
366 test.graphics_mode, test.map_mode,
367 wndext.cx, wndext.cy, vportext.cx, vportext.cy,
368 horzSize, horzRes, vertSize, vertRes);
369
370 if (test.graphics_mode == GM_COMPATIBLE)
371 {
372 test.ex_scale = 100.0 * ((FLOAT)horzSize / (FLOAT)horzRes) /
373 ((FLOAT)wndext.cx / (FLOAT)vportext.cx);
374 test.ey_scale = 100.0 * ((FLOAT)vertSize / (FLOAT)vertRes) /
375 ((FLOAT)wndext.cy / (FLOAT)vportext.cy);
376 }
377 else
378 {
379 test.ex_scale = 0.0;
380 test.ey_scale = 0.0;
381 }
382
383 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
384 ok(hdcMetafile != 0, "CreateEnhMetaFileA failed\n");
385
386 ret = SetGraphicsMode(hdcMetafile, test.graphics_mode);
387 ok(ret, "SetGraphicsMode failed\n");
388 ret = SetMapMode(hdcMetafile, test.map_mode);
389 ok(ret, "SetMapMode failed\n");
390
391 if ((test.map_mode == MM_ISOTROPIC) || (test.map_mode == MM_ANISOTROPIC))
392 {
393 ret = SetWindowExtEx(hdcMetafile, 1, 1, NULL);
394 ok(ret, "SetWindowExtEx failed\n");
395 ret = SetViewportExtEx(hdcMetafile, -20, -10, NULL);
396 ok(ret, "SetViewportExtEx failed\n");
397 }
398
399 ret = ExtTextOutW(hdcMetafile, 0, 0, 0, 0, str, 1, NULL);
400 ok(ret, "ExtTextOutW failed\n");
401
402 hMetafile = CloseEnhMetaFile(hdcMetafile);
403 ok(hMetafile != 0, "CloseEnhMetaFile failed\n");
404
405 test.processed = 0;
406 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_scale_enum_proc, &test, &rc);
407 ok(ret, "EnumEnhMetaFile failed\n");
408 ok(test.processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTW record\n");
409
410 ret = DeleteEnhMetaFile(hMetafile);
411 ok(ret, "DeleteEnhMetaFile failed\n");
412 }
413
414 ret = ReleaseDC(hwnd, hdcDisplay);
415 ok(ret, "ReleaseDC failed\n");
416 DestroyWindow(hwnd);
417 }
418
419
420 static void check_dc_state(HDC hdc, int restore_no,
421 int wnd_org_x, int wnd_org_y, int wnd_ext_x, int wnd_ext_y,
422 int vp_org_x, int vp_org_y, int vp_ext_x, int vp_ext_y)
423 {
424 BOOL ret;
425 XFORM xform;
426 POINT vp_org, win_org;
427 SIZE vp_size, win_size;
428 FLOAT xscale, yscale, edx, edy;
429
430 SetLastError(0xdeadbeef);
431 ret = GetWorldTransform(hdc, &xform);
432 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) goto win9x_here;
433 ok(ret, "GetWorldTransform error %u\n", GetLastError());
434
435 trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
436
437 ok(xform.eM12 == 0.0, "%d: expected eM12 0.0, got %f\n", restore_no, xform.eM12);
438 ok(xform.eM21 == 0.0, "%d: expected eM21 0.0, got %f\n", restore_no, xform.eM21);
439
440 xscale = (FLOAT)vp_ext_x / (FLOAT)wnd_ext_x;
441 trace("x scale %f\n", xscale);
442 ok(fabs(xscale - xform.eM11) < 0.01, "%d: vp_ext_x %d, wnd_ext_cx %d, eM11 %f\n",
443 restore_no, vp_ext_x, wnd_ext_x, xform.eM11);
444
445 yscale = (FLOAT)vp_ext_y / (FLOAT)wnd_ext_y;
446 trace("y scale %f\n", yscale);
447 ok(fabs(yscale - xform.eM22) < 0.01, "%d: vp_ext_y %d, wnd_ext_y %d, eM22 %f\n",
448 restore_no, vp_ext_y, wnd_ext_y, xform.eM22);
449
450 edx = (FLOAT)vp_org_x - xform.eM11 * (FLOAT)wnd_org_x;
451 ok(fabs(edx - xform.eDx) < 0.01, "%d: edx %f != eDx %f\n", restore_no, edx, xform.eDx);
452 edy = (FLOAT)vp_org_y - xform.eM22 * (FLOAT)wnd_org_y;
453 ok(fabs(edy - xform.eDy) < 0.01, "%d: edy %f != eDy %f\n", restore_no, edy, xform.eDy);
454
455 return;
456
457 win9x_here:
458
459 GetWindowOrgEx(hdc, &win_org);
460 GetViewportOrgEx(hdc, &vp_org);
461 GetWindowExtEx(hdc, &win_size);
462 GetViewportExtEx(hdc, &vp_size);
463
464 ok(wnd_org_x == win_org.x, "%d: wnd_org_x: %d != %d\n", restore_no, wnd_org_x, win_org.x);
465 ok(wnd_org_y == win_org.y, "%d: wnd_org_y: %d != %d\n", restore_no, wnd_org_y, win_org.y);
466
467 ok(vp_org_x == vp_org.x, "%d: vport_org_x: %d != %d\n", restore_no, vp_org_x, vp_org.x);
468 ok(vp_org_y == vp_org.y, "%d: vport_org_y: %d != %d\n", restore_no, vp_org_y, vp_org.y);
469
470 ok(wnd_ext_x == win_size.cx, "%d: wnd_ext_x: %d != %d\n", restore_no, wnd_ext_x, win_size.cx);
471 ok(wnd_ext_y == win_size.cy, "%d: wnd_ext_y: %d != %d\n", restore_no, wnd_ext_y, win_size.cy);
472
473 ok(vp_ext_x == vp_size.cx, "%d: vport_ext_x: %d != %d\n", restore_no, vp_ext_x, vp_size.cx);
474 ok(vp_ext_y == vp_size.cy, "%d: vport_ext_y: %d != %d\n", restore_no, vp_ext_y, vp_size.cy);
475 }
476
477 static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
478 const ENHMETARECORD *emr, int n_objs, LPARAM param)
479 {
480 BOOL ret;
481 XFORM xform;
482 POINT pt;
483 SIZE size;
484 static int save_state;
485 static int restore_no;
486 static int select_no;
487
488 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
489 hdc, emr->iType, emr->nSize, (void *)param);
490
491 trace("BEFORE:\n");
492 SetLastError(0xdeadbeef);
493 ret = GetWorldTransform(hdc, &xform);
494 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
495 {
496 ret = GetWindowOrgEx(hdc, &pt);
497 ok(ret, "GetWindowOrgEx error %u\n", GetLastError());
498 trace("window org (%d,%d)\n", pt.x, pt.y);
499 ret = GetViewportOrgEx(hdc, &pt);
500 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
501 trace("vport org (%d,%d)\n", pt.x, pt.y);
502 ret = GetWindowExtEx(hdc, &size);
503 ok(ret, "GetWindowExtEx error %u\n", GetLastError());
504 trace("window ext (%d,%d)\n", size.cx, size.cy);
505 ret = GetViewportExtEx(hdc, &size);
506 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
507 trace("vport ext (%d,%d)\n", size.cx, size.cy);
508 }
509 else
510 {
511 ok(ret, "GetWorldTransform error %u\n", GetLastError());
512 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
513 }
514
515 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
516
517 switch (emr->iType)
518 {
519 case EMR_HEADER:
520 {
521 static RECT exp_bounds = { 0, 0, 150, 150 };
522 RECT bounds;
523 const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
524
525 trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
526 emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
527 emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
528 trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
529 emf->szlDevice.cx, emf->szlDevice.cy);
530
531 SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
532 ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
533
534 save_state = 0;
535 restore_no = 0;
536 select_no = 0;
537 check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
538 break;
539 }
540
541 case EMR_LINETO:
542 {
543 const EMRLINETO *line = (const EMRLINETO *)emr;
544 trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
545 break;
546 }
547 case EMR_SETWINDOWORGEX:
548 {
549 const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
550 trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
551 break;
552 }
553 case EMR_SETWINDOWEXTEX:
554 {
555 const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
556 trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
557 break;
558 }
559 case EMR_SETVIEWPORTORGEX:
560 {
561 const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
562 trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
563 break;
564 }
565 case EMR_SETVIEWPORTEXTEX:
566 {
567 const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
568 trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
569 break;
570 }
571 case EMR_SAVEDC:
572 save_state++;
573 trace("EMR_SAVEDC\n");
574 break;
575
576 case EMR_RESTOREDC:
577 {
578 const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
579 trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
580
581 switch(++restore_no)
582 {
583 case 1:
584 ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
585 check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
586 break;
587 case 2:
588 ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
589 check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
590 break;
591 case 3:
592 ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
593 check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
594 break;
595 }
596 ok(restore_no <= 3, "restore_no %d\n", restore_no);
597 save_state += restoredc->iRelative;
598 break;
599 }
600 case EMR_SELECTOBJECT:
601 {
602 const EMRSELECTOBJECT *selectobj = (const EMRSELECTOBJECT*)emr;
603 trace("EMR_SELECTOBJECT: %x\n",selectobj->ihObject);
604 select_no ++;
605 break;
606 }
607 case EMR_EOF:
608 ok(save_state == 0, "EOF save_state %d\n", save_state);
609 ok(select_no == 3, "Too many/few selects %i\n",select_no);
610 break;
611 }
612
613 trace("AFTER:\n");
614 SetLastError(0xdeadbeef);
615 ret = GetWorldTransform(hdc, &xform);
616 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
617 {
618 ret = GetWindowOrgEx(hdc, &pt);
619 ok(ret, "GetWindowOrgEx error %u\n", GetLastError());
620 trace("window org (%d,%d)\n", pt.x, pt.y);
621 ret = GetViewportOrgEx(hdc, &pt);
622 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
623 trace("vport org (%d,%d)\n", pt.x, pt.y);
624 ret = GetWindowExtEx(hdc, &size);
625 ok(ret, "GetWindowExtEx error %u\n", GetLastError());
626 trace("window ext (%d,%d)\n", size.cx, size.cy);
627 ret = GetViewportExtEx(hdc, &size);
628 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
629 trace("vport ext (%d,%d)\n", size.cx, size.cy);
630 }
631 else
632 {
633 ok(ret, "GetWorldTransform error %u\n", GetLastError());
634 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
635 }
636
637 return 1;
638 }
639
640 static void test_SaveDC(void)
641 {
642 HDC hdcMetafile, hdcDisplay;
643 HENHMETAFILE hMetafile;
644 HWND hwnd;
645 int ret;
646 POINT pt;
647 SIZE size;
648 HFONT hFont,hFont2,hFontOld,hFontCheck;
649 static const RECT rc = { 0, 0, 150, 150 };
650
651 /* Win9x doesn't play EMFs on invisible windows */
652 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
653 0, 0, 200, 200, 0, 0, 0, NULL);
654 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
655
656 hdcDisplay = GetDC(hwnd);
657 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
658
659 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
660 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
661
662 SetMapMode(hdcMetafile, MM_ANISOTROPIC);
663
664 /* Need to write something to the emf, otherwise Windows won't play it back */
665 LineTo(hdcMetafile, 150, 150);
666
667 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
668 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
669 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
670 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
671
672 /* Force Win9x to update DC state */
673 SetPixelV(hdcMetafile, 50, 50, 0);
674
675 ret = GetViewportOrgEx(hdcMetafile, &pt);
676 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
677 ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
678 ret = GetViewportExtEx(hdcMetafile, &size);
679 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
680 ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
681 ret = SaveDC(hdcMetafile);
682 ok(ret == 1, "ret = %d\n", ret);
683
684 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
685 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
686 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
687 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
688
689 /* Force Win9x to update DC state */
690 SetPixelV(hdcMetafile, 50, 50, 0);
691
692 ret = GetViewportOrgEx(hdcMetafile, &pt);
693 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
694 ok(pt.x == 10,"Expecting ViewportOrg x of 10, got %i\n",pt.x);
695 ret = GetViewportExtEx(hdcMetafile, &size);
696 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
697 ok(size.cx == 200,"Expecting ViewportExt cx of 200, got %i\n",size.cx);
698 ret = SaveDC(hdcMetafile);
699 ok(ret == 2, "ret = %d\n", ret);
700
701 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
702 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
703 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
704 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
705 SetPolyFillMode( hdcMetafile, ALTERNATE );
706 SetBkColor( hdcMetafile, 0 );
707
708 /* Force Win9x to update DC state */
709 SetPixelV(hdcMetafile, 50, 50, 0);
710
711 ret = GetViewportOrgEx(hdcMetafile, &pt);
712 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
713 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
714 ret = GetViewportExtEx(hdcMetafile, &size);
715 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
716 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
717 ret = SaveDC(hdcMetafile);
718 ok(ret == 3, "ret = %d\n", ret);
719
720 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
721 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
722 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
723 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
724
725 SetPolyFillMode( hdcMetafile, WINDING );
726 SetBkColor( hdcMetafile, 0x123456 );
727 ok( GetPolyFillMode( hdcMetafile ) == WINDING, "PolyFillMode not restored\n" );
728 ok( GetBkColor( hdcMetafile ) == 0x123456, "Background color not restored\n" );
729
730 /* Force Win9x to update DC state */
731 SetPixelV(hdcMetafile, 50, 50, 0);
732
733 ret = GetViewportOrgEx(hdcMetafile, &pt);
734 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
735 ok(pt.x == 30,"Expecting ViewportOrg x of 30, got %i\n",pt.x);
736 ret = GetViewportExtEx(hdcMetafile, &size);
737 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
738 ok(size.cx == 400,"Expecting ViewportExt cx of 400, got %i\n",size.cx);
739 ret = RestoreDC(hdcMetafile, -1);
740 ok(ret, "ret = %d\n", ret);
741
742 ret = GetViewportOrgEx(hdcMetafile, &pt);
743 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
744 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
745 ret = GetViewportExtEx(hdcMetafile, &size);
746 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
747 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
748 ok( GetPolyFillMode( hdcMetafile ) == ALTERNATE, "PolyFillMode not restored\n" );
749 ok( GetBkColor( hdcMetafile ) == 0, "Background color not restored\n" );
750 ret = SaveDC(hdcMetafile);
751 ok(ret == 3, "ret = %d\n", ret);
752
753 ret = GetViewportOrgEx(hdcMetafile, &pt);
754 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
755 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
756 ret = GetViewportExtEx(hdcMetafile, &size);
757 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
758 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
759 ret = RestoreDC(hdcMetafile, 1);
760 ok(ret, "ret = %d\n", ret);
761 ret = GetViewportOrgEx(hdcMetafile, &pt);
762 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
763 ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
764 ret = GetViewportExtEx(hdcMetafile, &size);
765 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
766 ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
767
768 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
769 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
770 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
771 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
772
773 /* Force Win9x to update DC state */
774 SetPixelV(hdcMetafile, 50, 50, 0);
775
776 ret = GetViewportOrgEx(hdcMetafile, &pt);
777 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
778 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
779 ret = GetViewportExtEx(hdcMetafile, &size);
780 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
781 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
782 ret = SaveDC(hdcMetafile);
783 ok(ret == 1, "ret = %d\n", ret);
784
785 ret = GetViewportOrgEx(hdcMetafile, &pt);
786 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
787 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
788 ret = GetViewportExtEx(hdcMetafile, &size);
789 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
790 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
791 ret = SaveDC(hdcMetafile);
792 ok(ret == 2, "ret = %d\n", ret);
793
794 memset(&orig_lf, 0, sizeof(orig_lf));
795 orig_lf.lfCharSet = ANSI_CHARSET;
796 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
797 orig_lf.lfWeight = FW_DONTCARE;
798 orig_lf.lfHeight = 7;
799 orig_lf.lfQuality = DEFAULT_QUALITY;
800 lstrcpyA(orig_lf.lfFaceName, "Arial");
801 hFont = CreateFontIndirectA(&orig_lf);
802 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
803
804 hFontOld = SelectObject(hdcMetafile, hFont);
805
806 hFont2 = CreateFontIndirectA(&orig_lf);
807 ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
808 hFontCheck = SelectObject(hdcMetafile, hFont2);
809 ok(hFontCheck == hFont, "Font not selected\n");
810
811 /* Force Win9x to update DC state */
812 SetPixelV(hdcMetafile, 50, 50, 0);
813
814 ret = RestoreDC(hdcMetafile, 1);
815 ok(ret, "ret = %d\n", ret);
816 ret = GetViewportOrgEx(hdcMetafile, &pt);
817 ok(ret, "GetViewportOrgEx error %u\n", GetLastError());
818 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
819 ret = GetViewportExtEx(hdcMetafile, &size);
820 ok(ret, "GetViewportExtEx error %u\n", GetLastError());
821 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
822
823 hFontCheck = SelectObject(hdcMetafile, hFontOld);
824 ok(hFontOld == hFontCheck && hFontCheck != hFont && hFontCheck != hFont2,
825 "Font not reverted with DC Restore\n");
826
827 ret = RestoreDC(hdcMetafile, -20);
828 ok(!ret, "ret = %d\n", ret);
829 ret = RestoreDC(hdcMetafile, 20);
830 ok(!ret, "ret = %d\n", ret);
831
832 hMetafile = CloseEnhMetaFile(hdcMetafile);
833 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
834
835 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
836 ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
837
838 ret = DeleteObject(hFont);
839 ok( ret, "DeleteObject error %d\n", GetLastError());
840 ret = DeleteObject(hFont2);
841 ok( ret, "DeleteObject error %d\n", GetLastError());
842 ret = DeleteEnhMetaFile(hMetafile);
843 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
844 ret = ReleaseDC(hwnd, hdcDisplay);
845 ok( ret, "ReleaseDC error %d\n", GetLastError());
846 DestroyWindow(hwnd);
847 }
848
849 static void test_mf_SaveDC(void)
850 {
851 HDC hdcMetafile;
852 HMETAFILE hMetafile;
853 int ret;
854 POINT pt;
855 SIZE size;
856 HFONT hFont,hFont2,hFontOld,hFontCheck;
857
858 hdcMetafile = CreateMetaFileA(NULL);
859 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
860
861 ret = SetMapMode(hdcMetafile, MM_ANISOTROPIC);
862 ok (ret, "SetMapMode should not fail\n");
863
864 /* Need to write something to the emf, otherwise Windows won't play it back */
865 LineTo(hdcMetafile, 150, 150);
866
867 pt.x = pt.y = 5555;
868 SetWindowOrgEx(hdcMetafile, 0, 0, &pt);
869 ok( pt.x == 5555 && pt.y == 5555, "wrong origin %d,%d\n", pt.x, pt.y);
870 pt.x = pt.y = 5555;
871 SetViewportOrgEx(hdcMetafile, 0, 0, &pt);
872 ok( pt.x == 5555 && pt.y == 5555, "wrong origin %d,%d\n", pt.x, pt.y);
873 size.cx = size.cy = 5555;
874 SetWindowExtEx(hdcMetafile, 110, 110, &size );
875 ok( size.cx == 5555 && size.cy == 5555, "wrong size %d,%d\n", size.cx, size.cy );
876 size.cx = size.cy = 5555;
877 SetViewportExtEx(hdcMetafile, 120, 120, &size );
878 ok( size.cx == 5555 && size.cy == 5555, "wrong size %d,%d\n", size.cx, size.cy );
879
880 /* Force Win9x to update DC state */
881 SetPixelV(hdcMetafile, 50, 50, 0);
882
883 ret = GetViewportOrgEx(hdcMetafile, &pt);
884 todo_wine ok (!ret, "GetViewportOrgEx should fail\n");
885 ret = GetViewportExtEx(hdcMetafile, &size);
886 todo_wine ok (!ret, "GetViewportExtEx should fail\n");
887 ret = SaveDC(hdcMetafile);
888 ok(ret == 1, "ret = %d\n", ret);
889
890 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
891 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
892 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
893 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
894
895 /* Force Win9x to update DC state */
896 SetPixelV(hdcMetafile, 50, 50, 0);
897
898 ret = SaveDC(hdcMetafile);
899 ok(ret == 1, "ret = %d\n", ret);
900
901 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
902 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
903 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
904 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
905
906 /* Force Win9x to update DC state */
907 SetPixelV(hdcMetafile, 50, 50, 0);
908 SetPolyFillMode( hdcMetafile, ALTERNATE );
909 SetBkColor( hdcMetafile, 0 );
910
911 ret = SaveDC(hdcMetafile);
912 ok(ret == 1, "ret = %d\n", ret);
913
914 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
915 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
916 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
917 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
918
919 SetPolyFillMode( hdcMetafile, WINDING );
920 SetBkColor( hdcMetafile, 0x123456 );
921 todo_wine ok( !GetPolyFillMode( hdcMetafile ), "GetPolyFillMode succeeded\n" );
922 todo_wine ok( GetBkColor( hdcMetafile ) == CLR_INVALID, "GetBkColor succeeded\n" );
923
924 /* Force Win9x to update DC state */
925 SetPixelV(hdcMetafile, 50, 50, 0);
926
927 ret = RestoreDC(hdcMetafile, -1);
928 ok(ret, "ret = %d\n", ret);
929
930 ret = SaveDC(hdcMetafile);
931 ok(ret == 1, "ret = %d\n", ret);
932
933 ret = RestoreDC(hdcMetafile, 1);
934 ok(ret, "ret = %d\n", ret);
935
936 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
937 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
938 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
939 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
940
941 /* Force Win9x to update DC state */
942 SetPixelV(hdcMetafile, 50, 50, 0);
943
944 ret = SaveDC(hdcMetafile);
945 ok(ret == 1, "ret = %d\n", ret);
946
947 ret = SaveDC(hdcMetafile);
948 ok(ret == 1, "ret = %d\n", ret);
949
950 memset(&orig_lf, 0, sizeof(orig_lf));
951 orig_lf.lfCharSet = ANSI_CHARSET;
952 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
953 orig_lf.lfWeight = FW_DONTCARE;
954 orig_lf.lfHeight = 7;
955 orig_lf.lfQuality = DEFAULT_QUALITY;
956 lstrcpyA(orig_lf.lfFaceName, "Arial");
957 hFont = CreateFontIndirectA(&orig_lf);
958 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
959
960 hFontOld = SelectObject(hdcMetafile, hFont);
961
962 hFont2 = CreateFontIndirectA(&orig_lf);
963 ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
964 hFontCheck = SelectObject(hdcMetafile, hFont2);
965 ok(hFontCheck == hFont, "Font not selected\n");
966
967 /* Force Win9x to update DC state */
968 SetPixelV(hdcMetafile, 50, 50, 0);
969
970 ret = RestoreDC(hdcMetafile, 1);
971 ok(ret, "ret = %d\n", ret);
972
973 hFontCheck = SelectObject(hdcMetafile, hFontOld);
974 ok(hFontOld != hFontCheck && hFontCheck == hFont2, "Font incorrectly reverted with DC Restore\n");
975
976 /* restore level is ignored */
977 ret = RestoreDC(hdcMetafile, -20);
978 ok(ret, "ret = %d\n", ret);
979 ret = RestoreDC(hdcMetafile, 20);
980 ok(ret, "ret = %d\n", ret);
981 ret = RestoreDC(hdcMetafile, 0);
982 ok(ret, "ret = %d\n", ret);
983
984 hMetafile = CloseMetaFile(hdcMetafile);
985 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
986
987 ret = DeleteMetaFile(hMetafile);
988 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
989 ret = DeleteObject(hFont);
990 ok( ret, "DeleteObject error %d\n", GetLastError());
991 ret = DeleteObject(hFont2);
992 ok( ret, "DeleteObject error %d\n", GetLastError());
993 }
994
995
996 /* Win-format metafile (mfdrv) tests */
997 /* These tests compare the generated metafiles byte-by-byte */
998 /* with the nominal results. */
999
1000 /* Maximum size of sample metafiles in bytes. */
1001 #define MF_BUFSIZE 512
1002
1003 /* 8x8 bitmap data for a pattern brush */
1004 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
1005 0x01, 0x00, 0x02, 0x00,
1006 0x03, 0x00, 0x04, 0x00,
1007 0x05, 0x00, 0x06, 0x00,
1008 0x07, 0x00, 0x08, 0x00
1009 };
1010
1011 /* Sample metafiles to be compared to the outputs of the
1012 * test functions.
1013 */
1014
1015 static const unsigned char MF_BLANK_BITS[] = {
1016 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
1017 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1018 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
1019 };
1020
1021 static const unsigned char MF_GRAPHICS_BITS[] = {
1022 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
1023 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
1024 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
1025 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
1026 0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
1027 0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
1028 0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
1029 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
1030 0x00, 0x00, 0x00, 0x00
1031 };
1032
1033 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
1034 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
1035 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
1036 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
1037 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
1038 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
1039 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1040 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1043 0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
1044 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
1045 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1046 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1047 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1048 0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1049 0x00, 0x00
1050 };
1051
1052 static const unsigned char MF_DCBRUSH_BITS[] =
1053 {
1054 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x2a, 0x00,
1055 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
1056 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xfc, 0x02,
1057 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
1058 0x04, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00,
1059 0x08, 0x00, 0x00, 0x00, 0xfa, 0x02, 0x00, 0x00,
1060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1061 0x04, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x01, 0x00,
1062 0x07, 0x00, 0x00, 0x00, 0x1b, 0x04, 0x14, 0x00,
1063 0x14, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x03, 0x00,
1064 0x00, 0x00, 0x00, 0x00
1065 };
1066
1067 static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
1068 {
1069 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
1070 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
1071 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
1072 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
1073 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
1074 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
1075 0x00, 0x00
1076 };
1077
1078 static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
1079 {
1080 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1081 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1082 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1083 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1084 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
1085 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1086 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1087 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1088 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1089 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1090 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
1091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1092 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
1093 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
1094 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
1095 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1096 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
1097 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
1098 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
1099 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
1100 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
1101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1102 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
1103 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
1104 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
1105 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1106 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1107 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
1108 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1109 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1110 0x14, 0x00, 0x00, 0x00
1111 };
1112
1113 static const unsigned char MF_LINETO_BITS[] = {
1114 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
1115 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1116 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
1117 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
1118 0x00, 0x00
1119 };
1120
1121 static const unsigned char EMF_LINETO_BITS[] = {
1122 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1124 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1126 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
1127 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1128 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1129 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1131 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1132 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1134 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1135 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
1136 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
1137 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
1138 0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
1139 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
1140 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
1141 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1142 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
1143 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
1144 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
1145 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
1146 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1147 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1148 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1149 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1150 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1151 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1152 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1153 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
1154 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1155 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1156 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
1157 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1158 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1159 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1160 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1161 };
1162
1163 static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
1164 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1166 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1168 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1169 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1170 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1171 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1173 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1174 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1176 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1177 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
1178 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
1179 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
1180 0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
1181 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
1182 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
1183 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1184 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
1185 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
1186 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
1187 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
1188 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1189 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1190 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1191 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1192 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1193 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1194 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1195 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
1196 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1197 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1198 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
1199 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1200 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1201 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1202 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1203 };
1204
1205 static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
1206 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1208 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1210 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
1211 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1212 0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1213 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1215 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1216 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1218 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1219 0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
1220 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
1221 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1222 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
1223 0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
1224 0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
1225 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
1226 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
1227 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1228 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
1229 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
1230 0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1231 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1232 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1233 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1234 0x14, 0x00, 0x00, 0x00
1235 };
1236
1237 static const unsigned char EMF_BITBLT[] =
1238 {
1239 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1241 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1243 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00,
1244 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1245 0xa0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1246 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1248 0x23, 0x04, 0x00, 0x00, 0x3b, 0x02, 0x00, 0x00,
1249 0x75, 0x01, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00,
1250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1251 0x00, 0x00, 0x00, 0x00, 0x08, 0xb1, 0x05, 0x00,
1252 0x28, 0x11, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00,
1253 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1254 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1255 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1256 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1257 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0xcc, 0x00,
1258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1259 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
1260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
1261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1262 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
1263 0x64, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
1264 0x8c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1265 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1266 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00,
1267 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1271 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1272 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1274 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1275 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1276 0x4c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1278 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1280 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1281 0x62, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
1282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
1283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1284 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
1285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1288 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1289 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1290 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1291 };
1292
1293 static const unsigned char EMF_DCBRUSH_BITS[] =
1294 {
1295 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1296 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
1297 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
1298 0x39, 0x01, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00,
1299 0x52, 0x02, 0x00, 0x00, 0x52, 0x02, 0x00, 0x00,
1300 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1301 0x44, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1302 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1304 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
1305 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
1306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1307 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
1308 0x80, 0xa9, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00,
1309 0x0c, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x80,
1310 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1311 0x13, 0x00, 0x00, 0x80, 0x27, 0x00, 0x00, 0x00,
1312 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1313 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x00,
1314 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
1315 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1316 0x26, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
1317 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1319 0x33, 0x44, 0x55, 0x00, 0x25, 0x00, 0x00, 0x00,
1320 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1321 0x2b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
1322 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
1323 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
1324 0x28, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1325 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
1326 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1327 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x00,
1328 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
1329 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1330 0x28, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1331 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
1332 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1333 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1334 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1335 0x14, 0x00, 0x00, 0x00
1336 };
1337
1338 static const unsigned char EMF_BEZIER_BITS[] =
1339 {
1340 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1342 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
1343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1344 0x1a, 0x2a, 0x0d, 0x00, 0x1a, 0x2f, 0x0d, 0x00,
1345 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1346 0x44, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
1347 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1349 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1350 0x51, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00,
1351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1352 0x00, 0x00, 0x00, 0x00, 0x68, 0x24, 0x05, 0x00,
1353 0xb0, 0x1e, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00,
1354 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1355 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1356 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1357 0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x14, 0x00,
1358 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x00, 0x00, 0x00,
1359 0x2c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
1360 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
1361 0x19, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1362 0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x14, 0x00,
1363 0x0f, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x19, 0x00,
1364 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
1365 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1366 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
1367 0x04, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
1368 0x01, 0x80, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1369 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1370 0x0f, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
1371 0x19, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1372 0x34, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1373 0x0f, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
1374 0x01, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1375 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00,
1376 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1377 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1378 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1379 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1380 0x14, 0x00, 0x00, 0x00
1381 };
1382
1383 /* For debugging or dumping the raw metafiles produced by
1384 * new test functions.
1385 */
1386 static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
1387 INT nobj, LPARAM param)
1388 {
1389 trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, param %p\n",
1390 hdc, mr->rdFunction, mr->rdSize, (void *)param);
1391 return TRUE;
1392 }
1393
1394 /* For debugging or dumping the raw metafiles produced by
1395 * new test functions.
1396 */
1397
1398 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
1399 {
1400 BYTE buf[MF_BUFSIZE];
1401 UINT mfsize, i;
1402
1403 if (!winetest_debug) return;
1404
1405 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
1406 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
1407
1408 printf ("MetaFile %s has bits:\n{\n ", desc);
1409 for (i=0; i<mfsize; i++)
1410 {
1411 printf ("0x%02x", buf[i]);
1412 if (i == mfsize-1)
1413 printf ("\n");
1414 else if (i % 8 == 7)
1415 printf (",\n ");
1416 else
1417 printf (", ");
1418 }
1419 printf ("};\n");
1420 }
1421
1422 /* Compare the metafile produced by a test function with the
1423 * expected raw metafile data in "bits".
1424 * Return value is 0 for a perfect match,
1425 * -1 if lengths aren't equal,
1426 * otherwise returns the number of non-matching bytes.
1427 */
1428
1429 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
1430 const char *desc)
1431 {
1432 unsigned char buf[MF_BUFSIZE];
1433 UINT mfsize, i;
1434 int diff;
1435
1436 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
1437 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
1438 if (mfsize < MF_BUFSIZE)
1439 ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
1440 desc, mfsize, bsize);
1441 else
1442 ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
1443 desc, mfsize, bsize);
1444 if (mfsize != bsize)
1445 return -1;
1446
1447 diff = 0;
1448 for (i=0; i<bsize; i++)
1449 {
1450 if (buf[i] != bits[i])
1451 diff++;
1452 }
1453 ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1454 desc, mfsize, bsize, diff);
1455
1456 return diff;
1457 }
1458
1459 static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
1460 {
1461 unsigned char buf[MF_BUFSIZE];
1462 DWORD mfsize, rd_size, i;
1463 int diff;
1464 HANDLE hfile;
1465 BOOL ret;
1466
1467 hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1468 assert(hfile != INVALID_HANDLE_VALUE);
1469
1470 mfsize = GetFileSize(hfile, NULL);
1471 assert(mfsize <= MF_BUFSIZE);
1472
1473 ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
1474 ok( ret && rd_size == mfsize, "ReadFile: error %d\n", GetLastError());
1475
1476 CloseHandle(hfile);
1477
1478 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n", desc, mfsize, bsize);
1479
1480 if (mfsize != bsize)
1481 return -1;
1482
1483 diff = 0;
1484 for (i=0; i<bsize; i++)
1485 {
1486 if (buf[i] != bits[i])
1487 diff++;
1488 }
1489 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1490 desc, mfsize, bsize, diff);
1491
1492 return diff;
1493 }
1494
1495 /* For debugging or dumping the raw EMFs produced by
1496 * new test functions.
1497 */
1498 static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
1499 {
1500 BYTE buf[MF_BUFSIZE];
1501 UINT mfsize, i;
1502
1503 if (!winetest_debug) return;
1504
1505 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1506 ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
1507
1508 printf("EMF %s has bits:\n{\n ", desc);
1509 for (i = 0; i < mfsize; i++)
1510 {
1511 printf ("0x%02x", buf[i]);
1512 if (i == mfsize-1)
1513 printf ("\n");
1514 else if (i % 8 == 7)
1515 printf (",\n ");
1516 else
1517 printf (", ");
1518 }
1519 printf ("};\n");
1520 }
1521
1522 static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
1523 {
1524 BYTE *emf;
1525 BYTE buf[MF_BUFSIZE];
1526 UINT mfsize, offset;
1527
1528 if (!winetest_debug) return;
1529
1530 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1531 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1532
1533 printf("EMF %s has records:\n", desc);
1534
1535 emf = buf;
1536 offset = 0;
1537 while(offset < mfsize)
1538 {
1539 EMR *emr = (EMR *)(emf + offset);
1540 printf("emr->iType %d, emr->nSize %u\n", emr->iType, emr->nSize);
1541 /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
1542 offset += emr->nSize;
1543 }
1544 }
1545
1546 static void dump_emf_record(const ENHMETARECORD *emr, const char *desc)
1547 {
1548 const BYTE *buf;
1549 DWORD i;
1550
1551 if (!winetest_debug) return;
1552
1553 printf ("%s: EMF record %u has bits:\n{\n", desc, emr->iType);
1554 buf = (const BYTE *)emr;
1555 for (i = 0; i < emr->nSize; i++)
1556 {
1557 printf ("0x%02x", buf[i]);
1558 if (i == emr->nSize - 1)
1559 printf ("\n");
1560 else if (i % 8 == 7)
1561 printf (",\n");
1562 else
1563 printf (", ");
1564 }
1565 printf ("};\n");
1566 }
1567
1568 static void dump_EMREXTTEXTOUT(const EMREXTTEXTOUTW *eto)
1569 {
1570 trace("rclBounds %d,%d - %d,%d\n", eto->rclBounds.left, eto->rclBounds.top,
1571 eto->rclBounds.right, eto->rclBounds.bottom);
1572 trace("iGraphicsMode %u\n", eto->iGraphicsMode);
1573 trace("exScale: %f\n", eto->exScale);
1574 trace("eyScale: %f\n", eto->eyScale);
1575 trace("emrtext.ptlReference %d,%d\n", eto->emrtext.ptlReference.x, eto->emrtext.ptlReference.y);
1576 trace("emrtext.nChars %u\n", eto->emrtext.nChars);
1577 trace("emrtext.offString %#x\n", eto->emrtext.offString);
1578 trace("emrtext.fOptions %#x\n", eto->emrtext.fOptions);
1579 trace("emrtext.rcl %d,%d - %d,%d\n", eto->emrtext.rcl.left, eto->emrtext.rcl.top,
1580 eto->emrtext.rcl.right, eto->emrtext.rcl.bottom);
1581 trace("emrtext.offDx %#x\n", eto->emrtext.offDx);
1582 }
1583
1584 static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2,
1585 const char *desc, BOOL ignore_scaling)
1586 {
1587 int diff;
1588
1589 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
1590 desc, emr1->iType, emr2->iType);
1591
1592 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1593 desc, emr1->nSize, emr2->nSize);
1594
1595 /* iType and nSize mismatches are fatal */
1596 if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE;
1597
1598 /* contents of EMR_GDICOMMENT are not interesting */
1599 if (emr1->iType == EMR_GDICOMMENT) return TRUE;
1600
1601 /* different Windows versions setup DC scaling differently when
1602 * converting an old style metafile to an EMF.
1603 */
1604 if (ignore_scaling && (emr1->iType == EMR_SETWINDOWEXTEX ||
1605 emr1->iType == EMR_SETVIEWPORTEXTEX))
1606 return TRUE;
1607
1608 if (emr1->iType == EMR_EXTTEXTOUTW || emr1->iType == EMR_EXTTEXTOUTA)
1609 {
1610 EMREXTTEXTOUTW *eto1, *eto2;
1611
1612 eto1 = HeapAlloc(GetProcessHeap(), 0, emr1->nSize);
1613 memcpy(eto1, emr1, emr1->nSize);
1614 eto2 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1615 memcpy(eto2, emr2, emr2->nSize);
1616
1617 /* different Windows versions setup DC scaling differently */
1618 eto1->exScale = eto1->eyScale = 0.0;
1619 eto2->exScale = eto2->eyScale = 0.0;
1620
1621 diff = memcmp(eto1, eto2, emr1->nSize);
1622 if (diff)
1623 {
1624 dump_EMREXTTEXTOUT(eto1);
1625 dump_EMREXTTEXTOUT(eto2);
1626 }
1627 HeapFree(GetProcessHeap(), 0, eto1);
1628 HeapFree(GetProcessHeap(), 0, eto2);
1629 }
1630 else if (emr1->iType == EMR_EXTSELECTCLIPRGN && !lstrcmpA(desc, "emf_clipping"))
1631 {
1632 /* We have to take care of NT4 differences here */
1633 diff = memcmp(emr1, emr2, emr1->nSize);
1634 if (diff)
1635 {
1636 ENHMETARECORD *emr_nt4;
1637
1638 emr_nt4 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1639 memcpy(emr_nt4, emr2, emr2->nSize);
1640 /* Correct the nRgnSize field */
1641 emr_nt4->dParm[5] = sizeof(RECT);
1642
1643 diff = memcmp(emr1, emr_nt4, emr1->nSize);
1644 if (!diff)
1645 win_skip("Catered for NT4 differences\n");
1646
1647 HeapFree(GetProcessHeap(), 0, emr_nt4);
1648 }
1649 }
1650 else if (emr1->iType == EMR_POLYBEZIERTO16 || emr1->iType == EMR_POLYBEZIER16)
1651 {
1652 EMRPOLYBEZIER16 *eto1, *eto2;
1653
1654 eto1 = (EMRPOLYBEZIER16*)emr1;
1655 eto2 = (EMRPOLYBEZIER16*)emr2;
1656
1657 diff = eto1->cpts != eto2->cpts;
1658 if(!diff)
1659 diff = memcmp(eto1->apts, eto2->apts, eto1->cpts * sizeof(POINTS));
1660 }
1661 else if (emr1->iType == EMR_POLYBEZIERTO || emr1->iType == EMR_POLYBEZIER)
1662 {
1663 EMRPOLYBEZIER *eto1, *eto2;
1664
1665 eto1 = (EMRPOLYBEZIER*)emr1;
1666 eto2 = (EMRPOLYBEZIER*)emr2;
1667
1668 diff = eto1->cptl != eto2->cptl;
1669 if(!diff)
1670 diff = memcmp(eto1->aptl, eto2->aptl, eto1->cptl * sizeof(POINTL));
1671 }
1672 else
1673 diff = memcmp(emr1, emr2, emr1->nSize);
1674
1675 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1676
1677 if (diff)
1678 {
1679 dump_emf_record(emr1, "expected bits");
1680 dump_emf_record(emr2, "actual bits");
1681 }
1682
1683 return diff == 0; /* report all non-fatal record mismatches */
1684 }
1685
1686 /* Compare the EMF produced by a test function with the
1687 * expected raw EMF data in "bits".
1688 * Return value is 0 for a perfect match,
1689 * -1 if lengths aren't equal,
1690 * otherwise returns the number of non-matching bytes.
1691 */
1692 static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
1693 UINT bsize, const char *desc,
1694 BOOL ignore_scaling)
1695 {
1696 unsigned char buf[MF_BUFSIZE];
1697 UINT mfsize, offset1, offset2, diff_nt4, diff_9x;
1698 const ENHMETAHEADER *emh1, *emh2;
1699
1700 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1701 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1702
1703 /* ENHMETAHEADER size could differ, depending on platform */
1704 diff_nt4 = sizeof(SIZEL);
1705 diff_9x = sizeof(SIZEL) + 3 * sizeof(DWORD);
1706
1707 if (mfsize < MF_BUFSIZE)
1708 {
1709 ok(mfsize == bsize ||
1710 broken(mfsize == bsize - diff_nt4) || /* NT4 */
1711 broken(mfsize == bsize - diff_9x), /* Win9x/WinME */
1712 "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1713 }
1714 else
1715 ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
1716 desc, mfsize, bsize);
1717
1718 /* basic things must match */
1719 emh1 = (const ENHMETAHEADER *)bits;
1720 emh2 = (const ENHMETAHEADER *)buf;
1721 ok(emh1->iType == EMR_HEADER, "expected EMR_HEADER, got %u\n", emh1->iType);
1722 ok(emh1->nSize == sizeof(ENHMETAHEADER), "expected sizeof(ENHMETAHEADER), got %u\n", emh1->nSize);
1723 ok(emh2->nBytes == mfsize, "expected emh->nBytes %u, got %u\n", mfsize, emh2->nBytes);
1724 ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature);
1725
1726 ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType);
1727 ok(emh1->nSize == emh2->nSize ||
1728 broken(emh1->nSize - diff_nt4 == emh2->nSize) ||
1729 broken(emh1->nSize - diff_9x == emh2->nSize),
1730 "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
1731 ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
1732 ok(emh1->nBytes == emh2->nBytes ||
1733 broken(emh1->nBytes - diff_nt4 == emh2->nBytes) ||
1734 broken(emh1->nBytes - diff_9x == emh2->nBytes),
1735 "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1736 ok(emh1->nRecords == emh2->nRecords, "expected nRecords %u, got %u\n", emh1->nRecords, emh2->nRecords);
1737
1738 if(!winetest_interactive)
1739 {
1740 skip("skipping match_emf_record(), bug ROSTESTS-4\n");
1741 return 0;
1742 }
1743
1744 offset1 = emh1->nSize;
1745 offset2 = emh2->nSize; /* Needed for Win9x/WinME/NT4 */
1746 while (offset1 < emh1->nBytes)
1747 {
1748 const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset1);
1749 const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset2);
1750
1751 trace("%s: EMF record %u, size %u/record %u, size %u\n",
1752 desc, emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
1753
1754 if (!match_emf_record(emr1, emr2, desc, ignore_scaling)) return -1;
1755
1756 /* We have already bailed out if iType or nSize don't match */
1757 offset1 += emr1->nSize;
1758 offset2 += emr2->nSize;
1759 }
1760 return 0;
1761 }
1762
1763
1764 /* tests blitting to an EMF */
1765 static void test_emf_BitBlt(void)
1766 {
1767 HDC hdcDisplay, hdcMetafile, hdcBitmap;
1768 HBITMAP hBitmap, hOldBitmap;
1769 HENHMETAFILE hMetafile;
1770 #define BMP_DIM 4
1771 BITMAPINFOHEADER bmih =
1772 {
1773 sizeof(BITMAPINFOHEADER),
1774 BMP_DIM,/* biWidth */
1775 BMP_DIM,/* biHeight */
1776 1, /* biPlanes */
1777 24, /* biBitCount */
1778 BI_RGB, /* biCompression */
1779 0, /* biXPelsPerMeter */
1780 0, /* biYPelsPerMeter */
1781 0, /* biClrUsed */
1782 0, /* biClrImportant */
1783 };
1784 void *bits;
1785 BOOL ret;
1786
1787 hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL);
1788 ok( hdcDisplay != 0, "CreateDCA error %d\n", GetLastError() );
1789
1790 hdcBitmap = CreateCompatibleDC(hdcDisplay);
1791 ok( hdcBitmap != 0, "CreateCompatibleDC failed\n" );
1792 bmih.biXPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSX), 100, 3937);
1793 bmih.biYPelsPerMeter = MulDiv(GetDeviceCaps(hdcDisplay, LOGPIXELSY), 100, 3937);
1794 hBitmap = CreateDIBSection(hdcDisplay, (const BITMAPINFO *)&bmih,
1795 DIB_RGB_COLORS, &bits, NULL, 0);
1796 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
1797
1798 hdcMetafile = CreateEnhMetaFileA(hdcBitmap, NULL, NULL, NULL);
1799 ok( hdcMetafile != 0, "CreateEnhMetaFileA failed\n" );
1800
1801 /* First fill the bitmap DC with something recognizable, like BLACKNESS */
1802 ret = BitBlt(hdcBitmap, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, BLACKNESS);
1803 ok( ret, "BitBlt(BLACKNESS) failed\n" );
1804
1805 ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, hdcBitmap, 0, 0, SRCCOPY);
1806 ok( ret, "BitBlt(SRCCOPY) failed\n" );
1807 ret = BitBlt(hdcMetafile, 0, 0, BMP_DIM, BMP_DIM, 0, 0, 0, WHITENESS);
1808 ok( ret, "BitBlt(WHITENESS) failed\n" );
1809
1810 hMetafile = CloseEnhMetaFile(hdcMetafile);
1811 ok( hMetafile != 0, "CloseEnhMetaFile failed\n" );
1812
1813 if(compare_emf_bits(hMetafile, EMF_BITBLT, sizeof(EMF_BITBLT),
1814 "emf_BitBlt", FALSE) != 0)
1815 {
1816 dump_emf_bits(hMetafile, "emf_BitBlt");
1817 dump_emf_records(hMetafile, "emf_BitBlt");
1818 }
1819
1820 SelectObject(hdcBitmap, hOldBitmap);
1821 DeleteObject(hBitmap);
1822 DeleteDC(hdcBitmap);
1823 DeleteDC(hdcDisplay);
1824 #undef BMP_DIM
1825 }
1826
1827 static void test_emf_DCBrush(void)
1828 {
1829 HDC hdcMetafile;
1830 HENHMETAFILE hMetafile;
1831 HBRUSH hBrush;
1832 HPEN hPen;
1833 BOOL ret;
1834 COLORREF color;
1835
1836 if (!pSetDCBrushColor || !pSetDCPenColor)
1837 {
1838 win_skip( "SetDCBrush/PenColor not supported\n" );
1839 return;
1840 }
1841
1842 hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
1843 ok( hdcMetafile != 0, "CreateEnhMetaFileA failed\n" );
1844
1845 hBrush = SelectObject(hdcMetafile, GetStockObject(DC_BRUSH));
1846 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
1847
1848 hPen = SelectObject(hdcMetafile, GetStockObject(DC_PEN));
1849 ok(hPen != 0, "SelectObject error %d.\n", GetLastError());
1850
1851 color = pSetDCBrushColor( hdcMetafile, RGB(0x55,0x55,0x55) );
1852 ok( color == 0xffffff, "SetDCBrushColor returned %x\n", color );
1853
1854 color = pSetDCPenColor( hdcMetafile, RGB(0x33,0x44,0x55) );
1855 ok( color == 0, "SetDCPenColor returned %x\n", color );
1856
1857 Rectangle( hdcMetafile, 10, 10, 20, 20 );
1858
1859 color = pSetDCBrushColor( hdcMetafile, RGB(0x12,0x34,0x56) );
1860 ok( color == 0x555555, "SetDCBrushColor returned %x\n", color );
1861
1862 hMetafile = CloseEnhMetaFile(hdcMetafile);
1863 ok( hMetafile != 0, "CloseEnhMetaFile failed\n" );
1864
1865 if (compare_emf_bits (hMetafile, EMF_DCBRUSH_BITS, sizeof(EMF_DCBRUSH_BITS),
1866 "emf_DC_Brush", FALSE ) != 0)
1867 {
1868 dump_emf_bits(hMetafile, "emf_DC_Brush");
1869 dump_emf_records(hMetafile, "emf_DC_Brush");
1870 }
1871 ret = DeleteEnhMetaFile(hMetafile);
1872 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
1873 ret = DeleteObject(hBrush);
1874 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
1875 ret = DeleteObject(hPen);
1876 ok( ret, "DeleteObject(HPEN) error %d\n", GetLastError());
1877 }
1878
1879 /* Test a blank metafile. May be used as a template for new tests. */
1880
1881 static void test_mf_Blank(void)
1882 {
1883 HDC hdcMetafile;
1884 HMETAFILE hMetafile;
1885 INT caps;
1886 BOOL ret;
1887 INT type;
1888
1889 hdcMetafile = CreateMetaFileA(NULL);
1890 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1891 trace("hdcMetafile %p\n", hdcMetafile);
1892
1893 /* Tests on metafile initialization */
1894 caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
1895 ok (caps == DT_METAFILE,
1896 "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
1897
1898 hMetafile = CloseMetaFile(hdcMetafile);
1899 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1900 type = GetObjectType(hMetafile);
1901 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1902 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1903
1904 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1905 "mf_blank") != 0)
1906 {
1907 dump_mf_bits(hMetafile, "mf_Blank");
1908 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1909 }
1910
1911 ret = DeleteMetaFile(hMetafile);
1912 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1913 }
1914
1915 static void test_CopyMetaFile(void)
1916 {
1917 HDC hdcMetafile;
1918 HMETAFILE hMetafile, hmf_copy;
1919 BOOL ret;
1920 char temp_path[MAX_PATH];
1921 char mf_name[MAX_PATH];
1922 INT type;
1923
1924 hdcMetafile = CreateMetaFileA(NULL);
1925 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1926 trace("hdcMetafile %p\n", hdcMetafile);
1927
1928 hMetafile = CloseMetaFile(hdcMetafile);
1929 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1930 type = GetObjectType(hMetafile);
1931 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1932
1933 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1934 "mf_blank") != 0)
1935 {
1936 dump_mf_bits(hMetafile, "mf_Blank");
1937 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1938 }
1939
1940 GetTempPathA(MAX_PATH, temp_path);
1941 GetTempFileNameA(temp_path, "wmf", 0, mf_name);
1942
1943 hmf_copy = CopyMetaFileA(hMetafile, mf_name);
1944 ok(hmf_copy != 0, "CopyMetaFile error %d\n", GetLastError());
1945
1946 type = GetObjectType(hmf_copy);
1947 ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
1948
1949 ret = DeleteMetaFile(hMetafile);
1950 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1951
1952 if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
1953 {
1954 dump_mf_bits(hmf_copy, "mf_Blank");
1955 EnumMetaFile(0, hmf_copy, mf_enum_proc, 0);
1956 }
1957
1958 ret = DeleteMetaFile(hmf_copy);
1959 ok( ret, "DeleteMetaFile(%p) error %d\n", hmf_copy, GetLastError());
1960
1961 DeleteFileA(mf_name);
1962 }
1963
1964 static void test_SetMetaFileBits(void)
1965 {
1966 HMETAFILE hmf;
1967 INT type;
1968 BOOL ret;
1969 BYTE buf[256];
1970 METAHEADER *mh;
1971
1972 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
1973 trace("hmf %p\n", hmf);
1974 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1975 type = GetObjectType(hmf);
1976 ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
1977
1978 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1979 {
1980 dump_mf_bits(hmf, "mf_Graphics");
1981 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1982 }
1983
1984 ret = DeleteMetaFile(hmf);
1985 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1986
1987 /* NULL data crashes XP SP1 */
1988 /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
1989
1990 /* Now with zero size */
1991 SetLastError(0xdeadbeef);
1992 hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
1993 trace("hmf %p\n", hmf);
1994 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1995 ok(GetLastError() == ERROR_INVALID_DATA ||
1996 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
1997 "wrong error %d\n", GetLastError());
1998
1999 /* Now with odd size */
2000 SetLastError(0xdeadbeef);
2001 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
2002 trace("hmf %p\n", hmf);
2003 ok(!hmf, "SetMetaFileBitsEx should fail\n");
2004 ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
2005
2006 /* Now with zeroed out header fields */
2007 assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
2008 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
2009 mh = (METAHEADER *)buf;
2010 /* corruption of any of the below fields leads to a failure */
2011 mh->mtType = 0;
2012 mh->mtVersion = 0;
2013 mh->mtHeaderSize = 0;
2014 SetLastError(0xdeadbeef);
2015 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
2016 trace("hmf %p\n", hmf);
2017 ok(!hmf, "SetMetaFileBitsEx should fail\n");
2018 ok(GetLastError() == ERROR_INVALID_DATA ||
2019 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
2020 "wrong error %d\n", GetLastError());
2021
2022 /* Now with corrupted mtSize field */
2023 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
2024 mh = (METAHEADER *)buf;
2025 /* corruption of mtSize doesn't lead to a failure */
2026 mh->mtSize *= 2;
2027 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
2028 trace("hmf %p\n", hmf);
2029 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
2030
2031 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
2032 {
2033 dump_mf_bits(hmf, "mf_Graphics");
2034 EnumMetaFile(0, hmf, mf_enum_proc, 0);
2035 }
2036
2037 ret = DeleteMetaFile(hmf);
2038 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
2039
2040 #ifndef _WIN64 /* Generates access violation on XP x64 and Win2003 x64 */
2041 /* Now with zeroed out mtSize field */
2042 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
2043 mh = (METAHEADER *)buf;
2044 /* zeroing mtSize doesn't lead to a failure */
2045 mh->mtSize = 0;
2046 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
2047 trace("hmf %p\n", hmf);
2048 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
2049
2050 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
2051 {
2052 dump_mf_bits(hmf, "mf_Graphics");
2053 EnumMetaFile(0, hmf, mf_enum_proc, 0);
2054 }
2055
2056 ret = DeleteMetaFile(hmf);
2057 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
2058 #endif
2059 }
2060
2061 /* Simple APIs from mfdrv/graphics.c
2062 */
2063
2064 static void test_mf_Graphics(void)
2065 {
2066 HDC hdcMetafile;
2067 HMETAFILE hMetafile;
2068 POINT oldpoint;
2069 BOOL ret;
2070
2071 hdcMetafile = CreateMetaFileA(NULL);
2072 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
2073 trace("hdcMetafile %p\n", hdcMetafile);
2074
2075 ret = MoveToEx(hdcMetafile, 1, 1, NULL);
2076 ok( ret, "MoveToEx error %d.\n", GetLastError());
2077 ret = LineTo(hdcMetafile, 2, 2);
2078 ok( ret, "LineTo error %d.\n", GetLastError());
2079 ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
2080 ok( ret, "MoveToEx error %d.\n", GetLastError());
2081
2082 /* oldpoint gets garbage under Win XP, so the following test would
2083 * work under Wine but fails under Windows:
2084 *
2085 * ok((oldpoint.x == 2) && (oldpoint.y == 2),
2086 * "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
2087 * oldpoint.x, oldpoint.y);
2088 */
2089
2090 ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
2091 ok( ret, "Ellipse error %d.\n", GetLastError());
2092
2093 hMetafile = CloseMetaFile(hdcMetafile);
2094 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
2095 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
2096
2097 if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
2098 "mf_Graphics") != 0)
2099 {
2100 dump_mf_bits(hMetafile, "mf_Graphics");
2101 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
2102 }
2103
2104 ret = DeleteMetaFile(hMetafile);
2105 ok( ret, "DeleteMetaFile(%p) error %d\n",
2106 hMetafile, GetLastError());
2107 }
2108
2109 static void test_mf_PatternBrush(void)
2110 {
2111 HDC hdcMetafile;
2112 HMETAFILE hMetafile;
2113 LOGBRUSH *orig_lb;
2114 HBRUSH hBrush;
2115 BOOL ret;
2116
2117 orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
2118
2119 orig_lb->lbStyle = BS_PATTERN;
2120 orig_lb->lbColor = RGB(0, 0, 0);
2121 orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
2122 ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
2123
2124 hBrush = CreateBrushIndirect (orig_lb);
2125 ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
2126
2127 hdcMetafile = CreateMetaFileA(NULL);
2128 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
2129 trace("hdcMetafile %p\n", hdcMetafile);
2130
2131 hBrush = SelectObject(hdcMetafile, hBrush);
2132 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
2133
2134 hMetafile = CloseMetaFile(hdcMetafile);
2135 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
2136 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
2137
2138 if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
2139 "mf_Pattern_Brush") != 0)
2140 {
2141 dump_mf_bits(hMetafile, "mf_Pattern_Brush");
2142 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
2143 }
2144
2145 ret = DeleteMetaFile(hMetafile);
2146 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
2147 ret = DeleteObject(hBrush);
2148 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
2149 ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
2150 ok( ret, "DeleteObject(HBITMAP) error %d\n",
2151 GetLastError());
2152 HeapFree (GetProcessHeap(), 0, orig_lb);
2153 }
2154
2155 static void test_mf_DCBrush(void)
2156 {
2157 HDC hdcMetafile;
2158 HMETAFILE hMetafile;
2159 HBRUSH hBrush;
2160 HPEN hPen;
2161 BOOL ret;
2162 COLORREF color;
2163
2164 if (!pSetDCBrushColor || !pSetDCPenColor)
2165 {
2166 win_skip( "SetDCBrush/PenColor not supported\n" );
2167 return;
2168 }
2169
2170 hdcMetafile = CreateMetaFileA(NULL);
2171 ok( hdcMetafile != 0, "CreateMetaFileA failed\n" );
2172
2173 hBrush = SelectObject(hdcMetafile, GetStockObject(DC_BRUSH));
2174 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
2175
2176 hPen = SelectObject(hdcMetafile, GetStockObject(DC_PEN));
2177 ok(hPen != 0, "SelectObject error %d.\n", GetLastError());
2178
2179 color = pSetDCBrushColor( hdcMetafile, RGB(0x55,0x55,0x55) );
2180 ok( color == CLR_INVALID, "SetDCBrushColor returned %x\n", color );
2181
2182 color = pSetDCPenColor( hdcMetafile, RGB(0x33,0x44,0x55) );
2183 ok( color == CLR_INVALID, "SetDCPenColor returned %x\n", color );
2184
2185 Rectangle( hdcMetafile, 10, 10, 20, 20 );
2186
2187 color = pSetDCBrushColor( hdcMetafile, RGB(0x12,0x34,0x56) );
2188 ok( color == CLR_INVALID, "SetDCBrushColor returned %x\n", color );
2189
2190 hMetafile = CloseMetaFile(hdcMetafile);
2191 ok( hMetafile != 0, "CloseMetaFile failed\n" );
2192
2193 if (compare_mf_bits(hMetafile, MF_DCBRUSH_BITS, sizeof(MF_DCBRUSH_BITS), "mf_DCBrush") != 0)
2194 {
2195 dump_mf_bits(hMetafile, "mf_DCBrush");
2196 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
2197 }
2198 ret = DeleteMetaFile(hMetafile);
2199 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
2200 }
2201
2202 static void test_mf_ExtTextOut_on_path(void)
2203 {
2204 HDC hdcMetafile;
2205 HMETAFILE hMetafile;
2206 BOOL ret;
2207 static const INT dx[4] = { 3, 5, 8, 12 };
2208
2209 hdcMetafile = CreateMetaFileA(NULL);
2210 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
2211 trace("hdcMetafile %p\n", hdcMetafile);
2212
2213 ret = BeginPath(hdcMetafile);
2214 ok(!ret, "BeginPath on metafile DC should fail\n");
2215
2216 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
2217 ok(ret, "ExtTextOut error %d\n", GetLastError());
2218
2219 ret = EndPath(hdcMetafile);
2220 ok(!ret, "EndPath on metafile DC should fail\n");
2221
2222 hMetafile = CloseMetaFile(hdcMetafile);
2223 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
2224
2225 if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
2226 "mf_TextOut_on_path") != 0)
2227 {
2228 dump_mf_bits(hMetafile, "mf_TextOut_on_path");
2229 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
2230 }
2231
2232 ret = DeleteMetaFile(hMetafile);
2233 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
2234 }
2235
2236 static void test_emf_ExtTextOut_on_path(void)
2237 {
2238 HWND hwnd;
2239 HDC hdcDisplay, hdcMetafile;
2240 HENHMETAFILE hMetafile;
2241 BOOL ret;
2242 static const INT dx[4] = { 3, 5, 8, 12 };
2243
2244 /* Win9x doesn't play EMFs on invisible windows */
2245 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
2246 0, 0, 200, 200, 0, 0, 0, NULL);
2247 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
2248
2249 hdcDisplay = GetDC(hwnd);
2250 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
2251
2252 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
2253 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
2254
2255 ret = BeginPath(hdcMetafile);
2256 ok(ret, "BeginPath error %d\n", GetLastError());
2257
2258 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
2259 ok(ret, "ExtTextOut error %d\n", GetLastError());
2260
2261 ret = EndPath(hdcMetafile);
2262 ok(ret, "EndPath error %d\n", GetLastError());
2263
2264 hMetafile = CloseEnhMetaFile(hdcMetafile);
2265 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
2266
2267 /* this doesn't succeed yet: EMF has correct size, all EMF records
2268 * are there, but their contents don't match for different reasons.
2269 */
2270 if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
2271 "emf_TextOut_on_path", FALSE) != 0)
2272 {
2273 dump_emf_bits(hMetafile, "emf_TextOut_on_path");
2274 dump_emf_records(hMetafile, "emf_TextOut_on_path");
2275 }
2276
2277 ret = DeleteEnhMetaFile(hMetafile);
2278 ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
2279 ret = ReleaseDC(hwnd, hdcDisplay);
2280 ok(ret, "ReleaseDC error %d\n", GetLastError());
2281 DestroyWindow(hwnd);
2282 }
2283
2284 static const unsigned char EMF_CLIPPING[] =
2285 {
2286 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
2287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2288 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2290 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
2291 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
2292 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
2293 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2295 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
2296 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
2297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2298 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
2299 0xe0, 0x93, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
2300 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2301 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
2302 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
2303 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
2304 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2305 0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
2306 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
2307 0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
2308 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
2309 0x00, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
2310 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2311 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
2312 };
2313
2314 static void translate( POINT *pt, UINT count, const XFORM *xform )
2315 {
2316 while (count--)
2317 {
2318 FLOAT x = (FLOAT)pt->x;
2319 FLOAT y = (FLOAT)pt->y;
2320 pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
2321 pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
2322 pt++;
2323 }
2324 }
2325
2326 /* Compare rectangles allowing rounding errors */
2327 static BOOL is_equal_rect(const RECT *rc1, const RECT *rc2)
2328 {
2329 return abs(rc1->left - rc2->left) <= 1 &&
2330 abs(rc1->top - rc2->top) <= 1 &&
2331 abs(rc1->right - rc2->right) <= 1 &&
2332 abs(rc1->bottom - rc2->bottom) <= 1;
2333 }
2334
2335 static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
2336 const ENHMETARECORD *emr, int n_objs, LPARAM param)
2337 {
2338 if (emr->iType == EMR_EXTSELECTCLIPRGN)
2339 {
2340 const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
2341 union _rgn
2342 {
2343 RGNDATA data;
2344 char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
2345 };
2346 const union _rgn *rgn1;
2347 union _rgn rgn2;
2348 RECT rect, rc_transformed;
2349 const RECT *rc = (const RECT *)param;
2350 HRGN hrgn;
2351 XFORM xform;
2352 INT ret;
2353 BOOL is_win9x;
2354
2355 trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
2356 clip->cbRgnData, clip->iMode);
2357
2358 ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
2359 ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
2360 "too small data block: %u bytes\n", clip->cbRgnData);
2361 if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
2362 return 0;
2363
2364 rgn1 = (const union _rgn *)clip->RgnData;
2365
2366 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
2367 rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
2368 rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
2369 rgn1->data.rdh.rcBound.left, rgn1->data.rdh.rcBound.top,
2370 rgn1->data.rdh.rcBound.right, rgn1->data.rdh.rcBound.bottom);
2371
2372 ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
2373
2374 rect = *(const RECT *)rgn1->data.Buffer;
2375 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
2376 ok(EqualRect(&rect, rc), "rects don't match\n");
2377
2378 ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize);
2379 ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
2380 ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
2381 ok(rgn1->data.rdh.nRgnSize == sizeof(RECT) ||
2382 broken(rgn1->data.rdh.nRgnSize == 168), /* NT4 */
2383 "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
2384
2385 hrgn = CreateRectRgn(0, 0, 0, 0);
2386
2387 memset(&xform, 0, sizeof(xform));
2388 SetLastError(0xdeadbeef);
2389 ret = GetWorldTransform(hdc, &xform);
2390 is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
2391 if (!is_win9x)
2392 ok(ret, "GetWorldTransform error %u\n", GetLastError());
2393
2394 trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
2395
2396 ret = GetClipRgn(hdc, hrgn);
2397 ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
2398
2399 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
2400
2401 ret = GetClipRgn(hdc, hrgn);
2402 ok(ret == 1, "GetClipRgn returned %d, expected 1\n", ret);
2403
2404 /* Win9x returns empty clipping region */
2405 if (is_win9x) return 1;
2406
2407 ret = GetRegionData(hrgn, 0, NULL);
2408 ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
2409
2410 ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
2411 ok(ret == sizeof(rgn2), "expected sizeof(rgn2), got %u\n", ret);
2412
2413 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
2414 rgn2.data.rdh.dwSize, rgn2.data.rdh.iType,
2415 rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
2416 rgn2.data.rdh.rcBound.left, rgn2.data.rdh.rcBound.top,
2417 rgn2.data.rdh.rcBound.right, rgn2.data.rdh.rcBound.bottom);
2418
2419 rect = rgn2.data.rdh.rcBound;
2420 rc_transformed = *rc;
2421 translate((POINT *)&rc_transformed, 2, &xform);
2422 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
2423 rc_transformed.right, rc_transformed.bottom);
2424 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
2425
2426 rect = *(const RECT *)rgn2.data.Buffer;
2427 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
2428 rc_transformed = *rc;
2429 translate((POINT *)&rc_transformed, 2, &xform);
2430 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
2431 rc_transformed.right, rc_transformed.bottom);
2432 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
2433
2434 ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize);
2435 ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
2436 ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
2437 ok(rgn2.data.rdh.nRgnSize == sizeof(RECT) ||
2438 broken(rgn2.data.rdh.nRgnSize == 168), /* NT4 */
2439 "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
2440
2441 DeleteObject(hrgn);
2442 }
2443 return 1;
2444 }
2445
2446 static void test_emf_clipping(void)
2447 {
2448 static const RECT rc = { 0, 0, 100, 100 };
2449 RECT rc_clip = { 100, 100, 1024, 1024 };
2450 HWND hwnd;
2451 HDC hdc;
2452 HENHMETAFILE hemf;
2453 HRGN hrgn;
2454 INT ret;
2455 RECT rc_res, rc_sclip;
2456
2457 SetLastError(0xdeadbeef);
2458 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
2459 ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
2460
2461 /* Need to write something to the emf, otherwise Windows won't play it back */
2462 LineTo(hdc, 1, 1);
2463
2464 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
2465 ret = SelectClipRgn(hdc, hrgn);
2466 ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
2467
2468 SetLastError(0xdeadbeef);
2469 hemf = CloseEnhMetaFile(hdc);
2470 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
2471
2472 if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
2473 "emf_clipping", FALSE) != 0)
2474 {
2475 dump_emf_bits(hemf, "emf_clipping");
2476 dump_emf_records(hemf, "emf_clipping");
2477 }
2478
2479 DeleteObject(hrgn);
2480
2481 /* Win9x doesn't play EMFs on invisible windows */
2482 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
2483 0, 0, 200, 200, 0, 0, 0, NULL);
2484 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
2485
2486 hdc = GetDC(hwnd);
2487
2488 ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
2489 ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
2490
2491 DeleteEnhMetaFile(hemf);
2492 ReleaseDC(hwnd, hdc);
2493 DestroyWindow(hwnd);
2494
2495 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
2496
2497 SetRect(&rc_sclip, 100, 100, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2498 hrgn = CreateRectRgn(rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom);
2499 SelectClipRgn(hdc, hrgn);
2500 SetRect(&rc_res, -1, -1, -1, -1);
2501 ret = GetClipBox(hdc, &rc_res);
2502 ok(ret == SIMPLEREGION, "got %d\n", ret);
2503 ok(EqualRect(&rc_res, &rc_sclip),
2504 "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n",
2505 rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom,
2506 rc_res.left, rc_res.top, rc_res.right, rc_res.bottom);
2507
2508 OffsetRect(&rc_sclip, -100, -100);
2509 ret = OffsetClipRgn(hdc, -100, -100);
2510 ok(ret == SIMPLEREGION, "got %d\n", ret);
2511 SetRect(&rc_res, -1, -1, -1, -1);
2512 ret = GetClipBox(hdc, &rc_res);
2513 ok(ret == SIMPLEREGION, "got %d\n", ret);
2514 ok(EqualRect(&rc_res, &rc_sclip),
2515 "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n",
2516 rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom,
2517 rc_res.left, rc_res.top, rc_res.right, rc_res.bottom);
2518
2519 ret = IntersectClipRect(hdc, 0, 0, 100, 100);
2520 ok(ret == SIMPLEREGION || broken(ret == COMPLEXREGION) /* XP */, "got %d\n", ret);
2521 if (ret == COMPLEXREGION)
2522 {
2523 /* XP returns COMPLEXREGION although region contains only 1 rect */
2524 ret = GetClipRgn(hdc, hrgn);
2525 ok(ret == 1, "expected 1, got %d\n", ret);
2526 ret = rgn_rect_count(hrgn);
2527 ok(ret == 1, "expected 1, got %d\n", ret);
2528 }
2529 SetRect(&rc_res, -1, -1, -1, -1);
2530 ret = GetClipBox(hdc, &rc_res);
2531 ok(ret == SIMPLEREGION, "got %d\n", ret);
2532 ok(EqualRect(&rc_res, &rc),
2533 "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n",
2534 rc.left, rc.top, rc.right, rc.bottom,
2535 rc_res.left, rc_res.top, rc_res.right, rc_res.bottom);
2536
2537 SetRect(&rc_sclip, 0, 0, 100, 50);
2538 ret = ExcludeClipRect(hdc, 0, 50, 100, 100);
2539 ok(ret == SIMPLEREGION || broken(ret == COMPLEXREGION) /* XP */, "got %d\n", ret);
2540 if (ret == COMPLEXREGION)
2541 {
2542 /* XP returns COMPLEXREGION although region contains only 1 rect */
2543 ret = GetClipRgn(hdc, hrgn);
2544 ok(ret == 1, "expected 1, got %d\n", ret);
2545 ret = rgn_rect_count(hrgn);
2546 ok(ret == 1, "expected 1, got %d\n", ret);
2547 }
2548 SetRect(&rc_res, -1, -1, -1, -1);
2549 ret = GetClipBox(hdc, &rc_res);
2550 ok(ret == SIMPLEREGION, "got %d\n", ret);
2551 ok(EqualRect(&rc_res, &rc_sclip),
2552 "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n",
2553 rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom,
2554 rc_res.left, rc_res.top, rc_res.right, rc_res.bottom);
2555
2556 hemf = CloseEnhMetaFile(hdc);
2557 DeleteEnhMetaFile(hemf);
2558 DeleteObject(hrgn);
2559 }
2560
2561 static const unsigned char MF_CLIP_BITS[] = {
2562 /* METAHEADER */
2563 0x01, 0x00, /* mtType */
2564 0x09, 0x00, /* mtHeaderSize */
2565 0x00, 0x03, /* mtVersion */
2566 0x32, 0x00, 0x00, 0x00, /* mtSize */
2567 0x01, 0x00, /* mtNoObjects */
2568 0x14, 0x00, 0x00, 0x00, /* mtMaxRecord (size in words of longest record) */
2569 0x00, 0x00, /* reserved */
2570
2571 /* METARECORD for CreateRectRgn(0x11, 0x22, 0x33, 0x44) */
2572 0x14, 0x00, 0x00, 0x00, /* rdSize in words */
2573 0xff, 0x06, /* META_CREATEREGION */
2574 0x00, 0x00, 0x06, 0x00, 0xf6, 0x02, 0x00, 0x00,
2575 0x24, 0x00, 0x01, 0x00, 0x02, 0x00, 0x11, 0x00,
2576 0x22, 0x00, 0x33, 0x00, 0x44, 0x00, 0x02, 0x00,
2577 0x22, 0x00, 0x44, 0x00, 0x11, 0x00, 0x33, 0x00,
2578 0x02, 0x00,
2579
2580 /* METARECORD for SelectObject */
2581 0x04, 0x00, 0x00, 0x00,
2582 0x2d, 0x01, /* META_SELECTOBJECT (not META_SELECTCLIPREGION?!) */
2583 0x00, 0x00,
2584
2585 /* METARECORD */
2586 0x04, 0x00, 0x00, 0x00,
2587 0xf0, 0x01, /* META_DELETEOBJECT */
2588 0x00, 0x00,
2589
2590 /* METARECORD for MoveTo(1,0x30) */
2591 0x05, 0x00, 0x00, 0x00, /* rdSize in words */
2592 0x14, 0x02, /* META_MOVETO */
2593 0x30, 0x00, /* y */
2594 0x01, 0x00, /* x */
2595
2596 /* METARECORD for LineTo(0x20, 0x30) */
2597 0x05, 0x00, 0x00, 0x00, /* rdSize in words */
2598 0x13, 0x02, /* META_LINETO */
2599 0x30, 0x00, /* y */
2600 0x20, 0x00, /* x */
2601
2602 /* EOF */
2603 0x03, 0x00, 0x00, 0x00,
2604 0x00, 0x00
2605 };
2606
2607 static int clip_mf_enum_proc_seen_selectclipregion;
2608 static int clip_mf_enum_proc_seen_selectobject;
2609
2610 static int CALLBACK clip_mf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
2611 METARECORD *mr, int n_objs, LPARAM param)
2612 {
2613 switch (mr->rdFunction) {
2614 case META_SELECTCLIPREGION:
2615 clip_mf_enum_proc_seen_selectclipregion++;
2616 break;
2617 case META_SELECTOBJECT:
2618 clip_mf_enum_proc_seen_selectobject++;
2619 break;
2620 }
2621 return 1;
2622 }
2623
2624 static void test_mf_clipping(void)
2625 {
2626 /* left top right bottom */
2627 static RECT rc_clip = { 0x11, 0x22, 0x33, 0x44 };
2628 HWND hwnd;
2629 HDC hdc;
2630 HMETAFILE hmf;
2631 HRGN hrgn;
2632 INT ret;
2633
2634 SetLastError(0xdeadbeef);
2635 hdc = CreateMetaFileA(NULL);
2636 ok(hdc != 0, "CreateMetaFileA error %d\n", GetLastError());
2637
2638 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
2639 ret = SelectClipRgn(hdc, hrgn);
2640 /* Seems like it should be SIMPLEREGION, but windows returns NULLREGION? */
2641 ok(ret == NULLREGION, "expected NULLREGION, got %d\n", ret);
2642
2643 /* Draw a line that starts off left of the clip region and ends inside it */
2644 MoveToEx(hdc, 0x1, 0x30, NULL);
2645 LineTo(hdc, 0x20, 0x30);
2646
2647 SetLastError(0xdeadbeef);
2648 hmf = CloseMetaFile(hdc);
2649 ok(hmf != 0, "CloseMetaFile error %d\n", GetLastError());
2650
2651 if (compare_mf_bits(hmf, MF_CLIP_BITS, sizeof(MF_CLIP_BITS),
2652 "mf_clipping") != 0)
2653 {
2654 dump_mf_bits(hmf, "mf_clipping");
2655 }
2656
2657 DeleteObject(hrgn);
2658
2659 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
2660 0, 0, 200, 200, 0, 0, 0, NULL);
2661 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
2662
2663 hdc = GetDC(hwnd);
2664
2665 ret = EnumMetaFile(hdc, hmf, clip_mf_enum_proc, (LPARAM)&rc_clip);
2666 ok(ret, "EnumMetaFile error %d\n", GetLastError());
2667
2668 /* Oddly, windows doesn't seem to use META_SELECTCLIPREGION */
2669 ok(clip_mf_enum_proc_seen_selectclipregion == 0,
2670 "expected 0 selectclipregion, saw %d\n", clip_mf_enum_proc_seen_selectclipregion);
2671 ok(clip_mf_enum_proc_seen_selectobject == 1,
2672 "expected 1 selectobject, saw %d\n", clip_mf_enum_proc_seen_selectobject);
2673
2674 DeleteMetaFile(hmf);
2675 ReleaseDC(hwnd, hdc);
2676 DestroyWindow(hwnd);
2677 }
2678
2679 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
2680 {
2681 LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
2682 POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
2683 /* When using MM_TEXT Win9x does not update the mapping mode
2684 * until a record is played which actually outputs something */
2685 PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
2686 LPtoDP(hdc, mapping, 2);
2687 trace("EMF record: iType %d, nSize %d, (%d,%d)-(%d,%d)\n",
2688 lpEMFR->iType, lpEMFR->nSize,
2689 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
2690
2691 if (lpEMFR->iType == EMR_LINETO)
2692 {
2693 INT x0, y0, x1, y1;
2694 if (!lpMFP || lpMFP->mm == MM_TEXT)
2695 {
2696 x0 = 0;
2697 y0 = 0;
2698 x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
2699 y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
2700 }
2701 else
2702 {
2703 ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
2704
2705 x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
2706 y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
2707 x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
2708 y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
2709 }
2710 ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
2711 "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
2712 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
2713 x0, y0, x1, y1);
2714 }
2715 return TRUE;
2716 }
2717
2718 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
2719 {
2720 HDC hdcMf;
2721 HMETAFILE hmf;
2722 HENHMETAFILE hemf;
2723 BOOL ret;
2724 UINT size;
2725 LPBYTE pBits;
2726
2727 hdcMf = CreateMetaFileA(NULL);
2728 ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
2729 ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
2730 ok(ret, "LineTo failed with error %d\n", GetLastError());
2731 hmf = CloseMetaFile(hdcMf);
2732 ok(hmf != NULL, "CloseMetaFile failed with error %d\n", GetLastError());
2733
2734 if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
2735 {
2736 dump_mf_bits(hmf, "mf_LineTo");
2737 EnumMetaFile(0, hmf, mf_enum_proc, 0);
2738 }
2739
2740 size = GetMetaFileBitsEx(hmf, 0, NULL);
2741 ok(size, "GetMetaFileBitsEx failed with error %d\n", GetLastError());
2742 pBits = HeapAlloc(GetProcessHeap(), 0, size);
2743 GetMetaFileBitsEx(hmf, size, pBits);
2744 DeleteMetaFile(hmf);
2745 hemf = SetWinMetaFileBits(size, pBits, NULL, mfp);
2746 HeapFree(GetProcessHeap(), 0, pBits);
2747 return hemf;
2748 }
2749
2750 static void test_mf_conversions(void)
2751 {
2752 trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
2753 {
2754 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2755 HENHMETAFILE hemf;
2756 METAFILEPICT mfp;
2757 RECT rect = { 0, 0, 100, 100 };
2758 mfp.mm = MM_ANISOTROPIC;
2759 mfp.xExt = 100;
2760 mfp.yExt = 100;
2761 mfp.hMF = NULL;
2762 hemf = create_converted_emf(&mfp);
2763
2764 if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
2765 "emf_LineTo MM_ANISOTROPIC", TRUE) != 0)
2766 {
2767 dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
2768 dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
2769 }
2770
2771 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
2772
2773 DeleteEnhMetaFile(hemf);
2774 DeleteDC(hdcOffscreen);
2775 }
2776
2777 trace("Testing MF->EMF conversion (MM_TEXT)\n");
2778 {
2779 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2780 HENHMETAFILE hemf;
2781 METAFILEPICT mfp;
2782 RECT rect = { 0, 0, 100, 100 };
2783 mfp.mm = MM_TEXT;
2784 mfp.xExt = 0;
2785 mfp.yExt = 0;
2786 mfp.hMF = NULL;
2787 hemf = create_converted_emf(&mfp);
2788
2789 if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
2790 "emf_LineTo MM_TEXT", TRUE) != 0)
2791 {
2792 dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
2793 dump_emf_records(hemf, "emf_LineTo MM_TEXT");
2794 }
2795
2796 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
2797
2798 DeleteEnhMetaFile(hemf);
2799 DeleteDC(hdcOffscreen);
2800 }
2801
2802 trace("Testing MF->EMF conversion (NULL mfp)\n");
2803 {
2804 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2805 HENHMETAFILE hemf;
2806 RECT rect = { 0, 0, 100, 100 };
2807 hemf = create_converted_emf(NULL);
2808
2809 if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
2810 "emf_LineTo NULL", TRUE) != 0)
2811 {
2812 dump_emf_bits(hemf, "emf_LineTo NULL");
2813 dump_emf_records(hemf, "emf_LineTo NULL");
2814 }
2815
2816 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
2817
2818 DeleteEnhMetaFile(hemf);
2819 DeleteDC(hdcOffscreen);
2820 }
2821 }
2822
2823 static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
2824 LONG mm, LONG xExt, LONG yExt,
2825 RECTL * rclBounds, RECTL * rclFrame)
2826 {
2827 METAFILEPICT mfp;
2828 METAFILEPICT * mfpPtr = NULL;
2829 HENHMETAFILE emf;
2830 ENHMETAHEADER header;
2831 UINT res;
2832
2833 if (!mfpIsNull)
2834 {
2835 mfp.mm = mm;
2836 mfp.xExt = xExt;
2837 mfp.yExt = yExt;
2838 mfpPtr = &mfp;
2839 }
2840
2841 emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
2842 ok(emf != NULL, "SetWinMetaFileBits failed\n");
2843 if (!emf) return FALSE;
2844 res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
2845 ok(res != 0, "GetEnhMetaHeader failed\n");
2846 DeleteEnhMetaFile(emf);
2847 if (!res) return FALSE;
2848
2849 *rclBounds = header.rclBounds;
2850 *rclFrame = header.rclFrame;
2851 return TRUE;
2852 }
2853
2854 static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
2855 LONG mm, LONG xExt, LONG yExt,
2856 RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
2857 {
2858 RECTL rclBounds, rclFrame;
2859
2860 if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
2861 {
2862 const char * msg;
2863 char buf[64];
2864
2865 if (mfpIsNull)
2866 {
2867 msg = "mfp == NULL";
2868 }
2869 else
2870 {
2871 const char * mm_str;
2872 switch (mm)
2873 {
2874 case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
2875 case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
2876 default: mm_str = "Unexpected";
2877 }
2878 sprintf(buf, "mm=%s, xExt=%d, yExt=%d", mm_str, xExt, yExt);
2879 msg = buf;
2880 }
2881
2882 ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
2883 ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
2884 ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
2885 ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
2886 ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
2887 ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
2888 ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
2889 ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
2890 }
2891 }
2892
2893 static void test_SetWinMetaFileBits(void)
2894 {
2895 HMETAFILE wmf;
2896 HDC wmfDC;
2897 BYTE * buffer;
2898 UINT buffer_size;
2899 RECT rect;
2900 UINT res;
2901 RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
2902 RECTL rclBoundsIsotropic, rclFrameIsotropic;
2903 RECTL rclBounds, rclFrame;
2904 HDC dc;
2905 LONG diffx, diffy;
2906
2907 wmfDC = CreateMetaFileA(NULL);
2908 ok(wmfDC != NULL, "CreateMetaFile failed\n");
2909 if (!wmfDC) return;
2910
2911 SetWindowExtEx(wmfDC, 100, 100, NULL);
2912 rect.left = rect.top = 0;
2913 rect.right = rect.bottom = 50;
2914 FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
2915 wmf = CloseMetaFile(wmfDC);
2916 ok(wmf != NULL, "Metafile creation failed\n");
2917 if (!wmf) return;
2918
2919 buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
2920 ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
2921 if (buffer_size == 0)
2922 {
2923 DeleteMetaFile(wmf);
2924 return;
2925 }
2926
2927 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
2928 ok(buffer != NULL, "HeapAlloc failed\n");
2929 if (!buffer)
2930 {
2931 DeleteMetaFile(wmf);
2932 return;
2933 }
2934
2935 res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
2936 ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
2937 DeleteMetaFile(wmf);
2938 if (res != buffer_size)
2939 {
2940 HeapFree(GetProcessHeap(), 0, buffer);
2941 return;
2942 }
2943
2944 /* Get the reference bounds and frame */
2945 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2946 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2947
2948 ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
2949 rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
2950 "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
2951
2952 ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
2953 ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
2954 diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
2955 if (diffx < 0) diffx = -diffx;
2956 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
2957
2958 dc = CreateCompatibleDC(NULL);
2959
2960 /* Allow 1 mm difference (rounding errors) */
2961 diffx = rclBoundsAnisotropic.right - GetDeviceCaps(dc, HORZRES) / 2;
2962 diffy = rclBoundsAnisotropic.bottom - GetDeviceCaps(dc, VERTRES) / 2;
2963 if (diffx < 0) diffx = -diffx;
2964 if (diffy < 0) diffy = -diffy;
2965 todo_wine
2966 {
2967 ok(diffx <= 1 && diffy <= 1,
2968 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2969 GetDeviceCaps(dc, HORZRES) / 2, GetDeviceCaps(dc, VERTRES) / 2, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
2970 }
2971
2972 /* Allow 1 mm difference (rounding errors) */
2973 diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
2974 diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
2975 if (diffx < 0) diffx = -diffx;
2976 if (diffy < 0) diffy = -diffy;
2977 todo_wine
2978 {
2979 ok(diffx <= 1 && diffy <= 1,
2980 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2981 GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
2982 }
2983 DeleteDC(dc);
2984
2985 /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
2986 checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2987
2988 /* If xExt or yExt is zero or negative, the whole device surface is used */
2989 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2990 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2991 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2992 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2993 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2994 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2995 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2996 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2997 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2998 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2999 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
3000 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
3001
3002 /* MSDN says that negative xExt and yExt values specify a ratio.
3003 Check that this is wrong and the whole device surface is used */
3004 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
3005 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
3006
3007 /* Ordinary conversions */
3008
3009 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
3010 {
3011 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
3012 "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
3013 ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
3014 "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
3015 }
3016
3017 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
3018 {
3019 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
3020 "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
3021 ok(rclBounds.left == 0 && rclBounds.top == 0,
3022 "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
3023
3024 /* Wine has a rounding error */
3025 diffx = rclBounds.right - rclBounds.bottom;
3026 if (diffx < 0) diffx = -diffx;
3027 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
3028 }
3029
3030 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
3031 {
3032 ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
3033 "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
3034 }
3035
3036 HeapFree(GetProcessHeap(), 0, buffer);
3037 }
3038
3039 static BOOL near_match(int x, int y)
3040 {
3041 int epsilon = min(abs(x), abs(y));
3042
3043 epsilon = max(epsilon/100, 2);
3044
3045 if(x < y - epsilon || x > y + epsilon) return FALSE;
3046 return TRUE;
3047 }
3048
3049 static void getwinmetafilebits(UINT mode, int scale, RECT *rc)
3050 {
3051 HENHMETAFILE emf;
3052 HDC display_dc, emf_dc;
3053 ENHMETAHEADER *enh_header;
3054 UINT size, emf_size, i;
3055 WORD check = 0;
3056 DWORD rec_num = 0;
3057 METAHEADER *mh = NULL;
3058 METARECORD *rec;
3059 INT horz_res, vert_res, horz_size, vert_size;
3060 INT curve_caps, line_caps, poly_caps;
3061
3062 display_dc = GetDC(NULL);
3063 ok(display_dc != NULL, "display_dc is NULL\n");
3064
3065 horz_res = GetDeviceCaps(display_dc, HORZRES);
3066 vert_res = GetDeviceCaps(display_dc, VERTRES);
3067 horz_size = GetDeviceCaps(display_dc, HORZSIZE);
3068 vert_size = GetDeviceCaps(display_dc, VERTSIZE);
3069
3070 emf_dc = CreateEnhMetaFileA(display_dc, NULL, rc, NULL);
3071 ok(emf_dc != NULL, "emf_dc is NULL\n");
3072
3073 curve_caps = GetDeviceCaps(emf_dc, CURVECAPS);
3074 ok(curve_caps == 511, "expect 511 got %d\n", curve_caps);
3075
3076 line_caps = GetDeviceCaps(emf_dc, LINECAPS);
3077 ok(line_caps == 254, "expect 254 got %d\n", line_caps);
3078
3079 poly_caps = GetDeviceCaps(emf_dc, POLYGONALCAPS);
3080 ok(poly_caps == 255, "expect 511 got %d\n", poly_caps);
3081
3082 for(i = 0; i < 3000; i++) /* This is enough to take emf_size > 0xffff */
3083 Rectangle(emf_dc, 0, 0, 1000, 20);
3084 emf = CloseEnhMetaFile(emf_dc);
3085 ok(emf != NULL, "emf is NULL\n");
3086
3087 emf_size = GetEnhMetaFileBits(emf, 0, NULL);
3088 enh_header = HeapAlloc(GetProcessHeap(), 0, emf_size);
3089 emf_size = GetEnhMetaFileBits(emf, emf_size, (BYTE*)enh_header);
3090 DeleteEnhMetaFile(emf);
3091 /* multiply szlDevice.cx by scale, when scale != 1 the recording and playback dcs
3092 have different resolutions */
3093 enh_header->szlDevice.cx *= scale;
3094 emf = SetEnhMetaFileBits(emf_size, (BYTE*)enh_header);
3095 ok(emf != NULL, "emf is NULL\n");
3096 ok(EqualRect((RECT*)&enh_header->rclFrame, rc), "Frame rectangles differ\n");
3097
3098 size = GetWinMetaFileBits(emf, 0, NULL, mode, display_dc);
3099 ok(size ||
3100 broken(size == 0), /* some versions of winxp fail for some reason */
3101 "GetWinMetaFileBits returns 0\n");
3102 if(!size) goto end;
3103 mh = HeapAlloc(GetProcessHeap(), 0, size);
3104 GetWinMetaFileBits(emf, size, (BYTE*)mh, mode, display_dc);
3105
3106 for(i = 0; i < size / 2; i++) check += ((WORD*)mh)[i];
3107 ok(check == 0, "check %04x\n", check);
3108
3109 rec = (METARECORD*)(mh + 1);
3110
3111 while(rec->rdSize && rec->rdFunction)
3112 {
3113 const DWORD chunk_size = 0x2000;
3114 DWORD mfcomment_chunks = (emf_size + chunk_size - 1) / chunk_size;
3115
3116 if(rec_num < mfcomment_chunks)
3117 {
3118 DWORD this_chunk_size = chunk_size;
3119
3120 if(rec_num == mfcomment_chunks - 1)
3121 this_chunk_size = emf_size - rec_num * chunk_size;
3122
3123 ok(rec->rdSize == (this_chunk_size + 44) / 2, "%04x: got %04x expected %04x\n", rec_num, rec->rdSize, (this_chunk_size + 44) / 2);
3124 ok(rec->rdFunction == META_ESCAPE, "%04x: got %04x\n", rec_num, rec->rdFunction);
3125 if(rec->rdSize < (this_chunk_size + 44) / 2) break;
3126 ok(rec->rdParm[0] == MFCOMMENT, "got %04x\n", rec->rdParm[0]);
3127 ok(rec->rdParm[1] == this_chunk_size + 34, "got %04x %x\n", rec->rdParm[1], emf_size + 34);
3128 ok(rec->rdParm[2] == 0x4d57, "got %04x\n", rec->rdParm[2]); /* WMFC */
3129 ok(rec->rdParm[3] == 0x4346, "got %04x\n", rec->rdParm[3]); /* " */
3130 ok(rec->rdParm[4] == 1, "got %04x\n", rec->rdParm[4]);
3131 ok(rec->rdParm[5] == 0, "got %04x\n", rec->rdParm[5]);
3132 ok(rec->rdParm[6] == 0, "got %04x\n", rec->rdParm[6]);
3133 ok(rec->rdParm[7] == 1, "got %04x\n", rec->rdParm[7]);
3134 /* parm[8] is the checksum, tested above */
3135 if(rec_num > 0) ok(rec->rdParm[8] == 0, "got %04x\n", rec->rdParm[8]);
3136 ok(rec->rdParm[9] == 0, "got %04x\n", rec->rdParm[9]);
3137 ok(rec->rdParm[10] == 0, "got %04x\n", rec->rdParm[10]);
3138 ok(rec->rdParm[11] == mfcomment_chunks, "got %04x\n", rec->rdParm[11]); /* num chunks */
3139 ok(rec->rdParm[12] == 0, "got %04x\n", rec->rdParm[12]);
3140 ok(rec->rdParm[13] == this_chunk_size, "got %04x expected %04x\n", rec->rdParm[13], this_chunk_size);
3141 ok(rec->rdParm[14] == 0, "got %04x\n", rec->rdParm[14]);
3142 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 */
3143 ok(*(DWORD*)(rec->rdParm + 17) == emf_size, "got %08x emf_size %08x\n", *(DWORD*)(rec->rdParm + 17), emf_size);
3144 ok(!memcmp(rec->rdParm + 19, (char*)enh_header + rec_num * chunk_size, this_chunk_size), "bits mismatch\n");
3145 }
3146
3147 else if(rec_num == mfcomment_chunks)
3148 {
3149 ok(rec->rdFunction == META_SETMAPMODE, "got %04x\n", rec->rdFunction);
3150 ok(rec->rdParm[0] == mode, "got %04x\n", rec->rdParm[0]);
3151 }
3152 else if(rec_num == mfcomment_chunks + 1)
3153 {
3154 POINT pt;
3155 ok(rec->rdFunction == META_SETWINDOWORG, "got %04x\n", rec->rdFunction);
3156 switch(mode)
3157 {
3158 case MM_TEXT:
3159 case MM_ISOTROPIC:
3160 case MM_ANISOTROPIC:
3161 pt.y = MulDiv(rc->top, vert_res, vert_size * 100) + 1;
3162 pt.x = MulDiv(rc->left, horz_res, horz_size * 100);
3163 break;
3164 case MM_LOMETRIC:
3165 pt.y = MulDiv(-rc->top, 1, 10) + 1;
3166 pt.x = MulDiv( rc->left, 1, 10);
3167 break;
3168 case MM_HIMETRIC:
3169 pt.y = -rc->top + 1;
3170 pt.x = (rc->left >= 0) ? rc->left : rc->left + 1; /* strange but true */
3171 break;
3172 case MM_LOENGLISH:
3173 pt.y = MulDiv(-rc->top, 10, 254) + 1;
3174 pt.x = MulDiv( rc->left, 10, 254);
3175 break;
3176 case MM_HIENGLISH:
3177 pt.y = MulDiv(-rc->top, 100, 254) + 1;
3178 pt.x = MulDiv( rc->left, 100, 254);
3179 break;
3180 case MM_TWIPS:
3181 pt.y = MulDiv(-rc->top, 72 * 20, 2540) + 1;
3182 pt.x = MulDiv( rc->left, 72 * 20, 2540);
3183 break;
3184 default:
3185 pt.x = pt.y = 0;
3186 }
3187 ok(near_match((short)rec->rdParm[0], pt.y), "got %d expect %d\n", (short)rec->rdParm[0], pt.y);
3188 ok(near_match((short)rec->rdParm[1], pt.x), "got %d expect %d\n", (short)rec->rdParm[1], pt.x);
3189 }
3190 if(rec_num == mfcomment_chunks + 2)
3191 {
3192 ok(rec->rdFunction == META_SETWINDOWEXT, "got %04x\n", rec->rdFunction);
3193 ok(near_match((short)rec->rdParm[0], MulDiv(rc->bottom - rc->top, vert_res, vert_size * 100)),
3194 "got %d\n", (short)rec->rdParm[0]);
3195 ok(near_match((short)rec->rdParm[1], MulDiv(rc->right - rc->left, horz_res, horz_size * 100)),
3196 "got %d\n", (short)rec->rdParm[1]);
3197 }
3198
3199 rec_num++;
3200 rec = (METARECORD*)((WORD*)rec + rec->rdSize);
3201 }
3202
3203 end:
3204 HeapFree(GetProcessHeap(), 0, mh);
3205 HeapFree(GetProcessHeap(), 0, enh_header);
3206 DeleteEnhMetaFile(emf);
3207
3208 ReleaseDC(NULL, display_dc);
3209 }
3210
3211 static void test_GetWinMetaFileBits(void)
3212 {
3213 UINT mode;
3214 RECT frames[] =
3215 {
3216 { 1000, 2000, 3000, 6000},
3217 {-1000, 2000, 3000, 6000},
3218 { 1000, -2000, 3000, 6000},
3219 { 1005, 2005, 3000, 6000},
3220 {-1005, -2005, 3000, 6000},
3221 {-1005, -2010, 3000, 6000},
3222 {-1005, 2010, 3000, 6000},
3223 { 0, 0, 1, 1},
3224 { -1, -1, 1, 1},
3225 { 0, 0, 0, 0}
3226 };
3227
3228 for(mode = MM_MIN; mode <= MM_MAX; mode++)
3229 {
3230 RECT *rc;
3231 trace("mode %d\n", mode);
3232
3233 for(rc = frames; rc->right - rc->left > 0; rc++)
3234 {
3235 trace("frame %d,%d - %d,%d\n", rc->left, rc->top, rc->right, rc->bottom);
3236 getwinmetafilebits(mode, 1, rc);
3237 getwinmetafilebits(mode, 2, rc);
3238 }
3239 }
3240 }
3241
3242 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
3243 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
3244 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
3245
3246 static void test_gdiis(void)
3247 {
3248 RECT rect = {0,0,100,100};
3249 HDC hdc, hemfDC, hmfDC;
3250 HENHMETAFILE hemf;
3251 HMODULE hgdi32;
3252
3253 /* resolve all the functions */
3254 hgdi32 = GetModuleHandleA("gdi32.dll");
3255 pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
3256 pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
3257 pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
3258
3259 if(!pGdiIsMetaPrintDC || !pGdiIsMetaFileDC || !pGdiIsPlayMetafileDC)
3260 {
3261 win_skip("Needed GdiIs* functions are not available\n");
3262 return;
3263 }
3264
3265 /* try with nothing */
3266 ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
3267 ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
3268 ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
3269
3270 /* try with a metafile */
3271 hmfDC = CreateMetaFileA(NULL);
3272 ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
3273 ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
3274 ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
3275 DeleteMetaFile(CloseMetaFile(hmfDC));
3276
3277 /* try with an enhanced metafile */
3278 hdc = GetDC(NULL);
3279 hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
3280 ok(hemfDC != NULL, "failed to create emf\n");
3281
3282 ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
3283 ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
3284 ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
3285
3286 hemf = CloseEnhMetaFile(hemfDC);
3287 ok(hemf != NULL, "failed to close EMF\n");
3288 DeleteEnhMetaFile(hemf);
3289 ReleaseDC(NULL,hdc);
3290 }
3291
3292 static void test_SetEnhMetaFileBits(void)
3293 {
3294 BYTE data[256];
3295 HENHMETAFILE hemf;
3296 ENHMETAHEADER *emh;
3297
3298 memset(data, 0xAA, sizeof(data));
3299 SetLastError(0xdeadbeef);
3300 hemf = SetEnhMetaFileBits(sizeof(data), data);
3301 ok(!hemf, "SetEnhMetaFileBits should fail\n");
3302 ok(GetLastError() == ERROR_INVALID_DATA ||
3303 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
3304 "expected ERROR_INVALID_DATA or ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3305
3306 emh = (ENHMETAHEADER *)data;
3307 memset(emh, 0, sizeof(*emh));
3308
3309 emh->iType = EMR_HEADER;
3310 emh->nSize = sizeof(*emh);
3311 emh->dSignature = ENHMETA_SIGNATURE;
3312 /* emh->nVersion = 0x10000; XP doesn't care about version */
3313 emh->nBytes = sizeof(*emh);
3314 /* emh->nRecords = 1; XP doesn't care about records */
3315 emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
3316
3317 SetLastError(0xdeadbeef);
3318 hemf = SetEnhMetaFileBits(emh->nBytes, data);
3319 ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
3320 DeleteEnhMetaFile(hemf);
3321
3322 /* XP refuses to load unaligned EMF */
3323 emh->nBytes++;
3324 SetLastError(0xdeadbeef);
3325 hemf = SetEnhMetaFileBits(emh->nBytes, data);
3326 ok(!hemf ||
3327 broken(hemf != NULL), /* Win9x, WinMe */
3328 "SetEnhMetaFileBits should fail\n");
3329 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
3330 DeleteEnhMetaFile(hemf);
3331
3332 emh->dSignature = 0;
3333 emh->nBytes--;
3334 SetLastError(0xdeadbeef);
3335 hemf = SetEnhMetaFileBits(emh->nBytes, data);
3336 ok(!hemf ||
3337 broken(hemf != NULL), /* Win9x, WinMe */
3338 "SetEnhMetaFileBits should fail\n");
3339 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
3340 DeleteEnhMetaFile(hemf);
3341 }
3342
3343 static void test_emf_polybezier(void)
3344 {
3345 HDC hdcMetafile;
3346 HENHMETAFILE hemf;
3347 POINT pts[4];
3348 BOOL ret;
3349
3350 SetLastError(0xdeadbeef);
3351 hdcMetafile = CreateEnhMetaFileA(GetDC(0), NULL, NULL, NULL);
3352 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
3353
3354 pts[0].x = pts[0].y = 10;
3355 pts[1].x = pts[1].y = 20;
3356 pts[2].x = pts[2].y = 15;
3357 pts[3].x = pts[3].y = 25;
3358 ret = PolyBezierTo(hdcMetafile, pts, 3); /* EMR_POLYBEZIERTO16 */
3359 ok( ret, "PolyBezierTo failed\n" );
3360 ret = PolyBezier(hdcMetafile, pts, 4); /* EMR_POLYBEZIER16 */
3361 ok( ret, "PolyBezier failed\n" );
3362
3363 pts[0].x = pts[0].y = 32769;
3364 ret = PolyBezier(hdcMetafile, pts, 4); /* EMR_POLYBEZIER */
3365 ok( ret, "PolyBezier failed\n" );
3366 ret = PolyBezierTo(hdcMetafile, pts, 3); /* EMR_POLYBEZIERTO */
3367 ok( ret, "PolyBezierTo failed\n" );
3368
3369 hemf = CloseEnhMetaFile(hdcMetafile);
3370 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
3371
3372 if(compare_emf_bits(hemf, EMF_BEZIER_BITS, sizeof(EMF_BEZIER_BITS),
3373 "emf_Bezier", FALSE) != 0)
3374 {
3375 dump_emf_bits(hemf, "emf_Bezier");
3376 dump_emf_records(hemf, "emf_Bezier");
3377 }
3378
3379 DeleteEnhMetaFile(hemf);
3380 }
3381
3382 START_TEST(metafile)
3383 {
3384 init_function_pointers();
3385
3386 /* For enhanced metafiles (enhmfdrv) */
3387 test_ExtTextOut();
3388 test_ExtTextOutScale();
3389 test_SaveDC();
3390 test_emf_BitBlt();
3391 test_emf_DCBrush();
3392 test_emf_ExtTextOut_on_path();
3393 test_emf_clipping();
3394 test_emf_polybezier();
3395
3396 /* For win-format metafiles (mfdrv) */
3397 test_mf_SaveDC();
3398 test_mf_Blank();
3399 test_mf_Graphics();
3400 test_mf_PatternBrush();
3401 test_mf_DCBrush();
3402 test_CopyMetaFile();
3403 test_SetMetaFileBits();
3404 test_mf_ExtTextOut_on_path();
3405 test_mf_clipping();
3406
3407 /* For metafile conversions */
3408 test_mf_conversions();
3409 test_SetWinMetaFileBits();
3410 test_GetWinMetaFileBits();
3411
3412 test_gdiis();
3413 test_SetEnhMetaFileBits();
3414 }