1 /*
2 * Unit tests for metafile functions
3 *
4 * Copyright (c) 2002 Dmitry Timoshkov
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <math.h>
24
25 #include "wine/test.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30
31 static LOGFONTA orig_lf;
32 static BOOL emr_processed = FALSE;
33
34 /* Arbitrarily chosen values for the second co-ordinate of a metafile line */
35 #define LINE_X 55.0f
36 #define LINE_Y 15.0f
37
38 static INT (WINAPI * pGetRelAbs)(HDC, DWORD);
39 static INT (WINAPI * pSetRelAbs)(HDC, INT);
40
41 #define GDI_GET_PROC(func) \
42 p ## func = (void *)GetProcAddress(hGDI, #func); \
43 if(!p ## func) \
44 trace("GetProcAddress(hGDI, \"%s\") failed\n", #func); \
45
46 static void init_function_pointers(void)
47 {
48 HMODULE hGDI;
49
50 pGetRelAbs = NULL;
51 pSetRelAbs = NULL;
52
53 hGDI = GetModuleHandleA("gdi32.dll");
54 assert(hGDI);
55 GDI_GET_PROC(GetRelAbs);
56 GDI_GET_PROC(SetRelAbs);
57 }
58
59 static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
60 const ENHMETARECORD *emr, int n_objs, LPARAM param)
61 {
62 static int n_record;
63 DWORD i;
64 const INT *dx;
65 INT *orig_dx = (INT *)param;
66 LOGFONTA device_lf;
67 INT ret;
68
69 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
70 hdc, emr->iType, emr->nSize, (void *)param);
71
72 if(!hdc) return 1;
73
74 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
75
76 switch (emr->iType)
77 {
78 case EMR_HEADER:
79 ok(GetTextAlign(hdc) == 0, "text align %08x\n", GetTextAlign(hdc));
80 ok(GetBkColor(hdc) == RGB(0xff, 0xff, 0xff), "bk color %08x\n", GetBkColor(hdc));
81 ok(GetTextColor(hdc) == RGB(0x0, 0x0, 0x0), "text color %08x\n", GetTextColor(hdc));
82 ok(GetROP2(hdc) == R2_COPYPEN, "rop %d\n", GetROP2(hdc));
83 ok(GetArcDirection(hdc) == AD_COUNTERCLOCKWISE, "arc dir %d\n", GetArcDirection(hdc));
84 ok(GetPolyFillMode(hdc) == ALTERNATE, "poly fill %d\n", GetPolyFillMode(hdc));
85 ok(GetStretchBltMode(hdc) == BLACKONWHITE, "stretchblt mode %d\n", GetStretchBltMode(hdc));
86
87 /* GetBkMode, GetRelAbs do not get reset to the default value */
88 ok(GetBkMode(hdc) == OPAQUE, "bk mode %d\n", GetBkMode(hdc));
89 if(pSetRelAbs && pGetRelAbs)
90 ok(pGetRelAbs(hdc, 0) == RELATIVE, "relabs %d\n", pGetRelAbs(hdc, 0));
91
92 n_record = 0;
93 break;
94
95 case EMR_EXTTEXTOUTA:
96 {
97 const EMREXTTEXTOUTA *emr_ExtTextOutA = (const EMREXTTEXTOUTA *)emr;
98 dx = (const INT *)((const char *)emr + emr_ExtTextOutA->emrtext.offDx);
99
100 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
101 ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError());
102
103 /* compare up to lfOutPrecision, other values are not interesting,
104 * and in fact sometimes arbitrary adapted by Win9x.
105 */
106 ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
107 ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
108
109 for(i = 0; i < emr_ExtTextOutA->emrtext.nChars; i++)
110 {
111 ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
112 n_record, i, dx[i], orig_dx[i]);
113 }
114 n_record++;
115 emr_processed = TRUE;
116 break;
117 }
118
119 case EMR_EXTTEXTOUTW:
120 {
121 const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr;
122 dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx);
123
124 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
125 ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError());
126
127 /* compare up to lfOutPrecision, other values are not interesting,
128 * and in fact sometimes arbitrary adapted by Win9x.
129 */
130 ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
131 ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
132
133 for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
134 {
135 ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
136 n_record, i, dx[i], orig_dx[i]);
137 }
138 n_record++;
139 emr_processed = TRUE;
140 break;
141 }
142
143 default:
144 break;
145 }
146
147 return 1;
148 }
149
150 static void test_ExtTextOut(void)
151 {
152 HWND hwnd;
153 HDC hdcDisplay, hdcMetafile;
154 HENHMETAFILE hMetafile;
155 HFONT hFont;
156 static const char text[] = "Simple text to test ExtTextOut on metafiles";
157 INT i, len, dx[256];
158 static const RECT rc = { 0, 0, 100, 100 };
159 BOOL ret;
160
161 assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
162
163 /* Win9x doesn't play EMFs on invisible windows */
164 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
165 0, 0, 200, 200, 0, 0, 0, NULL);
166 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
167
168 hdcDisplay = GetDC(hwnd);
169 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
170
171 trace("hdcDisplay %p\n", hdcDisplay);
172
173 SetMapMode(hdcDisplay, MM_TEXT);
174
175 memset(&orig_lf, 0, sizeof(orig_lf));
176
177 orig_lf.lfCharSet = ANSI_CHARSET;
178 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
179 orig_lf.lfWeight = FW_DONTCARE;
180 orig_lf.lfHeight = 7;
181 orig_lf.lfQuality = DEFAULT_QUALITY;
182 lstrcpyA(orig_lf.lfFaceName, "Arial");
183 hFont = CreateFontIndirectA(&orig_lf);
184 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
185
186 hFont = SelectObject(hdcDisplay, hFont);
187
188 len = lstrlenA(text);
189 for (i = 0; i < len; i++)
190 {
191 ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
192 ok( ret, "GetCharWidthA error %d\n", GetLastError());
193 }
194 hFont = SelectObject(hdcDisplay, hFont);
195
196 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
197 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
198
199 trace("hdcMetafile %p\n", hdcMetafile);
200
201 ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
202 "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
203
204 hFont = SelectObject(hdcMetafile, hFont);
205
206 /* 1. pass NULL lpDx */
207 ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
208 ok( ret, "ExtTextOutA error %d\n", GetLastError());
209
210 /* 2. pass custom lpDx */
211 ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
212 ok( ret, "ExtTextOutA error %d\n", GetLastError());
213
214 hFont = SelectObject(hdcMetafile, hFont);
215 ret = DeleteObject(hFont);
216 ok( ret, "DeleteObject error %d\n", GetLastError());
217
218 hMetafile = CloseEnhMetaFile(hdcMetafile);
219 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
220
221 ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
222
223 ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
224 ok( ret, "PlayEnhMetaFile error %d\n", GetLastError());
225
226 SetTextAlign(hdcDisplay, TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING );
227 SetBkColor(hdcDisplay, RGB(0xff, 0, 0));
228 SetTextColor(hdcDisplay, RGB(0, 0xff, 0));
229 SetROP2(hdcDisplay, R2_NOT);
230 SetArcDirection(hdcDisplay, AD_CLOCKWISE);
231 SetPolyFillMode(hdcDisplay, WINDING);
232 SetStretchBltMode(hdcDisplay, HALFTONE);
233
234 if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
235 SetBkMode(hdcDisplay, OPAQUE);
236
237 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
238 ok( ret, "EnumEnhMetaFile error %d\n", GetLastError());
239
240 ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
241 "text align %08x\n", GetTextAlign(hdcDisplay));
242 ok( GetBkColor(hdcDisplay) == RGB(0xff, 0, 0), "bk color %08x\n", GetBkColor(hdcDisplay));
243 ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08x\n", GetTextColor(hdcDisplay));
244 ok( GetROP2(hdcDisplay) == R2_NOT, "rop2 %d\n", GetROP2(hdcDisplay));
245 ok( GetArcDirection(hdcDisplay) == AD_CLOCKWISE, "arc dir %d\n", GetArcDirection(hdcDisplay));
246 ok( GetPolyFillMode(hdcDisplay) == WINDING, "poly fill %d\n", GetPolyFillMode(hdcDisplay));
247 ok( GetStretchBltMode(hdcDisplay) == HALFTONE, "stretchblt mode %d\n", GetStretchBltMode(hdcDisplay));
248
249 ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
250
251 ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
252 "A valid hdc has to require a valid rc\n");
253
254 ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
255 "A null hdc does not require a valid rc\n");
256
257 ret = DeleteEnhMetaFile(hMetafile);
258 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
259 ret = ReleaseDC(hwnd, hdcDisplay);
260 ok( ret, "ReleaseDC error %d\n", GetLastError());
261 DestroyWindow(hwnd);
262 }
263
264 static void check_dc_state(HDC hdc, int restore_no,
265 int wnd_org_x, int wnd_org_y, int wnd_ext_x, int wnd_ext_y,
266 int vp_org_x, int vp_org_y, int vp_ext_x, int vp_ext_y)
267 {
268 BOOL ret;
269 XFORM xform;
270 POINT vp_org, win_org;
271 SIZE vp_size, win_size;
272 FLOAT xscale, yscale, edx, edy;
273
274 SetLastError(0xdeadbeef);
275 ret = GetWorldTransform(hdc, &xform);
276 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) goto win9x_here;
277 ok(ret, "GetWorldTransform error %u\n", GetLastError());
278
279 trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
280
281 ok(xform.eM12 == 0.0, "%d: expected eM12 0.0, got %f\n", restore_no, xform.eM12);
282 ok(xform.eM21 == 0.0, "%d: expected eM21 0.0, got %f\n", restore_no, xform.eM21);
283
284 xscale = (FLOAT)vp_ext_x / (FLOAT)wnd_ext_x;
285 trace("x scale %f\n", xscale);
286 ok(fabs(xscale - xform.eM11) < 0.01, "%d: vp_ext_x %d, wnd_ext_cx %d, eM11 %f\n",
287 restore_no, vp_ext_x, wnd_ext_x, xform.eM11);
288
289 yscale = (FLOAT)vp_ext_y / (FLOAT)wnd_ext_y;
290 trace("y scale %f\n", yscale);
291 ok(fabs(yscale - xform.eM22) < 0.01, "%d: vp_ext_y %d, wnd_ext_y %d, eM22 %f\n",
292 restore_no, vp_ext_y, wnd_ext_y, xform.eM22);
293
294 edx = (FLOAT)vp_org_x - xform.eM11 * (FLOAT)wnd_org_x;
295 ok(fabs(edx - xform.eDx) < 0.01, "%d: edx %f != eDx %f\n", restore_no, edx, xform.eDx);
296 edy = (FLOAT)vp_org_y - xform.eM22 * (FLOAT)wnd_org_y;
297 ok(fabs(edy - xform.eDy) < 0.01, "%d: edy %f != eDy %f\n", restore_no, edy, xform.eDy);
298
299 return;
300
301 win9x_here:
302
303 GetWindowOrgEx(hdc, &win_org);
304 GetViewportOrgEx(hdc, &vp_org);
305 GetWindowExtEx(hdc, &win_size);
306 GetViewportExtEx(hdc, &vp_size);
307
308 ok(wnd_org_x == win_org.x, "%d: wnd_org_x: %d != %d\n", restore_no, wnd_org_x, win_org.x);
309 ok(wnd_org_y == win_org.y, "%d: wnd_org_y: %d != %d\n", restore_no, wnd_org_y, win_org.y);
310
311 ok(vp_org_x == vp_org.x, "%d: vport_org_x: %d != %d\n", restore_no, vp_org_x, vp_org.x);
312 ok(vp_org_y == vp_org.y, "%d: vport_org_y: %d != %d\n", restore_no, vp_org_y, vp_org.y);
313
314 ok(wnd_ext_x == win_size.cx, "%d: wnd_ext_x: %d != %d\n", restore_no, wnd_ext_x, win_size.cx);
315 ok(wnd_ext_y == win_size.cy, "%d: wnd_ext_y: %d != %d\n", restore_no, wnd_ext_y, win_size.cy);
316
317 ok(vp_ext_x == vp_size.cx, "%d: vport_ext_x: %d != %d\n", restore_no, vp_ext_x, vp_size.cx);
318 ok(vp_ext_y == vp_size.cy, "%d: vport_ext_y: %d != %d\n", restore_no, vp_ext_y, vp_size.cy);
319 }
320
321 static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
322 const ENHMETARECORD *emr, int n_objs, LPARAM param)
323 {
324 BOOL ret;
325 XFORM xform;
326 POINT pt;
327 SIZE size;
328 static int save_state;
329 static int restore_no;
330
331 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
332 hdc, emr->iType, emr->nSize, (void *)param);
333
334 trace("BEFORE:\n");
335 SetLastError(0xdeadbeef);
336 ret = GetWorldTransform(hdc, &xform);
337 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
338 {
339 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
340 trace("window org (%d,%d)\n", pt.x, pt.y);
341 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
342 trace("vport org (%d,%d)\n", pt.x, pt.y);
343 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
344 trace("window ext (%d,%d)\n", size.cx, size.cy);
345 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
346 trace("vport ext (%d,%d)\n", size.cx, size.cy);
347 }
348 else
349 {
350 ok(ret, "GetWorldTransform error %u\n", GetLastError());
351 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
352 }
353
354 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
355
356 switch (emr->iType)
357 {
358 case EMR_HEADER:
359 {
360 static RECT exp_bounds = { 0, 0, 150, 150 };
361 RECT bounds;
362 const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
363
364 trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
365 emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
366 emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
367 trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
368 emf->szlDevice.cx, emf->szlDevice.cy);
369
370 SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
371 ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
372
373 save_state = 0;
374 restore_no = 0;
375 check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
376 break;
377 }
378
379 case EMR_LINETO:
380 {
381 const EMRLINETO *line = (const EMRLINETO *)emr;
382 trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
383 break;
384 }
385 case EMR_SETWINDOWORGEX:
386 {
387 const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
388 trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
389 break;
390 }
391 case EMR_SETWINDOWEXTEX:
392 {
393 const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
394 trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
395 break;
396 }
397 case EMR_SETVIEWPORTORGEX:
398 {
399 const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
400 trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
401 break;
402 }
403 case EMR_SETVIEWPORTEXTEX:
404 {
405 const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
406 trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
407 break;
408 }
409 case EMR_SAVEDC:
410 save_state++;
411 trace("EMR_SAVEDC\n");
412 break;
413
414 case EMR_RESTOREDC:
415 {
416 const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
417 trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
418
419 switch(++restore_no)
420 {
421 case 1:
422 ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
423 check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
424 break;
425 case 2:
426 ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
427 check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
428 break;
429 case 3:
430 ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
431 check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
432 break;
433 }
434 ok(restore_no <= 3, "restore_no %d\n", restore_no);
435 save_state += restoredc->iRelative;
436 break;
437 }
438 case EMR_EOF:
439 ok(save_state == 0, "EOF save_state %d\n", save_state);
440 break;
441 }
442
443 trace("AFTER:\n");
444 SetLastError(0xdeadbeef);
445 ret = GetWorldTransform(hdc, &xform);
446 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
447 {
448 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
449 trace("window org (%d,%d)\n", pt.x, pt.y);
450 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
451 trace("vport org (%d,%d)\n", pt.x, pt.y);
452 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
453 trace("window ext (%d,%d)\n", size.cx, size.cy);
454 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
455 trace("vport ext (%d,%d)\n", size.cx, size.cy);
456 }
457 else
458 {
459 ok(ret, "GetWorldTransform error %u\n", GetLastError());
460 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
461 }
462
463 return 1;
464 }
465
466 static void test_SaveDC(void)
467 {
468 HDC hdcMetafile, hdcDisplay;
469 HENHMETAFILE hMetafile;
470 HWND hwnd;
471 int ret;
472 static const RECT rc = { 0, 0, 150, 150 };
473
474 /* Win9x doesn't play EMFs on invisible windows */
475 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
476 0, 0, 200, 200, 0, 0, 0, NULL);
477 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
478
479 hdcDisplay = GetDC(hwnd);
480 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
481
482 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
483 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
484
485 SetMapMode(hdcMetafile, MM_ANISOTROPIC);
486
487 /* Need to write something to the emf, otherwise Windows won't play it back */
488 LineTo(hdcMetafile, 150, 150);
489
490 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
491 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
492 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
493 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
494
495 /* Force Win9x to update DC state */
496 SetPixelV(hdcMetafile, 50, 50, 0);
497
498 ret = SaveDC(hdcMetafile);
499 ok(ret == 1, "ret = %d\n", ret);
500
501 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
502 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
503 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
504 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
505
506 /* Force Win9x to update DC state */
507 SetPixelV(hdcMetafile, 50, 50, 0);
508
509 ret = SaveDC(hdcMetafile);
510 ok(ret == 2, "ret = %d\n", ret);
511
512 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
513 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
514 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
515 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
516
517 /* Force Win9x to update DC state */
518 SetPixelV(hdcMetafile, 50, 50, 0);
519
520 ret = SaveDC(hdcMetafile);
521 ok(ret == 3, "ret = %d\n", ret);
522
523 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
524 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
525 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
526 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
527
528 /* Force Win9x to update DC state */
529 SetPixelV(hdcMetafile, 50, 50, 0);
530
531 ret = RestoreDC(hdcMetafile, -1);
532 ok(ret, "ret = %d\n", ret);
533
534 ret = SaveDC(hdcMetafile);
535 ok(ret == 3, "ret = %d\n", ret);
536
537 ret = RestoreDC(hdcMetafile, 1);
538 ok(ret, "ret = %d\n", ret);
539
540 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
541 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
542 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
543 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
544
545 /* Force Win9x to update DC state */
546 SetPixelV(hdcMetafile, 50, 50, 0);
547
548 ret = SaveDC(hdcMetafile);
549 ok(ret == 1, "ret = %d\n", ret);
550
551 ret = SaveDC(hdcMetafile);
552 ok(ret == 2, "ret = %d\n", ret);
553
554 hMetafile = CloseEnhMetaFile(hdcMetafile);
555 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
556
557 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
558 ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
559
560 ret = DeleteEnhMetaFile(hMetafile);
561 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
562 ret = ReleaseDC(hwnd, hdcDisplay);
563 ok( ret, "ReleaseDC error %d\n", GetLastError());
564 DestroyWindow(hwnd);
565 }
566
567 /* Win-format metafile (mfdrv) tests */
568 /* These tests compare the generated metafiles byte-by-byte */
569 /* with the nominal results. */
570
571 /* Maximum size of sample metafiles in bytes. */
572 #define MF_BUFSIZE 512
573
574 /* 8x8 bitmap data for a pattern brush */
575 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
576 0x01, 0x00, 0x02, 0x00,
577 0x03, 0x00, 0x04, 0x00,
578 0x05, 0x00, 0x06, 0x00,
579 0x07, 0x00, 0x08, 0x00
580 };
581
582 /* Sample metafiles to be compared to the outputs of the
583 * test functions.
584 */
585
586 static const unsigned char MF_BLANK_BITS[] = {
587 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
588 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
590 };
591
592 static const unsigned char MF_GRAPHICS_BITS[] = {
593 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
595 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
596 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
597 0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
598 0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
599 0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
600 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
601 0x00, 0x00, 0x00, 0x00
602 };
603
604 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
605 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
606 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
608 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
609 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
610 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
615 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
616 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
617 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
618 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
619 0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
620 0x00, 0x00
621 };
622
623 static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
624 {
625 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
627 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
628 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
629 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
630 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
631 0x00, 0x00
632 };
633
634 static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
635 {
636 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
641 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
642 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
643 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
646 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
649 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
650 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
651 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
653 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
654 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
655 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
656 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
659 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
660 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
661 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
662 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
663 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
664 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
665 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
666 0x14, 0x00, 0x00, 0x00
667 };
668
669 static const unsigned char MF_LINETO_BITS[] = {
670 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
671 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
672 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
673 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
674 0x00, 0x00
675 };
676
677 static const unsigned char EMF_LINETO_BITS[] = {
678 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
683 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
684 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
685 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
688 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
691 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
692 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
693 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
694 0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
695 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
696 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
697 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
698 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
699 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
700 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
701 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
702 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
703 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
704 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
705 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
706 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
707 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
708 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
709 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
710 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
711 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
712 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
713 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
715 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
717 };
718
719 static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
720 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
721 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
725 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
726 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
727 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
728 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
729 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
730 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
732 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
733 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
734 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
735 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
736 0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
737 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
738 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
739 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
740 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
741 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
743 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
744 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
745 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
746 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
747 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
748 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
749 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
750 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
751 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
752 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
753 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
754 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
755 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
756 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
757 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
758 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
759 };
760
761 static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
762 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
767 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
768 0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
769 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
771 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
772 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
775 0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
776 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
777 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
778 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
779 0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
780 0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
781 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
782 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
783 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
784 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
785 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
786 0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
787 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
788 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
790 0x14, 0x00, 0x00, 0x00
791 };
792
793 /* For debugging or dumping the raw metafiles produced by
794 * new test functions.
795 */
796 static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
797 INT nobj, LPARAM param)
798 {
799 trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, param %p\n",
800 hdc, mr->rdFunction, mr->rdSize, (void *)param);
801 return TRUE;
802 }
803
804 /* For debugging or dumping the raw metafiles produced by
805 * new test functions.
806 */
807
808 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
809 {
810 BYTE buf[MF_BUFSIZE];
811 UINT mfsize, i;
812
813 if (!winetest_debug) return;
814
815 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
816 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
817
818 printf ("MetaFile %s has bits:\n{\n ", desc);
819 for (i=0; i<mfsize; i++)
820 {
821 printf ("0x%02x", buf[i]);
822 if (i == mfsize-1)
823 printf ("\n");
824 else if (i % 8 == 7)
825 printf (",\n ");
826 else
827 printf (", ");
828 }
829 printf ("};\n");
830 }
831
832 /* Compare the metafile produced by a test function with the
833 * expected raw metafile data in "bits".
834 * Return value is 0 for a perfect match,
835 * -1 if lengths aren't equal,
836 * otherwise returns the number of non-matching bytes.
837 */
838
839 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
840 const char *desc)
841 {
842 unsigned char buf[MF_BUFSIZE];
843 UINT mfsize, i;
844 int diff;
845
846 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
847 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
848 if (mfsize < MF_BUFSIZE)
849 ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
850 desc, mfsize, bsize);
851 else
852 ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
853 desc, mfsize, bsize);
854 if (mfsize != bsize)
855 return -1;
856
857 diff = 0;
858 for (i=0; i<bsize; i++)
859 {