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