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