a186608c0acd35ed0e832cc7949fb0a306ffe6f8
[reactos.git] / rostests / winetests / gdi32 / metafile.c
1 /*
2 * Unit tests for metafile functions
3 *
4 * Copyright (c) 2002 Dmitry Timoshkov
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <math.h>
24
25 #include "wine/test.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30
31 static LOGFONTA orig_lf;
32 static BOOL emr_processed = FALSE;
33
34 /* Arbitrarily chosen values for the second co-ordinate of a metafile line */
35 #define LINE_X 55.0f
36 #define LINE_Y 15.0f
37
38 static INT (WINAPI * pGetRelAbs)(HDC, DWORD);
39 static INT (WINAPI * pSetRelAbs)(HDC, INT);
40
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 SetLastError(0xdeadbeef);
125 ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf);
126 ok( ret == sizeof(device_lf) ||
127 broken(ret == (sizeof(device_lf) - LF_FACESIZE + strlen(device_lf.lfFaceName) + 1)), /* NT4 */
128 "GetObjectA error %d\n", GetLastError());
129
130 /* compare up to lfOutPrecision, other values are not interesting,
131 * and in fact sometimes arbitrary adapted by Win9x.
132 */
133 ok(!memcmp(&orig_lf, &device_lf, FIELD_OFFSET(LOGFONTA, lfOutPrecision)), "fonts don't match\n");
134 ok(!lstrcmpA(orig_lf.lfFaceName, device_lf.lfFaceName), "font names don't match\n");
135
136 for(i = 0; i < emr_ExtTextOutW->emrtext.nChars; i++)
137 {
138 ok(orig_dx[i] == dx[i], "pass %d: dx[%d] (%d) didn't match %d\n",
139 n_record, i, dx[i], orig_dx[i]);
140 }
141 n_record++;
142 emr_processed = TRUE;
143 break;
144 }
145
146 default:
147 break;
148 }
149
150 return 1;
151 }
152
153 static void test_ExtTextOut(void)
154 {
155 HWND hwnd;
156 HDC hdcDisplay, hdcMetafile;
157 HENHMETAFILE hMetafile;
158 HFONT hFont;
159 static const char text[] = "Simple text to test ExtTextOut on metafiles";
160 INT i, len, dx[256];
161 static const RECT rc = { 0, 0, 100, 100 };
162 BOOL ret;
163
164 assert(sizeof(dx)/sizeof(dx[0]) >= lstrlenA(text));
165
166 /* Win9x doesn't play EMFs on invisible windows */
167 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
168 0, 0, 200, 200, 0, 0, 0, NULL);
169 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
170
171 hdcDisplay = GetDC(hwnd);
172 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
173
174 trace("hdcDisplay %p\n", hdcDisplay);
175
176 SetMapMode(hdcDisplay, MM_TEXT);
177
178 memset(&orig_lf, 0, sizeof(orig_lf));
179
180 orig_lf.lfCharSet = ANSI_CHARSET;
181 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
182 orig_lf.lfWeight = FW_DONTCARE;
183 orig_lf.lfHeight = 7;
184 orig_lf.lfQuality = DEFAULT_QUALITY;
185 lstrcpyA(orig_lf.lfFaceName, "Arial");
186 hFont = CreateFontIndirectA(&orig_lf);
187 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
188
189 hFont = SelectObject(hdcDisplay, hFont);
190
191 len = lstrlenA(text);
192 for (i = 0; i < len; i++)
193 {
194 ret = GetCharWidthA(hdcDisplay, text[i], text[i], &dx[i]);
195 ok( ret, "GetCharWidthA error %d\n", GetLastError());
196 }
197 hFont = SelectObject(hdcDisplay, hFont);
198
199 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
200 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
201
202 trace("hdcMetafile %p\n", hdcMetafile);
203
204 ok(GetDeviceCaps(hdcMetafile, TECHNOLOGY) == DT_RASDISPLAY,
205 "GetDeviceCaps(TECHNOLOGY) has to return DT_RASDISPLAY for a display based EMF\n");
206
207 hFont = SelectObject(hdcMetafile, hFont);
208
209 /* 1. pass NULL lpDx */
210 ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, lstrlenA(text), NULL);
211 ok( ret, "ExtTextOutA error %d\n", GetLastError());
212
213 /* 2. pass custom lpDx */
214 ret = ExtTextOutA(hdcMetafile, 0, 20, 0, &rc, text, lstrlenA(text), dx);
215 ok( ret, "ExtTextOutA error %d\n", GetLastError());
216
217 hFont = SelectObject(hdcMetafile, hFont);
218 ret = DeleteObject(hFont);
219 ok( ret, "DeleteObject error %d\n", GetLastError());
220
221 hMetafile = CloseEnhMetaFile(hdcMetafile);
222 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
223
224 ok(!GetObjectType(hdcMetafile), "CloseEnhMetaFile has to destroy metafile hdc\n");
225
226 ret = PlayEnhMetaFile(hdcDisplay, hMetafile, &rc);
227 ok( ret, "PlayEnhMetaFile error %d\n", GetLastError());
228
229 SetTextAlign(hdcDisplay, TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING );
230 SetBkColor(hdcDisplay, RGB(0xff, 0, 0));
231 SetTextColor(hdcDisplay, RGB(0, 0xff, 0));
232 SetROP2(hdcDisplay, R2_NOT);
233 SetArcDirection(hdcDisplay, AD_CLOCKWISE);
234 SetPolyFillMode(hdcDisplay, WINDING);
235 SetStretchBltMode(hdcDisplay, HALFTONE);
236
237 if(pSetRelAbs) pSetRelAbs(hdcDisplay, RELATIVE);
238 SetBkMode(hdcDisplay, OPAQUE);
239
240 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, &rc);
241 ok( ret, "EnumEnhMetaFile error %d\n", GetLastError());
242
243 ok( GetTextAlign(hdcDisplay) == (TA_UPDATECP | TA_CENTER | TA_BASELINE | TA_RTLREADING),
244 "text align %08x\n", GetTextAlign(hdcDisplay));
245 ok( GetBkColor(hdcDisplay) == RGB(0xff, 0, 0), "bk color %08x\n", GetBkColor(hdcDisplay));
246 ok( GetTextColor(hdcDisplay) == RGB(0, 0xff, 0), "text color %08x\n", GetTextColor(hdcDisplay));
247 ok( GetROP2(hdcDisplay) == R2_NOT, "rop2 %d\n", GetROP2(hdcDisplay));
248 ok( GetArcDirection(hdcDisplay) == AD_CLOCKWISE, "arc dir %d\n", GetArcDirection(hdcDisplay));
249 ok( GetPolyFillMode(hdcDisplay) == WINDING, "poly fill %d\n", GetPolyFillMode(hdcDisplay));
250 ok( GetStretchBltMode(hdcDisplay) == HALFTONE, "stretchblt mode %d\n", GetStretchBltMode(hdcDisplay));
251
252 ok(emr_processed, "EnumEnhMetaFile couldn't find EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW record\n");
253
254 ok(!EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc, dx, NULL),
255 "A valid hdc has to require a valid rc\n");
256
257 ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
258 "A null hdc does not require a valid rc\n");
259
260 ret = DeleteEnhMetaFile(hMetafile);
261 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
262 ret = ReleaseDC(hwnd, hdcDisplay);
263 ok( ret, "ReleaseDC error %d\n", GetLastError());
264 DestroyWindow(hwnd);
265 }
266
267 static void check_dc_state(HDC hdc, int restore_no,
268 int wnd_org_x, int wnd_org_y, int wnd_ext_x, int wnd_ext_y,
269 int vp_org_x, int vp_org_y, int vp_ext_x, int vp_ext_y)
270 {
271 BOOL ret;
272 XFORM xform;
273 POINT vp_org, win_org;
274 SIZE vp_size, win_size;
275 FLOAT xscale, yscale, edx, edy;
276
277 SetLastError(0xdeadbeef);
278 ret = GetWorldTransform(hdc, &xform);
279 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) goto win9x_here;
280 ok(ret, "GetWorldTransform error %u\n", GetLastError());
281
282 trace("%d: eM11 %f, eM22 %f, eDx %f, eDy %f\n", restore_no, xform.eM11, xform.eM22, xform.eDx, xform.eDy);
283
284 ok(xform.eM12 == 0.0, "%d: expected eM12 0.0, got %f\n", restore_no, xform.eM12);
285 ok(xform.eM21 == 0.0, "%d: expected eM21 0.0, got %f\n", restore_no, xform.eM21);
286
287 xscale = (FLOAT)vp_ext_x / (FLOAT)wnd_ext_x;
288 trace("x scale %f\n", xscale);
289 ok(fabs(xscale - xform.eM11) < 0.01, "%d: vp_ext_x %d, wnd_ext_cx %d, eM11 %f\n",
290 restore_no, vp_ext_x, wnd_ext_x, xform.eM11);
291
292 yscale = (FLOAT)vp_ext_y / (FLOAT)wnd_ext_y;
293 trace("y scale %f\n", yscale);
294 ok(fabs(yscale - xform.eM22) < 0.01, "%d: vp_ext_y %d, wnd_ext_y %d, eM22 %f\n",
295 restore_no, vp_ext_y, wnd_ext_y, xform.eM22);
296
297 edx = (FLOAT)vp_org_x - xform.eM11 * (FLOAT)wnd_org_x;
298 ok(fabs(edx - xform.eDx) < 0.01, "%d: edx %f != eDx %f\n", restore_no, edx, xform.eDx);
299 edy = (FLOAT)vp_org_y - xform.eM22 * (FLOAT)wnd_org_y;
300 ok(fabs(edy - xform.eDy) < 0.01, "%d: edy %f != eDy %f\n", restore_no, edy, xform.eDy);
301
302 return;
303
304 win9x_here:
305
306 GetWindowOrgEx(hdc, &win_org);
307 GetViewportOrgEx(hdc, &vp_org);
308 GetWindowExtEx(hdc, &win_size);
309 GetViewportExtEx(hdc, &vp_size);
310
311 ok(wnd_org_x == win_org.x, "%d: wnd_org_x: %d != %d\n", restore_no, wnd_org_x, win_org.x);
312 ok(wnd_org_y == win_org.y, "%d: wnd_org_y: %d != %d\n", restore_no, wnd_org_y, win_org.y);
313
314 ok(vp_org_x == vp_org.x, "%d: vport_org_x: %d != %d\n", restore_no, vp_org_x, vp_org.x);
315 ok(vp_org_y == vp_org.y, "%d: vport_org_y: %d != %d\n", restore_no, vp_org_y, vp_org.y);
316
317 ok(wnd_ext_x == win_size.cx, "%d: wnd_ext_x: %d != %d\n", restore_no, wnd_ext_x, win_size.cx);
318 ok(wnd_ext_y == win_size.cy, "%d: wnd_ext_y: %d != %d\n", restore_no, wnd_ext_y, win_size.cy);
319
320 ok(vp_ext_x == vp_size.cx, "%d: vport_ext_x: %d != %d\n", restore_no, vp_ext_x, vp_size.cx);
321 ok(vp_ext_y == vp_size.cy, "%d: vport_ext_y: %d != %d\n", restore_no, vp_ext_y, vp_size.cy);
322 }
323
324 static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
325 const ENHMETARECORD *emr, int n_objs, LPARAM param)
326 {
327 BOOL ret;
328 XFORM xform;
329 POINT pt;
330 SIZE size;
331 static int save_state;
332 static int restore_no;
333 static int select_no;
334
335 trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n",
336 hdc, emr->iType, emr->nSize, (void *)param);
337
338 trace("BEFORE:\n");
339 SetLastError(0xdeadbeef);
340 ret = GetWorldTransform(hdc, &xform);
341 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
342 {
343 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
344 trace("window org (%d,%d)\n", pt.x, pt.y);
345 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
346 trace("vport org (%d,%d)\n", pt.x, pt.y);
347 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
348 trace("window ext (%d,%d)\n", size.cx, size.cy);
349 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
350 trace("vport ext (%d,%d)\n", size.cx, size.cy);
351 }
352 else
353 {
354 ok(ret, "GetWorldTransform error %u\n", GetLastError());
355 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
356 }
357
358 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
359
360 switch (emr->iType)
361 {
362 case EMR_HEADER:
363 {
364 static RECT exp_bounds = { 0, 0, 150, 150 };
365 RECT bounds;
366 const ENHMETAHEADER *emf = (const ENHMETAHEADER *)emr;
367
368 trace("bounds %d,%d-%d,%d, frame %d,%d-%d,%d\n",
369 emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom,
370 emf->rclFrame.left, emf->rclFrame.top, emf->rclFrame.right, emf->rclFrame.bottom);
371 trace("mm %d x %d, device %d x %d\n", emf->szlMillimeters.cx, emf->szlMillimeters.cy,
372 emf->szlDevice.cx, emf->szlDevice.cy);
373
374 SetRect(&bounds, emf->rclBounds.left, emf->rclBounds.top, emf->rclBounds.right, emf->rclBounds.bottom);
375 ok(EqualRect(&bounds, &exp_bounds), "wrong bounds\n");
376
377 save_state = 0;
378 restore_no = 0;
379 select_no = 0;
380 check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1);
381 break;
382 }
383
384 case EMR_LINETO:
385 {
386 const EMRLINETO *line = (const EMRLINETO *)emr;
387 trace("EMR_LINETO %d,%d\n", line->ptl.x, line->ptl.x);
388 break;
389 }
390 case EMR_SETWINDOWORGEX:
391 {
392 const EMRSETWINDOWORGEX *org = (const EMRSETWINDOWORGEX *)emr;
393 trace("EMR_SETWINDOWORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
394 break;
395 }
396 case EMR_SETWINDOWEXTEX:
397 {
398 const EMRSETWINDOWEXTEX *ext = (const EMRSETWINDOWEXTEX *)emr;
399 trace("EMR_SETWINDOWEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
400 break;
401 }
402 case EMR_SETVIEWPORTORGEX:
403 {
404 const EMRSETVIEWPORTORGEX *org = (const EMRSETVIEWPORTORGEX *)emr;
405 trace("EMR_SETVIEWPORTORGEX: %d,%d\n", org->ptlOrigin.x, org->ptlOrigin.y);
406 break;
407 }
408 case EMR_SETVIEWPORTEXTEX:
409 {
410 const EMRSETVIEWPORTEXTEX *ext = (const EMRSETVIEWPORTEXTEX *)emr;
411 trace("EMR_SETVIEWPORTEXTEX: %d,%d\n", ext->szlExtent.cx, ext->szlExtent.cy);
412 break;
413 }
414 case EMR_SAVEDC:
415 save_state++;
416 trace("EMR_SAVEDC\n");
417 break;
418
419 case EMR_RESTOREDC:
420 {
421 const EMRRESTOREDC *restoredc = (const EMRRESTOREDC *)emr;
422 trace("EMR_RESTOREDC: %d\n", restoredc->iRelative);
423
424 switch(++restore_no)
425 {
426 case 1:
427 ok(restoredc->iRelative == -1, "first restore %d\n", restoredc->iRelative);
428 check_dc_state(hdc, restore_no, -2, -2, 8192, 8192, 20, 20, 20479, 20478);
429 break;
430 case 2:
431 ok(restoredc->iRelative == -3, "second restore %d\n", restoredc->iRelative);
432 check_dc_state(hdc, restore_no, 0, 0, 16384, 16384, 0, 0, 17873, 17872);
433 break;
434 case 3:
435 ok(restoredc->iRelative == -2, "third restore %d\n", restoredc->iRelative);
436 check_dc_state(hdc, restore_no, -4, -4, 32767, 32767, 40, 40, 3276, 3276);
437 break;
438 }
439 ok(restore_no <= 3, "restore_no %d\n", restore_no);
440 save_state += restoredc->iRelative;
441 break;
442 }
443 case EMR_SELECTOBJECT:
444 {
445 const EMRSELECTOBJECT *selectobj = (const EMRSELECTOBJECT*)emr;
446 trace("EMR_SELECTOBJECT: %x\n",selectobj->ihObject);
447 select_no ++;
448 break;
449 }
450 case EMR_EOF:
451 ok(save_state == 0, "EOF save_state %d\n", save_state);
452 ok(select_no == 3, "Too many/few selects %i\n",select_no);
453 break;
454 }
455
456 trace("AFTER:\n");
457 SetLastError(0xdeadbeef);
458 ret = GetWorldTransform(hdc, &xform);
459 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
460 {
461 ok(GetWindowOrgEx(hdc, &pt), "GetWindowOrgEx error %u\n", GetLastError());
462 trace("window org (%d,%d)\n", pt.x, pt.y);
463 ok(GetViewportOrgEx(hdc, &pt), "GetViewportOrgEx error %u\n", GetLastError());
464 trace("vport org (%d,%d)\n", pt.x, pt.y);
465 ok(GetWindowExtEx(hdc, &size), "GetWindowExtEx error %u\n", GetLastError());
466 trace("window ext (%d,%d)\n", size.cx, size.cy);
467 ok(GetViewportExtEx(hdc, &size), "GetViewportExtEx error %u\n", GetLastError());
468 trace("vport ext (%d,%d)\n", size.cx, size.cy);
469 }
470 else
471 {
472 ok(ret, "GetWorldTransform error %u\n", GetLastError());
473 trace("eM11 %f, eM22 %f, eDx %f, eDy %f\n", xform.eM11, xform.eM22, xform.eDx, xform.eDy);
474 }
475
476 return 1;
477 }
478
479 static void test_SaveDC(void)
480 {
481 HDC hdcMetafile, hdcDisplay;
482 HENHMETAFILE hMetafile;
483 HWND hwnd;
484 int ret;
485 POINT pt;
486 SIZE size;
487 HFONT hFont,hFont2,hFontOld,hFontCheck;
488 static const RECT rc = { 0, 0, 150, 150 };
489
490 /* Win9x doesn't play EMFs on invisible windows */
491 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
492 0, 0, 200, 200, 0, 0, 0, NULL);
493 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
494
495 hdcDisplay = GetDC(hwnd);
496 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
497
498 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
499 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
500
501 SetMapMode(hdcMetafile, MM_ANISOTROPIC);
502
503 /* Need to write something to the emf, otherwise Windows won't play it back */
504 LineTo(hdcMetafile, 150, 150);
505
506 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
507 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
508 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
509 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
510
511 /* Force Win9x to update DC state */
512 SetPixelV(hdcMetafile, 50, 50, 0);
513
514 ret = GetViewportOrgEx(hdcMetafile, &pt);
515 ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
516 ret = GetViewportExtEx(hdcMetafile, &size);
517 ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
518 ret = SaveDC(hdcMetafile);
519 ok(ret == 1, "ret = %d\n", ret);
520
521 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
522 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
523 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
524 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
525
526 /* Force Win9x to update DC state */
527 SetPixelV(hdcMetafile, 50, 50, 0);
528
529 ret = GetViewportOrgEx(hdcMetafile, &pt);
530 ok(pt.x == 10,"Expecting ViewportOrg x of 10, got %i\n",pt.x);
531 ret = GetViewportExtEx(hdcMetafile, &size);
532 ok(size.cx == 200,"Expecting ViewportExt cx of 200, got %i\n",size.cx);
533 ret = SaveDC(hdcMetafile);
534 ok(ret == 2, "ret = %d\n", ret);
535
536 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
537 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
538 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
539 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
540 SetPolyFillMode( hdcMetafile, ALTERNATE );
541 SetBkColor( hdcMetafile, 0 );
542
543 /* Force Win9x to update DC state */
544 SetPixelV(hdcMetafile, 50, 50, 0);
545
546 ret = GetViewportOrgEx(hdcMetafile, &pt);
547 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
548 ret = GetViewportExtEx(hdcMetafile, &size);
549 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
550 ret = SaveDC(hdcMetafile);
551 ok(ret == 3, "ret = %d\n", ret);
552
553 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
554 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
555 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
556 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
557
558 SetPolyFillMode( hdcMetafile, WINDING );
559 SetBkColor( hdcMetafile, 0x123456 );
560 ok( GetPolyFillMode( hdcMetafile ) == WINDING, "PolyFillMode not restored\n" );
561 ok( GetBkColor( hdcMetafile ) == 0x123456, "Background color not restored\n" );
562
563 /* Force Win9x to update DC state */
564 SetPixelV(hdcMetafile, 50, 50, 0);
565
566 ret = GetViewportOrgEx(hdcMetafile, &pt);
567 ok(pt.x == 30,"Expecting ViewportOrg x of 30, got %i\n",pt.x);
568 ret = GetViewportExtEx(hdcMetafile, &size);
569 ok(size.cx == 400,"Expecting ViewportExt cx of 400, got %i\n",size.cx);
570 ret = RestoreDC(hdcMetafile, -1);
571 ok(ret, "ret = %d\n", ret);
572
573 ret = GetViewportOrgEx(hdcMetafile, &pt);
574 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
575 ret = GetViewportExtEx(hdcMetafile, &size);
576 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
577 ok( GetPolyFillMode( hdcMetafile ) == ALTERNATE, "PolyFillMode not restored\n" );
578 ok( GetBkColor( hdcMetafile ) == 0, "Background color not restored\n" );
579 ret = SaveDC(hdcMetafile);
580 ok(ret == 3, "ret = %d\n", ret);
581
582 ret = GetViewportOrgEx(hdcMetafile, &pt);
583 ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x);
584 ret = GetViewportExtEx(hdcMetafile, &size);
585 ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx);
586 ret = RestoreDC(hdcMetafile, 1);
587 ok(ret, "ret = %d\n", ret);
588 ret = GetViewportOrgEx(hdcMetafile, &pt);
589 ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x);
590 ret = GetViewportExtEx(hdcMetafile, &size);
591 ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx);
592
593 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
594 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
595 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
596 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
597
598 /* Force Win9x to update DC state */
599 SetPixelV(hdcMetafile, 50, 50, 0);
600
601 ret = GetViewportOrgEx(hdcMetafile, &pt);
602 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
603 ret = GetViewportExtEx(hdcMetafile, &size);
604 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
605 ret = SaveDC(hdcMetafile);
606 ok(ret == 1, "ret = %d\n", ret);
607
608 ret = GetViewportOrgEx(hdcMetafile, &pt);
609 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
610 ret = GetViewportExtEx(hdcMetafile, &size);
611 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
612 ret = SaveDC(hdcMetafile);
613 ok(ret == 2, "ret = %d\n", ret);
614
615 memset(&orig_lf, 0, sizeof(orig_lf));
616 orig_lf.lfCharSet = ANSI_CHARSET;
617 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
618 orig_lf.lfWeight = FW_DONTCARE;
619 orig_lf.lfHeight = 7;
620 orig_lf.lfQuality = DEFAULT_QUALITY;
621 lstrcpyA(orig_lf.lfFaceName, "Arial");
622 hFont = CreateFontIndirectA(&orig_lf);
623 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
624
625 hFontOld = SelectObject(hdcMetafile, hFont);
626
627 hFont2 = CreateFontIndirectA(&orig_lf);
628 ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
629 hFontCheck = SelectObject(hdcMetafile, hFont2);
630 ok(hFontCheck == hFont, "Font not selected\n");
631
632 /* Force Win9x to update DC state */
633 SetPixelV(hdcMetafile, 50, 50, 0);
634
635 ret = RestoreDC(hdcMetafile, 1);
636 ok(ret, "ret = %d\n", ret);
637 ret = GetViewportOrgEx(hdcMetafile, &pt);
638 ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x);
639 ret = GetViewportExtEx(hdcMetafile, &size);
640 ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx);
641
642 hFontCheck = SelectObject(hdcMetafile, hFontOld);
643 ok(hFontOld == hFontCheck && hFontCheck != hFont && hFontCheck != hFont2,
644 "Font not reverted with DC Restore\n");
645
646 ret = RestoreDC(hdcMetafile, -20);
647 ok(!ret, "ret = %d\n", ret);
648 ret = RestoreDC(hdcMetafile, 20);
649 ok(!ret, "ret = %d\n", ret);
650
651 hMetafile = CloseEnhMetaFile(hdcMetafile);
652 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
653
654 ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc);
655 ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret);
656
657 ret = DeleteObject(hFont);
658 ok( ret, "DeleteObject error %d\n", GetLastError());
659 ret = DeleteObject(hFont2);
660 ok( ret, "DeleteObject error %d\n", GetLastError());
661 ret = DeleteEnhMetaFile(hMetafile);
662 ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
663 ret = ReleaseDC(hwnd, hdcDisplay);
664 ok( ret, "ReleaseDC error %d\n", GetLastError());
665 DestroyWindow(hwnd);
666 }
667
668 static void test_mf_SaveDC(void)
669 {
670 HDC hdcMetafile;
671 HMETAFILE hMetafile;
672 int ret;
673 POINT pt;
674 SIZE size;
675 HFONT hFont,hFont2,hFontOld,hFontCheck;
676
677 hdcMetafile = CreateMetaFileA(NULL);
678 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
679
680 ret = SetMapMode(hdcMetafile, MM_ANISOTROPIC);
681 ok (ret, "SetMapMode should not fail\n");
682
683 /* Need to write something to the emf, otherwise Windows won't play it back */
684 LineTo(hdcMetafile, 150, 150);
685
686 SetWindowOrgEx(hdcMetafile, 0, 0, NULL);
687 SetViewportOrgEx(hdcMetafile, 0, 0, NULL);
688 SetWindowExtEx(hdcMetafile, 110, 110, NULL );
689 SetViewportExtEx(hdcMetafile, 120, 120, NULL );
690
691 /* Force Win9x to update DC state */
692 SetPixelV(hdcMetafile, 50, 50, 0);
693
694 ret = GetViewportOrgEx(hdcMetafile, &pt);
695 todo_wine ok (!ret, "GetViewportOrgEx should fail\n");
696 ret = GetViewportExtEx(hdcMetafile, &size);
697 todo_wine ok (!ret, "GetViewportExtEx should fail\n");
698 ret = SaveDC(hdcMetafile);
699 ok(ret == 1, "ret = %d\n", ret);
700
701 SetWindowOrgEx(hdcMetafile, -1, -1, NULL);
702 SetViewportOrgEx(hdcMetafile, 10, 10, NULL);
703 SetWindowExtEx(hdcMetafile, 150, 150, NULL );
704 SetViewportExtEx(hdcMetafile, 200, 200, NULL );
705
706 /* Force Win9x to update DC state */
707 SetPixelV(hdcMetafile, 50, 50, 0);
708
709 ret = SaveDC(hdcMetafile);
710 ok(ret == 1, "ret = %d\n", ret);
711
712 SetWindowOrgEx(hdcMetafile, -2, -2, NULL);
713 SetViewportOrgEx(hdcMetafile, 20, 20, NULL);
714 SetWindowExtEx(hdcMetafile, 120, 120, NULL );
715 SetViewportExtEx(hdcMetafile, 300, 300, NULL );
716
717 /* Force Win9x to update DC state */
718 SetPixelV(hdcMetafile, 50, 50, 0);
719 SetPolyFillMode( hdcMetafile, ALTERNATE );
720 SetBkColor( hdcMetafile, 0 );
721
722 ret = SaveDC(hdcMetafile);
723 ok(ret == 1, "ret = %d\n", ret);
724
725 SetWindowOrgEx(hdcMetafile, -3, -3, NULL);
726 SetViewportOrgEx(hdcMetafile, 30, 30, NULL);
727 SetWindowExtEx(hdcMetafile, 200, 200, NULL );
728 SetViewportExtEx(hdcMetafile, 400, 400, NULL );
729
730 SetPolyFillMode( hdcMetafile, WINDING );
731 SetBkColor( hdcMetafile, 0x123456 );
732 todo_wine ok( !GetPolyFillMode( hdcMetafile ), "GetPolyFillMode succeeded\n" );
733 todo_wine ok( GetBkColor( hdcMetafile ) == CLR_INVALID, "GetBkColor succeeded\n" );
734
735 /* Force Win9x to update DC state */
736 SetPixelV(hdcMetafile, 50, 50, 0);
737
738 ret = RestoreDC(hdcMetafile, -1);
739 ok(ret, "ret = %d\n", ret);
740
741 ret = SaveDC(hdcMetafile);
742 ok(ret == 1, "ret = %d\n", ret);
743
744 ret = RestoreDC(hdcMetafile, 1);
745 ok(ret, "ret = %d\n", ret);
746
747 SetWindowOrgEx(hdcMetafile, -4, -4, NULL);
748 SetViewportOrgEx(hdcMetafile, 40, 40, NULL);
749 SetWindowExtEx(hdcMetafile, 500, 500, NULL );
750 SetViewportExtEx(hdcMetafile, 50, 50, NULL );
751
752 /* Force Win9x to update DC state */
753 SetPixelV(hdcMetafile, 50, 50, 0);
754
755 ret = SaveDC(hdcMetafile);
756 ok(ret == 1, "ret = %d\n", ret);
757
758 ret = SaveDC(hdcMetafile);
759 ok(ret == 1, "ret = %d\n", ret);
760
761 memset(&orig_lf, 0, sizeof(orig_lf));
762 orig_lf.lfCharSet = ANSI_CHARSET;
763 orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
764 orig_lf.lfWeight = FW_DONTCARE;
765 orig_lf.lfHeight = 7;
766 orig_lf.lfQuality = DEFAULT_QUALITY;
767 lstrcpyA(orig_lf.lfFaceName, "Arial");
768 hFont = CreateFontIndirectA(&orig_lf);
769 ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
770
771 hFontOld = SelectObject(hdcMetafile, hFont);
772
773 hFont2 = CreateFontIndirectA(&orig_lf);
774 ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError());
775 hFontCheck = SelectObject(hdcMetafile, hFont2);
776 ok(hFontCheck == hFont, "Font not selected\n");
777
778 /* Force Win9x to update DC state */
779 SetPixelV(hdcMetafile, 50, 50, 0);
780
781 ret = RestoreDC(hdcMetafile, 1);
782 ok(ret, "ret = %d\n", ret);
783
784 hFontCheck = SelectObject(hdcMetafile, hFontOld);
785 ok(hFontOld != hFontCheck && hFontCheck == hFont2, "Font incorrectly reverted with DC Restore\n");
786
787 /* restore level is ignored */
788 ret = RestoreDC(hdcMetafile, -20);
789 ok(ret, "ret = %d\n", ret);
790 ret = RestoreDC(hdcMetafile, 20);
791 ok(ret, "ret = %d\n", ret);
792 ret = RestoreDC(hdcMetafile, 0);
793 ok(ret, "ret = %d\n", ret);
794
795 hMetafile = CloseMetaFile(hdcMetafile);
796 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
797
798 ret = DeleteMetaFile(hMetafile);
799 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
800 ret = DeleteObject(hFont);
801 ok( ret, "DeleteObject error %d\n", GetLastError());
802 ret = DeleteObject(hFont2);
803 ok( ret, "DeleteObject error %d\n", GetLastError());
804 }
805
806
807 /* Win-format metafile (mfdrv) tests */
808 /* These tests compare the generated metafiles byte-by-byte */
809 /* with the nominal results. */
810
811 /* Maximum size of sample metafiles in bytes. */
812 #define MF_BUFSIZE 512
813
814 /* 8x8 bitmap data for a pattern brush */
815 static const unsigned char SAMPLE_PATTERN_BRUSH[] = {
816 0x01, 0x00, 0x02, 0x00,
817 0x03, 0x00, 0x04, 0x00,
818 0x05, 0x00, 0x06, 0x00,
819 0x07, 0x00, 0x08, 0x00
820 };
821
822 /* Sample metafiles to be compared to the outputs of the
823 * test functions.
824 */
825
826 static const unsigned char MF_BLANK_BITS[] = {
827 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0c, 0x00,
828 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
829 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
830 };
831
832 static const unsigned char MF_GRAPHICS_BITS[] = {
833 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x22, 0x00,
834 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
835 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x02,
836 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
837 0x13, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00,
838 0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x01, 0x00,
839 0x07, 0x00, 0x00, 0x00, 0x18, 0x04, 0x02, 0x00,
840 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
841 0x00, 0x00, 0x00, 0x00
842 };
843
844 static const unsigned char MF_PATTERN_BRUSH_BITS[] = {
845 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x3d, 0x00,
846 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
847 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x42, 0x01,
848 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
849 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
850 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
851 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
854 0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00,
855 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
856 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
857 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
858 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
859 0x2d, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
860 0x00, 0x00
861 };
862
863 static const unsigned char MF_TEXTOUT_ON_PATH_BITS[] =
864 {
865 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
866 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
867 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
868 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
869 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
870 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
871 0x00, 0x00
872 };
873
874 static const unsigned char EMF_TEXTOUT_ON_PATH_BITS[] =
875 {
876 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
877 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
878 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
879 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
880 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
881 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
882 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
883 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
884 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
885 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
886 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
888 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
889 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
890 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
891 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
892 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
893 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
894 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
895 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
896 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
897 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
898 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
899 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
900 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
901 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
902 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
903 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
904 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
905 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
906 0x14, 0x00, 0x00, 0x00
907 };
908
909 static const unsigned char MF_LINETO_BITS[] = {
910 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
911 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
912 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
913 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
914 0x00, 0x00
915 };
916
917 static const unsigned char EMF_LINETO_BITS[] = {
918 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
919 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
920 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
921 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
922 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
923 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
924 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
925 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
927 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
928 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
929 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
930 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
931 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
932 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
933 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
934 0x00, 0x03, 0x00, 0x00, 0x60, 0xe5, 0xf4, 0x73,
935 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
936 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
937 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
938 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
939 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
940 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
941 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
942 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
943 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
944 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
945 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
946 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
947 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
948 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
949 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
950 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
951 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
952 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
953 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
954 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
955 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
956 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
957 };
958
959 static const unsigned char EMF_LINETO_MM_ANISOTROPIC_BITS[] = {
960 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
961 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
962 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
963 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
964 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
965 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
966 0x38, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
967 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
968 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
969 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
970 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
971 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
972 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
973 0xe0, 0x93, 0x04, 0x00, 0x46, 0x00, 0x00, 0x00,
974 0x48, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
975 0x47, 0x44, 0x49, 0x43, 0x01, 0x00, 0x00, 0x80,
976 0x00, 0x03, 0x00, 0x00, 0xa4, 0xfe, 0xf4, 0x73,
977 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
978 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x11, 0x00,
979 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
980 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x02,
981 0x0f, 0x00, 0x37, 0x00, 0x03, 0x00, 0x00, 0x00,
982 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
983 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
984 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
985 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
986 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
987 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
988 0x36, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
989 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
990 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
991 0x07, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x00,
992 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
993 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
994 0x0f, 0x00, 0x00, 0x80, 0x4b, 0x00, 0x00, 0x00,
995 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
996 0x05, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
997 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
998 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
999 };
1000
1001 static const unsigned char EMF_LINETO_MM_TEXT_BITS[] = {
1002 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1004 0x37, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
1005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1006 0x61, 0x06, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00,
1007 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1008 0xe4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1009 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1010 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1011 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1012 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1013 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1014 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1015 0xe0, 0x93, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
1016 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
1017 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1018 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
1019 0x00, 0x04, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
1020 0x10, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
1021 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
1022 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80,
1023 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1024 0x00, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00,
1025 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80,
1026 0x4b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1027 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1028 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
1029 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1030 0x14, 0x00, 0x00, 0x00
1031 };
1032
1033 /* For debugging or dumping the raw metafiles produced by
1034 * new test functions.
1035 */
1036 static INT CALLBACK mf_enum_proc(HDC hdc, HANDLETABLE *ht, METARECORD *mr,
1037 INT nobj, LPARAM param)
1038 {
1039 trace("hdc %p, mr->rdFunction %04x, mr->rdSize %u, param %p\n",
1040 hdc, mr->rdFunction, mr->rdSize, (void *)param);
1041 return TRUE;
1042 }
1043
1044 /* For debugging or dumping the raw metafiles produced by
1045 * new test functions.
1046 */
1047
1048 static void dump_mf_bits (const HMETAFILE mf, const char *desc)
1049 {
1050 BYTE buf[MF_BUFSIZE];
1051 UINT mfsize, i;
1052
1053 if (!winetest_debug) return;
1054
1055 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
1056 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
1057
1058 printf ("MetaFile %s has bits:\n{\n ", desc);
1059 for (i=0; i<mfsize; i++)
1060 {
1061 printf ("0x%02x", buf[i]);
1062 if (i == mfsize-1)
1063 printf ("\n");
1064 else if (i % 8 == 7)
1065 printf (",\n ");
1066 else
1067 printf (", ");
1068 }
1069 printf ("};\n");
1070 }
1071
1072 /* Compare the metafile produced by a test function with the
1073 * expected raw metafile data in "bits".
1074 * Return value is 0 for a perfect match,
1075 * -1 if lengths aren't equal,
1076 * otherwise returns the number of non-matching bytes.
1077 */
1078
1079 static int compare_mf_bits (const HMETAFILE mf, const unsigned char *bits, UINT bsize,
1080 const char *desc)
1081 {
1082 unsigned char buf[MF_BUFSIZE];
1083 UINT mfsize, i;
1084 int diff;
1085
1086 mfsize = GetMetaFileBitsEx (mf, MF_BUFSIZE, buf);
1087 ok (mfsize > 0, "%s: GetMetaFileBitsEx failed.\n", desc);
1088 if (mfsize < MF_BUFSIZE)
1089 ok (mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n",
1090 desc, mfsize, bsize);
1091 else
1092 ok (bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d.\n",
1093 desc, mfsize, bsize);
1094 if (mfsize != bsize)
1095 return -1;
1096
1097 diff = 0;
1098 for (i=0; i<bsize; i++)
1099 {
1100 if (buf[i] != bits[i])
1101 diff++;
1102 }
1103 ok (diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1104 desc, mfsize, bsize, diff);
1105
1106 return diff;
1107 }
1108
1109 static int compare_mf_disk_bits(LPCSTR name, const BYTE *bits, UINT bsize, const char *desc)
1110 {
1111 unsigned char buf[MF_BUFSIZE];
1112 DWORD mfsize, rd_size, i;
1113 int diff;
1114 HANDLE hfile;
1115 BOOL ret;
1116
1117 hfile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1118 assert(hfile != INVALID_HANDLE_VALUE);
1119
1120 mfsize = GetFileSize(hfile, NULL);
1121 assert(mfsize <= MF_BUFSIZE);
1122
1123 ret = ReadFile(hfile, buf, sizeof(buf), &rd_size, NULL);
1124 ok( ret && rd_size == mfsize, "ReadFile: error %d\n", GetLastError());
1125
1126 CloseHandle(hfile);
1127
1128 ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d.\n", desc, mfsize, bsize);
1129
1130 if (mfsize != bsize)
1131 return -1;
1132
1133 diff = 0;
1134 for (i=0; i<bsize; i++)
1135 {
1136 if (buf[i] != bits[i])
1137 diff++;
1138 }
1139 ok(diff == 0, "%s: mfsize=%d, bsize=%d, diff=%d\n",
1140 desc, mfsize, bsize, diff);
1141
1142 return diff;
1143 }
1144
1145 /* For debugging or dumping the raw EMFs produced by
1146 * new test functions.
1147 */
1148 static void dump_emf_bits(const HENHMETAFILE mf, const char *desc)
1149 {
1150 BYTE buf[MF_BUFSIZE];
1151 UINT mfsize, i;
1152
1153 if (!winetest_debug) return;
1154
1155 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1156 ok (mfsize > 0, "%s: GetEnhMetaFileBits failed\n", desc);
1157
1158 printf("EMF %s has bits:\n{\n ", desc);
1159 for (i = 0; i < mfsize; i++)
1160 {
1161 printf ("0x%02x", buf[i]);
1162 if (i == mfsize-1)
1163 printf ("\n");
1164 else if (i % 8 == 7)
1165 printf (",\n ");
1166 else
1167 printf (", ");
1168 }
1169 printf ("};\n");
1170 }
1171
1172 static void dump_emf_records(const HENHMETAFILE mf, const char *desc)
1173 {
1174 BYTE *emf;
1175 BYTE buf[MF_BUFSIZE];
1176 UINT mfsize, offset;
1177
1178 if (!winetest_debug) return;
1179
1180 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1181 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1182
1183 printf("EMF %s has records:\n", desc);
1184
1185 emf = buf;
1186 offset = 0;
1187 while(offset < mfsize)
1188 {
1189 EMR *emr = (EMR *)(emf + offset);
1190 printf("emr->iType %d, emr->nSize %u\n", emr->iType, emr->nSize);
1191 /*trace("emr->iType 0x%04lx, emr->nSize 0x%04lx\n", emr->iType, emr->nSize);*/
1192 offset += emr->nSize;
1193 }
1194 }
1195
1196 static void dump_emf_record(const ENHMETARECORD *emr, const char *desc)
1197 {
1198 const BYTE *buf;
1199 DWORD i;
1200
1201 if (!winetest_debug) return;
1202
1203 printf ("%s: EMF record %u has bits:\n{\n", desc, emr->iType);
1204 buf = (const BYTE *)emr;
1205 for (i = 0; i < emr->nSize; i++)
1206 {
1207 printf ("0x%02x", buf[i]);
1208 if (i == emr->nSize - 1)
1209 printf ("\n");
1210 else if (i % 8 == 7)
1211 printf (",\n");
1212 else
1213 printf (", ");
1214 }
1215 printf ("};\n");
1216 }
1217
1218 static void dump_EMREXTTEXTOUT(const EMREXTTEXTOUTW *eto)
1219 {
1220 trace("rclBounds %d,%d - %d,%d\n", eto->rclBounds.left, eto->rclBounds.top,
1221 eto->rclBounds.right, eto->rclBounds.bottom);
1222 trace("iGraphicsMode %u\n", eto->iGraphicsMode);
1223 trace("exScale: %f\n", eto->exScale);
1224 trace("eyScale: %f\n", eto->eyScale);
1225 trace("emrtext.ptlReference %d,%d\n", eto->emrtext.ptlReference.x, eto->emrtext.ptlReference.y);
1226 trace("emrtext.nChars %u\n", eto->emrtext.nChars);
1227 trace("emrtext.offString %#x\n", eto->emrtext.offString);
1228 trace("emrtext.fOptions %#x\n", eto->emrtext.fOptions);
1229 trace("emrtext.rcl %d,%d - %d,%d\n", eto->emrtext.rcl.left, eto->emrtext.rcl.top,
1230 eto->emrtext.rcl.right, eto->emrtext.rcl.bottom);
1231 trace("emrtext.offDx %#x\n", eto->emrtext.offDx);
1232 }
1233
1234 static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2,
1235 const char *desc, BOOL ignore_scaling)
1236 {
1237 int diff;
1238
1239 ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n",
1240 desc, emr1->iType, emr2->iType);
1241
1242 ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n",
1243 desc, emr1->nSize, emr2->nSize);
1244
1245 /* iType and nSize mismatches are fatal */
1246 if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE;
1247
1248 /* contents of EMR_GDICOMMENT are not interesting */
1249 if (emr1->iType == EMR_GDICOMMENT) return TRUE;
1250
1251 /* different Windows versions setup DC scaling differently when
1252 * converting an old style metafile to an EMF.
1253 */
1254 if (ignore_scaling && (emr1->iType == EMR_SETWINDOWEXTEX ||
1255 emr1->iType == EMR_SETVIEWPORTEXTEX))
1256 return TRUE;
1257
1258 if (emr1->iType == EMR_EXTTEXTOUTW || emr1->iType == EMR_EXTTEXTOUTA)
1259 {
1260 EMREXTTEXTOUTW *eto1, *eto2;
1261
1262 eto1 = HeapAlloc(GetProcessHeap(), 0, emr1->nSize);
1263 memcpy(eto1, emr1, emr1->nSize);
1264 eto2 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1265 memcpy(eto2, emr2, emr2->nSize);
1266
1267 /* different Windows versions setup DC scaling differently */
1268 eto1->exScale = eto1->eyScale = 0.0;
1269 eto2->exScale = eto2->eyScale = 0.0;
1270
1271 diff = memcmp(eto1, eto2, emr1->nSize);
1272 if (diff)
1273 {
1274 dump_EMREXTTEXTOUT(eto1);
1275 dump_EMREXTTEXTOUT(eto2);
1276 }
1277 HeapFree(GetProcessHeap(), 0, eto1);
1278 HeapFree(GetProcessHeap(), 0, eto2);
1279 }
1280 else if (emr1->iType == EMR_EXTSELECTCLIPRGN && !lstrcmpA(desc, "emf_clipping"))
1281 {
1282 /* We have to take care of NT4 differences here */
1283 diff = memcmp(emr1, emr2, emr1->nSize);
1284 if (diff)
1285 {
1286 ENHMETARECORD *emr_nt4;
1287
1288 emr_nt4 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize);
1289 memcpy(emr_nt4, emr2, emr2->nSize);
1290 /* Correct the nRgnSize field */
1291 emr_nt4->dParm[5] = sizeof(RECT);
1292
1293 diff = memcmp(emr1, emr_nt4, emr1->nSize);
1294 if (!diff)
1295 win_skip("Catered for NT4 differences\n");
1296
1297 HeapFree(GetProcessHeap(), 0, emr_nt4);
1298 }
1299 }
1300 else
1301 diff = memcmp(emr1, emr2, emr1->nSize);
1302
1303 ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType);
1304
1305 if (diff)
1306 {
1307 dump_emf_record(emr1, "expected bits");
1308 dump_emf_record(emr2, "actual bits");
1309 }
1310
1311 return diff == 0; /* report all non-fatal record mismatches */
1312 }
1313
1314 /* Compare the EMF produced by a test function with the
1315 * expected raw EMF data in "bits".
1316 * Return value is 0 for a perfect match,
1317 * -1 if lengths aren't equal,
1318 * otherwise returns the number of non-matching bytes.
1319 */
1320 static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits,
1321 UINT bsize, const char *desc,
1322 BOOL ignore_scaling)
1323 {
1324 unsigned char buf[MF_BUFSIZE];
1325 UINT mfsize, offset1, offset2, diff_nt4, diff_9x;
1326 const ENHMETAHEADER *emh1, *emh2;
1327
1328 mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf);
1329 ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError());
1330
1331 /* ENHMETAHEADER size could differ, depending on platform */
1332 diff_nt4 = sizeof(SIZEL);
1333 diff_9x = sizeof(SIZEL) + 3 * sizeof(DWORD);
1334
1335 if (mfsize < MF_BUFSIZE)
1336 {
1337 ok(mfsize == bsize ||
1338 broken(mfsize == bsize - diff_nt4) || /* NT4 */
1339 broken(mfsize == bsize - diff_9x), /* Win9x/WinME */
1340 "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize);
1341 }
1342 else
1343 ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n",
1344 desc, mfsize, bsize);
1345
1346 /* basic things must match */
1347 emh1 = (const ENHMETAHEADER *)bits;
1348 emh2 = (const ENHMETAHEADER *)buf;
1349 ok(emh1->iType == EMR_HEADER, "expected EMR_HEADER, got %u\n", emh1->iType);
1350 ok(emh1->nSize == sizeof(ENHMETAHEADER), "expected sizeof(ENHMETAHEADER), got %u\n", emh1->nSize);
1351 ok(emh2->nBytes == mfsize, "expected emh->nBytes %u, got %u\n", mfsize, emh2->nBytes);
1352 ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature);
1353
1354 ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType);
1355 ok(emh1->nSize == emh2->nSize ||
1356 broken(emh1->nSize - diff_nt4 == emh2->nSize) ||
1357 broken(emh1->nSize - diff_9x == emh2->nSize),
1358 "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize);
1359 ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature);
1360 ok(emh1->nBytes == emh2->nBytes ||
1361 broken(emh1->nBytes - diff_nt4 == emh2->nBytes) ||
1362 broken(emh1->nBytes - diff_9x == emh2->nBytes),
1363 "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes);
1364 ok(emh1->nRecords == emh2->nRecords, "expected nRecords %u, got %u\n", emh1->nRecords, emh2->nRecords);
1365
1366 offset1 = emh1->nSize;
1367 offset2 = emh2->nSize; /* Needed for Win9x/WinME/NT4 */
1368 while (offset1 < emh1->nBytes)
1369 {
1370 const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset1);
1371 const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset2);
1372
1373 trace("%s: EMF record %u, size %u/record %u, size %u\n",
1374 desc, emr1->iType, emr1->nSize, emr2->iType, emr2->nSize);
1375
1376 if (!match_emf_record(emr1, emr2, desc, ignore_scaling)) return -1;
1377
1378 /* We have already bailed out if iType or nSize don't match */
1379 offset1 += emr1->nSize;
1380 offset2 += emr2->nSize;
1381 }
1382 return 0;
1383 }
1384
1385 /* Test a blank metafile. May be used as a template for new tests. */
1386
1387 static void test_mf_Blank(void)
1388 {
1389 HDC hdcMetafile;
1390 HMETAFILE hMetafile;
1391 INT caps;
1392 BOOL ret;
1393 INT type;
1394
1395 hdcMetafile = CreateMetaFileA(NULL);
1396 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1397 trace("hdcMetafile %p\n", hdcMetafile);
1398
1399 /* Tests on metafile initialization */
1400 caps = GetDeviceCaps (hdcMetafile, TECHNOLOGY);
1401 ok (caps == DT_METAFILE,
1402 "GetDeviceCaps: TECHNOLOGY=%d != DT_METAFILE.\n", caps);
1403
1404 hMetafile = CloseMetaFile(hdcMetafile);
1405 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1406 type = GetObjectType(hMetafile);
1407 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1408 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1409
1410 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1411 "mf_blank") != 0)
1412 {
1413 dump_mf_bits(hMetafile, "mf_Blank");
1414 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1415 }
1416
1417 ret = DeleteMetaFile(hMetafile);
1418 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1419 }
1420
1421 static void test_CopyMetaFile(void)
1422 {
1423 HDC hdcMetafile;
1424 HMETAFILE hMetafile, hmf_copy;
1425 BOOL ret;
1426 char temp_path[MAX_PATH];
1427 char mf_name[MAX_PATH];
1428 INT type;
1429
1430 hdcMetafile = CreateMetaFileA(NULL);
1431 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1432 trace("hdcMetafile %p\n", hdcMetafile);
1433
1434 hMetafile = CloseMetaFile(hdcMetafile);
1435 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1436 type = GetObjectType(hMetafile);
1437 ok(type == OBJ_METAFILE, "CloseMetaFile created object with type %d\n", type);
1438
1439 if (compare_mf_bits (hMetafile, MF_BLANK_BITS, sizeof(MF_BLANK_BITS),
1440 "mf_blank") != 0)
1441 {
1442 dump_mf_bits(hMetafile, "mf_Blank");
1443 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1444 }
1445
1446 GetTempPathA(MAX_PATH, temp_path);
1447 GetTempFileNameA(temp_path, "wmf", 0, mf_name);
1448
1449 hmf_copy = CopyMetaFileA(hMetafile, mf_name);
1450 ok(hmf_copy != 0, "CopyMetaFile error %d\n", GetLastError());
1451
1452 type = GetObjectType(hmf_copy);
1453 ok(type == OBJ_METAFILE, "CopyMetaFile created object with type %d\n", type);
1454
1455 ret = DeleteMetaFile(hMetafile);
1456 ok( ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1457
1458 if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0)
1459 {
1460 dump_mf_bits(hmf_copy, "mf_Blank");
1461 EnumMetaFile(0, hmf_copy, mf_enum_proc, 0);
1462 }
1463
1464 ret = DeleteMetaFile(hmf_copy);
1465 ok( ret, "DeleteMetaFile(%p) error %d\n", hmf_copy, GetLastError());
1466
1467 DeleteFileA(mf_name);
1468 }
1469
1470 static void test_SetMetaFileBits(void)
1471 {
1472 HMETAFILE hmf;
1473 INT type;
1474 BOOL ret;
1475 BYTE buf[256];
1476 METAHEADER *mh;
1477
1478 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS);
1479 trace("hmf %p\n", hmf);
1480 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1481 type = GetObjectType(hmf);
1482 ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type);
1483
1484 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1485 {
1486 dump_mf_bits(hmf, "mf_Graphics");
1487 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1488 }
1489
1490 ret = DeleteMetaFile(hmf);
1491 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1492
1493 /* NULL data crashes XP SP1 */
1494 /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/
1495
1496 /* Now with zero size */
1497 SetLastError(0xdeadbeef);
1498 hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS);
1499 trace("hmf %p\n", hmf);
1500 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1501 ok(GetLastError() == ERROR_INVALID_DATA ||
1502 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
1503 "wrong error %d\n", GetLastError());
1504
1505 /* Now with odd size */
1506 SetLastError(0xdeadbeef);
1507 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS);
1508 trace("hmf %p\n", hmf);
1509 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1510 ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError());
1511
1512 /* Now with zeroed out header fields */
1513 assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS));
1514 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1515 mh = (METAHEADER *)buf;
1516 /* corruption of any of the below fields leads to a failure */
1517 mh->mtType = 0;
1518 mh->mtVersion = 0;
1519 mh->mtHeaderSize = 0;
1520 SetLastError(0xdeadbeef);
1521 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1522 trace("hmf %p\n", hmf);
1523 ok(!hmf, "SetMetaFileBitsEx should fail\n");
1524 ok(GetLastError() == ERROR_INVALID_DATA ||
1525 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
1526 "wrong error %d\n", GetLastError());
1527
1528 /* Now with corrupted mtSize field */
1529 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1530 mh = (METAHEADER *)buf;
1531 /* corruption of mtSize doesn't lead to a failure */
1532 mh->mtSize *= 2;
1533 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1534 trace("hmf %p\n", hmf);
1535 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1536
1537 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1538 {
1539 dump_mf_bits(hmf, "mf_Graphics");
1540 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1541 }
1542
1543 ret = DeleteMetaFile(hmf);
1544 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1545
1546 /* Now with zeroed out mtSize field */
1547 memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS));
1548 mh = (METAHEADER *)buf;
1549 /* zeroing mtSize doesn't lead to a failure */
1550 mh->mtSize = 0;
1551 hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf);
1552 trace("hmf %p\n", hmf);
1553 ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError());
1554
1555 if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0)
1556 {
1557 dump_mf_bits(hmf, "mf_Graphics");
1558 EnumMetaFile(0, hmf, mf_enum_proc, 0);
1559 }
1560
1561 ret = DeleteMetaFile(hmf);
1562 ok(ret, "DeleteMetaFile(%p) error %d\n", hmf, GetLastError());
1563 }
1564
1565 /* Simple APIs from mfdrv/graphics.c
1566 */
1567
1568 static void test_mf_Graphics(void)
1569 {
1570 HDC hdcMetafile;
1571 HMETAFILE hMetafile;
1572 POINT oldpoint;
1573 BOOL ret;
1574
1575 hdcMetafile = CreateMetaFileA(NULL);
1576 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1577 trace("hdcMetafile %p\n", hdcMetafile);
1578
1579 ret = MoveToEx(hdcMetafile, 1, 1, NULL);
1580 ok( ret, "MoveToEx error %d.\n", GetLastError());
1581 ret = LineTo(hdcMetafile, 2, 2);
1582 ok( ret, "LineTo error %d.\n", GetLastError());
1583 ret = MoveToEx(hdcMetafile, 1, 1, &oldpoint);
1584 ok( ret, "MoveToEx error %d.\n", GetLastError());
1585
1586 /* oldpoint gets garbage under Win XP, so the following test would
1587 * work under Wine but fails under Windows:
1588 *
1589 * ok((oldpoint.x == 2) && (oldpoint.y == 2),
1590 * "MoveToEx: (x, y) = (%ld, %ld), should be (2, 2).\n",
1591 * oldpoint.x, oldpoint.y);
1592 */
1593
1594 ret = Ellipse(hdcMetafile, 0, 0, 2, 2);
1595 ok( ret, "Ellipse error %d.\n", GetLastError());
1596
1597 hMetafile = CloseMetaFile(hdcMetafile);
1598 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1599 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1600
1601 if (compare_mf_bits (hMetafile, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS),
1602 "mf_Graphics") != 0)
1603 {
1604 dump_mf_bits(hMetafile, "mf_Graphics");
1605 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1606 }
1607
1608 ret = DeleteMetaFile(hMetafile);
1609 ok( ret, "DeleteMetaFile(%p) error %d\n",
1610 hMetafile, GetLastError());
1611 }
1612
1613 static void test_mf_PatternBrush(void)
1614 {
1615 HDC hdcMetafile;
1616 HMETAFILE hMetafile;
1617 LOGBRUSH *orig_lb;
1618 HBRUSH hBrush;
1619 BOOL ret;
1620
1621 orig_lb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGBRUSH));
1622
1623 orig_lb->lbStyle = BS_PATTERN;
1624 orig_lb->lbColor = RGB(0, 0, 0);
1625 orig_lb->lbHatch = (ULONG_PTR)CreateBitmap (8, 8, 1, 1, SAMPLE_PATTERN_BRUSH);
1626 ok((HBITMAP)orig_lb->lbHatch != NULL, "CreateBitmap error %d.\n", GetLastError());
1627
1628 hBrush = CreateBrushIndirect (orig_lb);
1629 ok(hBrush != 0, "CreateBrushIndirect error %d\n", GetLastError());
1630
1631 hdcMetafile = CreateMetaFileA(NULL);
1632 ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError());
1633 trace("hdcMetafile %p\n", hdcMetafile);
1634
1635 hBrush = SelectObject(hdcMetafile, hBrush);
1636 ok(hBrush != 0, "SelectObject error %d.\n", GetLastError());
1637
1638 hMetafile = CloseMetaFile(hdcMetafile);
1639 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1640 ok(!GetObjectType(hdcMetafile), "CloseMetaFile has to destroy metafile hdc\n");
1641
1642 if (compare_mf_bits (hMetafile, MF_PATTERN_BRUSH_BITS, sizeof(MF_PATTERN_BRUSH_BITS),
1643 "mf_Pattern_Brush") != 0)
1644 {
1645 dump_mf_bits(hMetafile, "mf_Pattern_Brush");
1646 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1647 }
1648
1649 ret = DeleteMetaFile(hMetafile);
1650 ok( ret, "DeleteMetaFile error %d\n", GetLastError());
1651 ret = DeleteObject(hBrush);
1652 ok( ret, "DeleteObject(HBRUSH) error %d\n", GetLastError());
1653 ret = DeleteObject((HBITMAP)orig_lb->lbHatch);
1654 ok( ret, "DeleteObject(HBITMAP) error %d\n",
1655 GetLastError());
1656 HeapFree (GetProcessHeap(), 0, orig_lb);
1657 }
1658
1659 static void test_mf_ExtTextOut_on_path(void)
1660 {
1661 HDC hdcMetafile;
1662 HMETAFILE hMetafile;
1663 BOOL ret;
1664 static const INT dx[4] = { 3, 5, 8, 12 };
1665
1666 hdcMetafile = CreateMetaFileA(NULL);
1667 ok(hdcMetafile != 0, "CreateMetaFileA(NULL) error %d\n", GetLastError());
1668 trace("hdcMetafile %p\n", hdcMetafile);
1669
1670 ret = BeginPath(hdcMetafile);
1671 ok(!ret, "BeginPath on metafile DC should fail\n");
1672
1673 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1674 ok(ret, "ExtTextOut error %d\n", GetLastError());
1675
1676 ret = EndPath(hdcMetafile);
1677 ok(!ret, "EndPath on metafile DC should fail\n");
1678
1679 hMetafile = CloseMetaFile(hdcMetafile);
1680 ok(hMetafile != 0, "CloseMetaFile error %d\n", GetLastError());
1681
1682 if (compare_mf_bits(hMetafile, MF_TEXTOUT_ON_PATH_BITS, sizeof(MF_TEXTOUT_ON_PATH_BITS),
1683 "mf_TextOut_on_path") != 0)
1684 {
1685 dump_mf_bits(hMetafile, "mf_TextOut_on_path");
1686 EnumMetaFile(0, hMetafile, mf_enum_proc, 0);
1687 }
1688
1689 ret = DeleteMetaFile(hMetafile);
1690 ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
1691 }
1692
1693 static void test_emf_ExtTextOut_on_path(void)
1694 {
1695 HWND hwnd;
1696 HDC hdcDisplay, hdcMetafile;
1697 HENHMETAFILE hMetafile;
1698 BOOL ret;
1699 static const INT dx[4] = { 3, 5, 8, 12 };
1700
1701 /* Win9x doesn't play EMFs on invisible windows */
1702 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1703 0, 0, 200, 200, 0, 0, 0, NULL);
1704 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1705
1706 hdcDisplay = GetDC(hwnd);
1707 ok(hdcDisplay != 0, "GetDC error %d\n", GetLastError());
1708
1709 hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
1710 ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1711
1712 ret = BeginPath(hdcMetafile);
1713 ok(ret, "BeginPath error %d\n", GetLastError());
1714
1715 ret = ExtTextOutA(hdcMetafile, 11, 22, 0, NULL, "Test", 4, dx);
1716 ok(ret, "ExtTextOut error %d\n", GetLastError());
1717
1718 ret = EndPath(hdcMetafile);
1719 ok(ret, "EndPath error %d\n", GetLastError());
1720
1721 hMetafile = CloseEnhMetaFile(hdcMetafile);
1722 ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1723
1724 /* this doesn't succeed yet: EMF has correct size, all EMF records
1725 * are there, but their contents don't match for different reasons.
1726 */
1727 if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS),
1728 "emf_TextOut_on_path", FALSE) != 0)
1729 {
1730 dump_emf_bits(hMetafile, "emf_TextOut_on_path");
1731 dump_emf_records(hMetafile, "emf_TextOut_on_path");
1732 }
1733
1734 ret = DeleteEnhMetaFile(hMetafile);
1735 ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
1736 ret = ReleaseDC(hwnd, hdcDisplay);
1737 ok(ret, "ReleaseDC error %d\n", GetLastError());
1738 DestroyWindow(hwnd);
1739 }
1740
1741 static const unsigned char EMF_CLIPPING[] =
1742 {
1743 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
1744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1745 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1746 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1747 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
1748 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
1749 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1750 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1752 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1753 0x7c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
1754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1755 0x00, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x05, 0x00,
1756 0xe0, 0x93, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
1757 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1758 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
1759 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
1760 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1761 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1762 0x10, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1763 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1764 0x00, 0x04, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
1765 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1766 0x00, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
1767 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1768 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
1769 };
1770
1771 static void translate( POINT *pt, UINT count, const XFORM *xform )
1772 {
1773 while (count--)
1774 {
1775 FLOAT x = (FLOAT)pt->x;
1776 FLOAT y = (FLOAT)pt->y;
1777 pt->x = (LONG)floor( x * xform->eM11 + y * xform->eM21 + xform->eDx + 0.5 );
1778 pt->y = (LONG)floor( x * xform->eM12 + y * xform->eM22 + xform->eDy + 0.5 );
1779 pt++;
1780 }
1781 }
1782
1783 /* Compare rectangles allowing rounding errors */
1784 static BOOL is_equal_rect(const RECT *rc1, const RECT *rc2)
1785 {
1786 return abs(rc1->left - rc2->left) <= 1 &&
1787 abs(rc1->top - rc2->top) <= 1 &&
1788 abs(rc1->right - rc2->right) <= 1 &&
1789 abs(rc1->bottom - rc2->bottom) <= 1;
1790 }
1791
1792 static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
1793 const ENHMETARECORD *emr, int n_objs, LPARAM param)
1794 {
1795 if (emr->iType == EMR_EXTSELECTCLIPRGN)
1796 {
1797 const EMREXTSELECTCLIPRGN *clip = (const EMREXTSELECTCLIPRGN *)emr;
1798 union _rgn
1799 {
1800 RGNDATA data;
1801 char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
1802 };
1803 const union _rgn *rgn1;
1804 union _rgn rgn2;
1805 RECT rect, rc_transformed;
1806 const RECT *rc = (const RECT *)param;
1807 HRGN hrgn;
1808 XFORM xform;
1809 INT ret;
1810 BOOL is_win9x;
1811
1812 trace("EMR_EXTSELECTCLIPRGN: cbRgnData %#x, iMode %u\n",
1813 clip->cbRgnData, clip->iMode);
1814
1815 ok(clip->iMode == RGN_COPY, "expected RGN_COPY, got %u\n", clip->iMode);
1816 ok(clip->cbRgnData >= sizeof(RGNDATAHEADER) + sizeof(RECT),
1817 "too small data block: %u bytes\n", clip->cbRgnData);
1818 if (clip->cbRgnData < sizeof(RGNDATAHEADER) + sizeof(RECT))
1819 return 0;
1820
1821 rgn1 = (const union _rgn *)clip->RgnData;
1822
1823 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1824 rgn1->data.rdh.dwSize, rgn1->data.rdh.iType,
1825 rgn1->data.rdh.nCount, rgn1->data.rdh.nRgnSize,
1826 rgn1->data.rdh.rcBound.left, rgn1->data.rdh.rcBound.top,
1827 rgn1->data.rdh.rcBound.right, rgn1->data.rdh.rcBound.bottom);
1828
1829 ok(EqualRect(&rgn1->data.rdh.rcBound, rc), "rects don't match\n");
1830
1831 rect = *(const RECT *)rgn1->data.Buffer;
1832 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1833 ok(EqualRect(&rect, rc), "rects don't match\n");
1834
1835 ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize);
1836 ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType);
1837 ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount);
1838 ok(rgn1->data.rdh.nRgnSize == sizeof(RECT) ||
1839 broken(rgn1->data.rdh.nRgnSize == 168), /* NT4 */
1840 "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize);
1841
1842 hrgn = CreateRectRgn(0, 0, 0, 0);
1843
1844 memset(&xform, 0, sizeof(xform));
1845 SetLastError(0xdeadbeef);
1846 ret = GetWorldTransform(hdc, &xform);
1847 is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1848 if (!is_win9x)
1849 ok(ret, "GetWorldTransform error %u\n", GetLastError());
1850
1851 trace("xform.eM11 %f, xform.eM22 %f\n", xform.eM11, xform.eM22);
1852
1853 ret = GetClipRgn(hdc, hrgn);
1854 ok(ret == 0, "GetClipRgn returned %d, expected 0\n", ret);
1855
1856 PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs);
1857
1858 ret = GetClipRgn(hdc, hrgn);
1859 ok(ret == 1, "GetClipRgn returned %d, expected 1\n", ret);
1860
1861 /* Win9x returns empty clipping region */
1862 if (is_win9x) return 1;
1863
1864 ret = GetRegionData(hrgn, 0, NULL);
1865 ok(ret == sizeof(rgn2.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
1866
1867 ret = GetRegionData(hrgn, sizeof(rgn2), &rgn2.data);
1868
1869 trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
1870 rgn2.data.rdh.dwSize, rgn2.data.rdh.iType,
1871 rgn2.data.rdh.nCount, rgn2.data.rdh.nRgnSize,
1872 rgn2.data.rdh.rcBound.left, rgn2.data.rdh.rcBound.top,
1873 rgn2.data.rdh.rcBound.right, rgn2.data.rdh.rcBound.bottom);
1874
1875 rect = rgn2.data.rdh.rcBound;
1876 rc_transformed = *rc;
1877 translate((POINT *)&rc_transformed, 2, &xform);
1878 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1879 rc_transformed.right, rc_transformed.bottom);
1880 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
1881
1882 rect = *(const RECT *)rgn2.data.Buffer;
1883 trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom);
1884 rc_transformed = *rc;
1885 translate((POINT *)&rc_transformed, 2, &xform);
1886 trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top,
1887 rc_transformed.right, rc_transformed.bottom);
1888 ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n");
1889
1890 ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize);
1891 ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType);
1892 ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount);
1893 ok(rgn2.data.rdh.nRgnSize == sizeof(RECT) ||
1894 broken(rgn2.data.rdh.nRgnSize == 168), /* NT4 */
1895 "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize);
1896
1897 DeleteObject(hrgn);
1898 }
1899 return 1;
1900 }
1901
1902 static void test_emf_clipping(void)
1903 {
1904 static const RECT rc = { 0, 0, 100, 100 };
1905 RECT rc_clip = { 100, 100, 1024, 1024 };
1906 HWND hwnd;
1907 HDC hdc;
1908 HENHMETAFILE hemf;
1909 HRGN hrgn;
1910 INT ret;
1911 RECT rc_res, rc_sclip;
1912
1913 SetLastError(0xdeadbeef);
1914 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1915 ok(hdc != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
1916
1917 /* Need to write something to the emf, otherwise Windows won't play it back */
1918 LineTo(hdc, 1, 1);
1919
1920 hrgn = CreateRectRgn(rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
1921 ret = SelectClipRgn(hdc, hrgn);
1922 ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
1923
1924 SetLastError(0xdeadbeef);
1925 hemf = CloseEnhMetaFile(hdc);
1926 ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError());
1927
1928 if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING),
1929 "emf_clipping", FALSE) != 0)
1930 {
1931 dump_emf_bits(hemf, "emf_clipping");
1932 dump_emf_records(hemf, "emf_clipping");
1933 }
1934
1935 DeleteObject(hrgn);
1936
1937 /* Win9x doesn't play EMFs on invisible windows */
1938 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
1939 0, 0, 200, 200, 0, 0, 0, NULL);
1940 ok(hwnd != 0, "CreateWindowExA error %d\n", GetLastError());
1941
1942 hdc = GetDC(hwnd);
1943
1944 ret = EnumEnhMetaFile(hdc, hemf, clip_emf_enum_proc, &rc_clip, &rc);
1945 ok(ret, "EnumEnhMetaFile error %d\n", GetLastError());
1946
1947 DeleteEnhMetaFile(hemf);
1948 ReleaseDC(hwnd, hdc);
1949 DestroyWindow(hwnd);
1950
1951 hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1952
1953 SetRect(&rc_sclip, 100, 100, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1954 hrgn = CreateRectRgn(rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom);
1955 SelectClipRgn(hdc, hrgn);
1956 GetClipBox(hdc, &rc_res);
1957 todo_wine ok(EqualRect(&rc_res, &rc_sclip),
1958 "expected rc_res (%d, %d) - (%d, %d), got (%d, %d) - (%d, %d)\n",
1959 rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom,
1960 rc_res.left, rc_res.top, rc_res.right, rc_res.bottom);
1961
1962 hemf = CloseEnhMetaFile(hdc);
1963 DeleteEnhMetaFile(hemf);
1964 DeleteObject(hrgn);
1965 DeleteDC(hdc);
1966 }
1967
1968 static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData)
1969 {
1970 LPMETAFILEPICT lpMFP = (LPMETAFILEPICT)lpData;
1971 POINT mapping[2] = { { 0, 0 }, { 10, 10 } };
1972 /* When using MM_TEXT Win9x does not update the mapping mode
1973 * until a record is played which actually outputs something */
1974 PlayEnhMetaFileRecord(hdc, lpHTable, lpEMFR, nObj);
1975 LPtoDP(hdc, mapping, 2);
1976 trace("EMF record: iType %d, nSize %d, (%d,%d)-(%d,%d)\n",
1977 lpEMFR->iType, lpEMFR->nSize,
1978 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y);
1979
1980 if (lpEMFR->iType == EMR_LINETO)
1981 {
1982 INT x0, y0, x1, y1;
1983 if (!lpMFP || lpMFP->mm == MM_TEXT)
1984 {
1985 x0 = 0;
1986 y0 = 0;
1987 x1 = (INT)floor(10 * 100.0 / LINE_X + 0.5);
1988 y1 = (INT)floor(10 * 100.0 / LINE_Y + 0.5);
1989 }
1990 else
1991 {
1992 ok(lpMFP->mm == MM_ANISOTROPIC, "mm=%d\n", lpMFP->mm);
1993
1994 x0 = MulDiv(0, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1995 y0 = MulDiv(0, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1996 x1 = MulDiv(10, GetDeviceCaps(hdc, HORZSIZE) * 100, GetDeviceCaps(hdc, HORZRES));
1997 y1 = MulDiv(10, GetDeviceCaps(hdc, VERTSIZE) * 100, GetDeviceCaps(hdc, VERTRES));
1998 }
1999 ok(mapping[0].x == x0 && mapping[0].y == y0 && mapping[1].x == x1 && mapping[1].y == y1,
2000 "(%d,%d)->(%d,%d), expected (%d,%d)->(%d,%d)\n",
2001 mapping[0].x, mapping[0].y, mapping[1].x, mapping[1].y,
2002 x0, y0, x1, y1);
2003 }
2004 return TRUE;
2005 }
2006
2007 static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp)
2008 {
2009 HDC hdcMf;
2010 HMETAFILE hmf;
2011 HENHMETAFILE hemf;
2012 BOOL ret;
2013 UINT size;
2014 LPBYTE pBits;
2015
2016 hdcMf = CreateMetaFile(NULL);
2017 ok(hdcMf != NULL, "CreateMetaFile failed with error %d\n", GetLastError());
2018 ret = LineTo(hdcMf, (INT)LINE_X, (INT)LINE_Y);
2019 ok(ret, "LineTo failed with error %d\n", GetLastError());
2020 hmf = CloseMetaFile(hdcMf);
2021 ok(hmf != NULL, "CloseMetaFile failed with error %d\n", GetLastError());
2022
2023 if (compare_mf_bits (hmf, MF_LINETO_BITS, sizeof(MF_LINETO_BITS), "mf_LineTo") != 0)
2024 {
2025 dump_mf_bits(hmf, "mf_LineTo");
2026 EnumMetaFile(0, hmf, mf_enum_proc, 0);
2027 }
2028
2029 size = GetMetaFileBitsEx(hmf, 0, NULL);
2030 ok(size, "GetMetaFileBitsEx failed with error %d\n", GetLastError());
2031 pBits = HeapAlloc(GetProcessHeap(), 0, size);
2032 GetMetaFileBitsEx(hmf, size, pBits);
2033 DeleteMetaFile(hmf);
2034 hemf = SetWinMetaFileBits(size, pBits, NULL, mfp);
2035 HeapFree(GetProcessHeap(), 0, pBits);
2036 return hemf;
2037 }
2038
2039 static void test_mf_conversions(void)
2040 {
2041 trace("Testing MF->EMF conversion (MM_ANISOTROPIC)\n");
2042 {
2043 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2044 HENHMETAFILE hemf;
2045 METAFILEPICT mfp;
2046 RECT rect = { 0, 0, 100, 100 };
2047 mfp.mm = MM_ANISOTROPIC;
2048 mfp.xExt = 100;
2049 mfp.yExt = 100;
2050 mfp.hMF = NULL;
2051 hemf = create_converted_emf(&mfp);
2052
2053 if (compare_emf_bits(hemf, EMF_LINETO_MM_ANISOTROPIC_BITS, sizeof(EMF_LINETO_MM_ANISOTROPIC_BITS),
2054 "emf_LineTo MM_ANISOTROPIC", TRUE) != 0)
2055 {
2056 dump_emf_bits(hemf, "emf_LineTo MM_ANISOTROPIC");
2057 dump_emf_records(hemf, "emf_LineTo MM_ANISOTROPIC");
2058 }
2059
2060 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
2061
2062 DeleteEnhMetaFile(hemf);
2063 DeleteDC(hdcOffscreen);
2064 }
2065
2066 trace("Testing MF->EMF conversion (MM_TEXT)\n");
2067 {
2068 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2069 HENHMETAFILE hemf;
2070 METAFILEPICT mfp;
2071 RECT rect = { 0, 0, 100, 100 };
2072 mfp.mm = MM_TEXT;
2073 mfp.xExt = 0;
2074 mfp.yExt = 0;
2075 mfp.hMF = NULL;
2076 hemf = create_converted_emf(&mfp);
2077
2078 if (compare_emf_bits(hemf, EMF_LINETO_MM_TEXT_BITS, sizeof(EMF_LINETO_MM_TEXT_BITS),
2079 "emf_LineTo MM_TEXT", TRUE) != 0)
2080 {
2081 dump_emf_bits(hemf, "emf_LineTo MM_TEXT");
2082 dump_emf_records(hemf, "emf_LineTo MM_TEXT");
2083 }
2084
2085 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, &mfp, &rect);
2086
2087 DeleteEnhMetaFile(hemf);
2088 DeleteDC(hdcOffscreen);
2089 }
2090
2091 trace("Testing MF->EMF conversion (NULL mfp)\n");
2092 {
2093 HDC hdcOffscreen = CreateCompatibleDC(NULL);
2094 HENHMETAFILE hemf;
2095 RECT rect = { 0, 0, 100, 100 };
2096 hemf = create_converted_emf(NULL);
2097
2098 if (compare_emf_bits(hemf, EMF_LINETO_BITS, sizeof(EMF_LINETO_BITS),
2099 "emf_LineTo NULL", TRUE) != 0)
2100 {
2101 dump_emf_bits(hemf, "emf_LineTo NULL");
2102 dump_emf_records(hemf, "emf_LineTo NULL");
2103 }
2104
2105 EnumEnhMetaFile(hdcOffscreen, hemf, EmfEnumProc, NULL, &rect);
2106
2107 DeleteEnhMetaFile(hemf);
2108 DeleteDC(hdcOffscreen);
2109 }
2110 }
2111
2112 static BOOL getConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
2113 LONG mm, LONG xExt, LONG yExt,
2114 RECTL * rclBounds, RECTL * rclFrame)
2115 {
2116 METAFILEPICT mfp;
2117 METAFILEPICT * mfpPtr = NULL;
2118 HENHMETAFILE emf;
2119 ENHMETAHEADER header;
2120 UINT res;
2121
2122 if (!mfpIsNull)
2123 {
2124 mfp.mm = mm;
2125 mfp.xExt = xExt;
2126 mfp.yExt = yExt;
2127 mfpPtr = &mfp;
2128 }
2129
2130 emf = SetWinMetaFileBits(buffer_size, buffer, NULL, mfpPtr);
2131 ok(emf != NULL, "SetWinMetaFileBits failed\n");
2132 if (!emf) return FALSE;
2133 res = GetEnhMetaFileHeader(emf, sizeof(header), &header);
2134 ok(res != 0, "GetEnhMetaHeader failed\n");
2135 DeleteEnhMetaFile(emf);
2136 if (!res) return FALSE;
2137
2138 *rclBounds = header.rclBounds;
2139 *rclFrame = header.rclFrame;
2140 return TRUE;
2141 }
2142
2143 static void checkConvertedFrameAndBounds(UINT buffer_size, BYTE * buffer, BOOL mfpIsNull,
2144 LONG mm, LONG xExt, LONG yExt,
2145 RECTL * rclBoundsExpected, RECTL * rclFrameExpected)
2146 {
2147 RECTL rclBounds, rclFrame;
2148
2149 if (getConvertedFrameAndBounds(buffer_size, buffer, mfpIsNull, mm, xExt, yExt, &rclBounds, &rclFrame))
2150 {
2151 const char * msg;
2152 char buf[64];
2153
2154 if (mfpIsNull)
2155 {
2156 msg = "mfp == NULL";
2157 }
2158 else
2159 {
2160 const char * mm_str;
2161 switch (mm)
2162 {
2163 case MM_ANISOTROPIC: mm_str = "MM_ANISOTROPIC"; break;
2164 case MM_ISOTROPIC: mm_str = "MM_ISOTROPIC"; break;
2165 default: mm_str = "Unexpected";
2166 }
2167 sprintf(buf, "mm=%s, xExt=%d, yExt=%d", mm_str, xExt, yExt);
2168 msg = buf;
2169 }
2170
2171 ok(rclBounds.left == rclBoundsExpected->left, "rclBounds.left: Expected %d, got %d (%s)\n", rclBoundsExpected->left, rclBounds.left, msg);
2172 ok(rclBounds.top == rclBoundsExpected->top, "rclBounds.top: Expected %d, got %d (%s)\n", rclBoundsExpected->top, rclBounds.top, msg);
2173 ok(rclBounds.right == rclBoundsExpected->right, "rclBounds.right: Expected %d, got %d (%s)\n", rclBoundsExpected->right, rclBounds.right, msg);
2174 ok(rclBounds.bottom == rclBoundsExpected->bottom, "rclBounds.bottom: Expected %d, got %d (%s)\n", rclBoundsExpected->bottom, rclBounds.bottom, msg);
2175 ok(rclFrame.left == rclFrameExpected->left, "rclFrame.left: Expected %d, got %d (%s)\n", rclFrameExpected->left, rclFrame.left, msg);
2176 ok(rclFrame.top == rclFrameExpected->top, "rclFrame.top: Expected %d, got %d (%s)\n", rclFrameExpected->top, rclFrame.top, msg);
2177 ok(rclFrame.right == rclFrameExpected->right, "rclFrame.right: Expected %d, got %d (%s)\n", rclFrameExpected->right, rclFrame.right, msg);
2178 ok(rclFrame.bottom == rclFrameExpected->bottom, "rclFrame.bottom: Expected %d, got %d (%s)\n", rclFrameExpected->bottom, rclFrame.bottom, msg);
2179 }
2180 }
2181
2182 static void test_SetWinMetaFileBits(void)
2183 {
2184 HMETAFILE wmf;
2185 HDC wmfDC;
2186 BYTE * buffer;
2187 UINT buffer_size;
2188 RECT rect;
2189 UINT res;
2190 RECTL rclBoundsAnisotropic, rclFrameAnisotropic;
2191 RECTL rclBoundsIsotropic, rclFrameIsotropic;
2192 RECTL rclBounds, rclFrame;
2193 HDC dc;
2194 LONG diffx, diffy;
2195
2196 wmfDC = CreateMetaFile(NULL);
2197 ok(wmfDC != NULL, "CreateMetaFile failed\n");
2198 if (!wmfDC) return;
2199
2200 SetWindowExtEx(wmfDC, 100, 100, NULL);
2201 rect.left = rect.top = 0;
2202 rect.right = rect.bottom = 50;
2203 FillRect(wmfDC, &rect, GetStockObject(BLACK_BRUSH));
2204 wmf = CloseMetaFile(wmfDC);
2205 ok(wmf != NULL, "Metafile creation failed\n");
2206 if (!wmf) return;
2207
2208 buffer_size = GetMetaFileBitsEx(wmf, 0, NULL);
2209 ok(buffer_size != 0, "GetMetaFileBitsEx failed\n");
2210 if (buffer_size == 0)
2211 {
2212 DeleteMetaFile(wmf);
2213 return;
2214 }
2215
2216 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
2217 ok(buffer != NULL, "HeapAlloc failed\n");
2218 if (!buffer)
2219 {
2220 DeleteMetaFile(wmf);
2221 return;
2222 }
2223
2224 res = GetMetaFileBitsEx(wmf, buffer_size, buffer);
2225 ok(res == buffer_size, "GetMetaFileBitsEx failed\n");
2226 DeleteMetaFile(wmf);
2227 if (res != buffer_size)
2228 {
2229 HeapFree(GetProcessHeap(), 0, buffer);
2230 return;
2231 }
2232
2233 /* Get the reference bounds and frame */
2234 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2235 getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2236
2237 ok(rclBoundsAnisotropic.left == 0 && rclBoundsAnisotropic.top == 0 &&
2238 rclBoundsIsotropic.left == 0 && rclBoundsIsotropic.top == 0,
2239 "SetWinMetaFileBits: Reference bounds: Left and top bound must be zero\n");
2240
2241 ok(rclBoundsAnisotropic.right >= rclBoundsIsotropic.right, "SetWinMetaFileBits: Reference bounds: Invalid right bound\n");
2242 ok(rclBoundsAnisotropic.bottom >= rclBoundsIsotropic.bottom, "SetWinMetaFileBits: Reference bounds: Invalid bottom bound\n");
2243 diffx = rclBoundsIsotropic.right - rclBoundsIsotropic.bottom;
2244 if (diffx < 0) diffx = -diffx;
2245 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n");
2246
2247 dc = CreateCompatibleDC(NULL);
2248
2249 /* Allow 1 mm difference (rounding errors) */
2250 diffx = rclBoundsAnisotropic.right - GetDeviceCaps(dc, HORZRES) / 2;
2251 diffy = rclBoundsAnisotropic.bottom - GetDeviceCaps(dc, VERTRES) / 2;
2252 if (diffx < 0) diffx = -diffx;
2253 if (diffy < 0) diffy = -diffy;
2254 todo_wine
2255 {
2256 ok(diffx <= 1 && diffy <= 1,
2257 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2258 GetDeviceCaps(dc, HORZRES) / 2, GetDeviceCaps(dc, VERTRES) / 2, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom);
2259 }
2260
2261 /* Allow 1 mm difference (rounding errors) */
2262 diffx = rclFrameAnisotropic.right / 100 - GetDeviceCaps(dc, HORZSIZE) / 2;
2263 diffy = rclFrameAnisotropic.bottom / 100 - GetDeviceCaps(dc, VERTSIZE) / 2;
2264 if (diffx < 0) diffx = -diffx;
2265 if (diffy < 0) diffy = -diffy;
2266 todo_wine
2267 {
2268 ok(diffx <= 1 && diffy <= 1,
2269 "SetWinMetaFileBits (MM_ANISOTROPIC): Reference frame: The whole device surface must be used (%dx%d), but got (%dx%d)\n",
2270 GetDeviceCaps(dc, HORZSIZE) / 2, GetDeviceCaps(dc, VERTSIZE) / 2, rclFrameAnisotropic.right / 100, rclFrameAnisotropic.bottom / 100);
2271 }
2272 DeleteDC(dc);
2273
2274 /* If the METAFILEPICT pointer is NULL, the MM_ANISOTROPIC mapping mode and the whole device surface are used */
2275 checkConvertedFrameAndBounds(buffer_size, buffer, TRUE, 0, 0, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2276
2277 /* If xExt or yExt is zero or negative, the whole device surface is used */
2278 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2279 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2280 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2281 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2282 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 0, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2283 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 0, &rclBoundsIsotropic, &rclFrameIsotropic);
2284 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 0, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2285 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 0, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2286 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -10000, 10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2287 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -10000, 10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2288 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 10000, -10000, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2289 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 10000, -10000, &rclBoundsIsotropic, &rclFrameIsotropic);
2290
2291 /* MSDN says that negative xExt and yExt values specify a ratio.
2292 Check that this is wrong and the whole device surface is used */
2293 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, -1000, -100, &rclBoundsAnisotropic, &rclFrameAnisotropic);
2294 checkConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, -1000, -100, &rclBoundsIsotropic, &rclFrameIsotropic);
2295
2296 /* Ordinary conversions */
2297
2298 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ANISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2299 {
2300 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2301 "SetWinMetaFileBits (MM_ANISOTROPIC): rclFrame contains invalid values\n");
2302 ok(rclBounds.left == 0 && rclBounds.top == 0 && rclBounds.right > rclBounds.bottom,
2303 "SetWinMetaFileBits (MM_ANISOTROPIC): rclBounds contains invalid values\n");
2304 }
2305
2306 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_ISOTROPIC, 30000, 20000, &rclBounds, &rclFrame))
2307 {
2308 ok(rclFrame.left == 0 && rclFrame.top == 0 && rclFrame.right == 30000 && rclFrame.bottom == 20000,
2309 "SetWinMetaFileBits (MM_ISOTROPIC): rclFrame contains invalid values\n");
2310 ok(rclBounds.left == 0 && rclBounds.top == 0,
2311 "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds contains invalid values\n");
2312
2313 /* Wine has a rounding error */
2314 diffx = rclBounds.right - rclBounds.bottom;
2315 if (diffx < 0) diffx = -diffx;
2316 ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): rclBounds is not isotropic\n");
2317 }
2318
2319 if (getConvertedFrameAndBounds(buffer_size, buffer, FALSE, MM_HIMETRIC, 30000, 20000, &rclBounds, &rclFrame))
2320 {
2321 ok(rclFrame.right - rclFrame.left != 30000 && rclFrame.bottom - rclFrame.top != 20000,
2322 "SetWinMetaFileBits: xExt and yExt must be ignored for mapping modes other than MM_ANISOTROPIC and MM_ISOTROPIC\n");
2323 }
2324
2325 HeapFree(GetProcessHeap(), 0, buffer);
2326 }
2327
2328 static BOOL near_match(int x, int y)
2329 {
2330 int epsilon = min(abs(x), abs(y));
2331
2332 epsilon = max(epsilon/100, 2);
2333
2334 if(x < y - epsilon || x > y + epsilon) return FALSE;
2335 return TRUE;
2336 }
2337
2338 static void getwinmetafilebits(UINT mode, int scale, RECT *rc)
2339 {
2340 HENHMETAFILE emf;
2341 HDC display_dc, emf_dc;
2342 ENHMETAHEADER *enh_header;
2343 UINT size, emf_size, i;
2344 WORD check = 0;
2345 DWORD rec_num = 0;
2346 METAHEADER *mh = NULL;
2347 METARECORD *rec;
2348 INT horz_res, vert_res, horz_size, vert_size;
2349
2350 display_dc = GetDC(NULL);
2351 ok(display_dc != NULL, "display_dc is NULL\n");
2352
2353 horz_res = GetDeviceCaps(display_dc, HORZRES);
2354 vert_res = GetDeviceCaps(display_dc, VERTRES);
2355 horz_size = GetDeviceCaps(display_dc, HORZSIZE);
2356 vert_size = GetDeviceCaps(display_dc, VERTSIZE);
2357
2358 emf_dc = CreateEnhMetaFileA(display_dc, NULL, rc, NULL);
2359 ok(emf_dc != NULL, "emf_dc is NULL\n");
2360 for(i = 0; i < 3000; i++) /* This is enough to take emf_size > 0xffff */
2361 Rectangle(emf_dc, 0, 0, 1000, 20);
2362 emf = CloseEnhMetaFile(emf_dc);
2363 ok(emf != NULL, "emf is NULL\n");
2364
2365 emf_size = GetEnhMetaFileBits(emf, 0, NULL);
2366 enh_header = HeapAlloc(GetProcessHeap(), 0, emf_size);
2367 emf_size = GetEnhMetaFileBits(emf, emf_size, (BYTE*)enh_header);
2368 DeleteEnhMetaFile(emf);
2369 /* multiply szlDevice.cx by scale, when scale != 1 the recording and playback dcs
2370 have different resolutions */
2371 enh_header->szlDevice.cx *= scale;
2372 emf = SetEnhMetaFileBits(emf_size, (BYTE*)enh_header);
2373 ok(emf != NULL, "emf is NULL\n");
2374 ok(EqualRect((RECT*)&enh_header->rclFrame, rc), "Frame rectangles differ\n");
2375
2376 size = GetWinMetaFileBits(emf, 0, NULL, mode, display_dc);
2377 ok(size ||
2378 broken(size == 0), /* some versions of winxp fail for some reason */
2379 "GetWinMetaFileBits returns 0\n");
2380 if(!size) goto end;
2381 mh = HeapAlloc(GetProcessHeap(), 0, size);
2382 GetWinMetaFileBits(emf, size, (BYTE*)mh, mode, display_dc);
2383
2384 for(i = 0; i < size / 2; i++) check += ((WORD*)mh)[i];
2385 ok(check == 0, "check %04x\n", check);
2386
2387 rec = (METARECORD*)(mh + 1);
2388
2389 while(rec->rdSize && rec->rdFunction)
2390 {
2391 const DWORD chunk_size = 0x2000;
2392 DWORD mfcomment_chunks = (emf_size + chunk_size - 1) / chunk_size;
2393
2394 if(rec_num < mfcomment_chunks)
2395 {
2396 DWORD this_chunk_size = chunk_size;
2397
2398 if(rec_num == mfcomment_chunks - 1)
2399 this_chunk_size = emf_size - rec_num * chunk_size;
2400
2401 ok(rec->rdSize == (this_chunk_size + 44) / 2, "%04x: got %04x expected %04x\n", rec_num, rec->rdSize, (this_chunk_size + 44) / 2);
2402 ok(rec->rdFunction == META_ESCAPE, "%04x: got %04x\n", rec_num, rec->rdFunction);
2403 if(rec->rdSize < (this_chunk_size + 44) / 2) break;
2404 ok(rec->rdParm[0] == MFCOMMENT, "got %04x\n", rec->rdParm[0]);
2405 ok(rec->rdParm[1] == this_chunk_size + 34, "got %04x %x\n", rec->rdParm[1], emf_size + 34);
2406 ok(rec->rdParm[2] == 0x4d57, "got %04x\n", rec->rdParm[2]); /* WMFC */
2407 ok(rec->rdParm[3] == 0x4346, "got %04x\n", rec->rdParm[3]); /* " */
2408 ok(rec->rdParm[4] == 1, "got %04x\n", rec->rdParm[4]);
2409 ok(rec->rdParm[5] == 0, "got %04x\n", rec->rdParm[5]);
2410 ok(rec->rdParm[6] == 0, "got %04x\n", rec->rdParm[6]);
2411 ok(rec->rdParm[7] == 1, "got %04x\n", rec->rdParm[7]);
2412 /* parm[8] is the checksum, tested above */
2413 if(rec_num > 0) ok(rec->rdParm[8] == 0, "got %04x\n", rec->rdParm[8]);
2414 ok(rec->rdParm[9] == 0, "got %04x\n", rec->rdParm[9]);
2415 ok(rec->rdParm[10] == 0, "got %04x\n", rec->rdParm[10]);
2416 ok(rec->rdParm[11] == mfcomment_chunks, "got %04x\n", rec->rdParm[11]); /* num chunks */
2417 ok(rec->rdParm[12] == 0, "got %04x\n", rec->rdParm[12]);
2418 ok(rec->rdParm[13] == this_chunk_size, "got %04x expected %04x\n", rec->rdParm[13], this_chunk_size);
2419 ok(rec->rdParm[14] == 0, "got %04x\n", rec->rdParm[14]);
2420 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 */
2421 ok(*(DWORD*)(rec->rdParm + 17) == emf_size, "got %08x emf_size %08x\n", *(DWORD*)(rec->rdParm + 17), emf_size);
2422 ok(!memcmp(rec->rdParm + 19, (char*)enh_header + rec_num * chunk_size, this_chunk_size), "bits mismatch\n");
2423 }
2424
2425 else if(rec_num == mfcomment_chunks)
2426 {
2427 ok(rec->rdFunction == META_SETMAPMODE, "got %04x\n", rec->rdFunction);
2428 ok(rec->rdParm[0] == mode, "got %04x\n", rec->rdParm[0]);
2429 }
2430 else if(rec_num == mfcomment_chunks + 1)
2431 {
2432 POINT pt;
2433 ok(rec->rdFunction == META_SETWINDOWORG, "got %04x\n", rec->rdFunction);
2434 switch(mode)
2435 {
2436 case MM_TEXT:
2437 case MM_ISOTROPIC:
2438 case MM_ANISOTROPIC:
2439 pt.y = MulDiv(rc->top, vert_res, vert_size * 100) + 1;
2440 pt.x = MulDiv(rc->left, horz_res, horz_size * 100);
2441 break;
2442 case MM_LOMETRIC:
2443 pt.y = MulDiv(-rc->top, 1, 10) + 1;
2444 pt.x = MulDiv( rc->left, 1, 10);
2445 break;
2446 case MM_HIMETRIC:
2447 pt.y = -rc->top + 1;
2448 pt.x = (rc->left >= 0) ? rc->left : rc->left + 1; /* strange but true */
2449 break;
2450 case MM_LOENGLISH:
2451 pt.y = MulDiv(-rc->top, 10, 254) + 1;
2452 pt.x = MulDiv( rc->left, 10, 254);
2453 break;
2454 case MM_HIENGLISH:
2455 pt.y = MulDiv(-rc->top, 100, 254) + 1;
2456 pt.x = MulDiv( rc->left, 100, 254);
2457 break;
2458 case MM_TWIPS:
2459 pt.y = MulDiv(-rc->top, 72 * 20, 2540) + 1;
2460 pt.x = MulDiv( rc->left, 72 * 20, 2540);
2461 break;
2462 default:
2463 pt.x = pt.y = 0;
2464 }
2465 ok(near_match((short)rec->rdParm[0], pt.y), "got %d expect %d\n", (short)rec->rdParm[0], pt.y);
2466 ok(near_match((short)rec->rdParm[1], pt.x), "got %d expect %d\n", (short)rec->rdParm[1], pt.x);
2467 }
2468 if(rec_num == mfcomment_chunks + 2)
2469 {
2470 ok(rec->rdFunction == META_SETWINDOWEXT, "got %04x\n", rec->rdFunction);
2471 ok(near_match((short)rec->rdParm[0], MulDiv(rc->bottom - rc->top, vert_res, vert_size * 100)),
2472 "got %d\n", (short)rec->rdParm[0]);
2473 ok(near_match((short)rec->rdParm[1], MulDiv(rc->right - rc->left, horz_res, horz_size * 100)),
2474 "got %d\n", (short)rec->rdParm[1]);
2475 }
2476
2477 rec_num++;
2478 rec = (METARECORD*)((WORD*)rec + rec->rdSize);
2479 }
2480
2481 end:
2482 HeapFree(GetProcessHeap(), 0, mh);
2483 HeapFree(GetProcessHeap(), 0, enh_header);
2484 DeleteEnhMetaFile(emf);
2485
2486 ReleaseDC(NULL, display_dc);
2487 }
2488
2489 static void test_GetWinMetaFileBits(void)
2490 {
2491 UINT mode;
2492 RECT frames[] =
2493 {
2494 { 1000, 2000, 3000, 6000},
2495 {-1000, 2000, 3000, 6000},
2496 { 1000, -2000, 3000, 6000},
2497 { 1005, 2005, 3000, 6000},
2498 {-1005, -2005, 3000, 6000},
2499 {-1005, -2010, 3000, 6000},
2500 {-1005, 2010, 3000, 6000},
2501 { 0, 0, 1, 1},
2502 { -1, -1, 1, 1},
2503 { 0, 0, 0, 0}
2504 };
2505
2506 for(mode = MM_MIN; mode <= MM_MAX; mode++)
2507 {
2508 RECT *rc;
2509 trace("mode %d\n", mode);
2510
2511 for(rc = frames; rc->right - rc->left > 0; rc++)
2512 {
2513 trace("frame %d,%d - %d,%d\n", rc->left, rc->top, rc->right, rc->bottom);
2514 getwinmetafilebits(mode, 1, rc);
2515 getwinmetafilebits(mode, 2, rc);
2516 }
2517 }
2518 }
2519
2520 static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC);
2521 static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC);
2522 static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC);
2523
2524 static void test_gdiis(void)
2525 {
2526 RECT rect = {0,0,100,100};
2527 HDC hdc, hemfDC, hmfDC;
2528 HENHMETAFILE hemf;
2529 HMODULE hgdi32;
2530
2531 /* resolve all the functions */
2532 hgdi32 = GetModuleHandle("gdi32");
2533 pGdiIsMetaPrintDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaPrintDC");
2534 pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC");
2535 pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC");
2536
2537 if(!pGdiIsMetaPrintDC || !pGdiIsMetaFileDC || !pGdiIsPlayMetafileDC)
2538 {
2539 win_skip("Needed GdiIs* functions are not available\n");
2540 return;
2541 }
2542
2543 /* try with nothing */
2544 ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n");
2545 ok(!pGdiIsMetaFileDC(NULL), "ismetafile with NULL parameter\n");
2546 ok(!pGdiIsPlayMetafileDC(NULL), "isplaymetafile with NULL parameter\n");
2547
2548 /* try with a metafile */
2549 hmfDC = CreateMetaFile(NULL);
2550 ok(!pGdiIsMetaPrintDC(hmfDC), "ismetaprint on metafile\n");
2551 ok(pGdiIsMetaFileDC(hmfDC), "ismetafile on metafile\n");
2552 ok(!pGdiIsPlayMetafileDC(hmfDC), "isplaymetafile on metafile\n");
2553 DeleteMetaFile(CloseMetaFile(hmfDC));
2554
2555 /* try with an enhanced metafile */
2556 hdc = GetDC(NULL);
2557 hemfDC = CreateEnhMetaFileW(hdc, NULL, &rect, NULL);
2558 ok(hemfDC != NULL, "failed to create emf\n");
2559
2560 ok(!pGdiIsMetaPrintDC(hemfDC), "ismetaprint on emf\n");
2561 ok(pGdiIsMetaFileDC(hemfDC), "ismetafile on emf\n");
2562 ok(!pGdiIsPlayMetafileDC(hemfDC), "isplaymetafile on emf\n");
2563
2564 hemf = CloseEnhMetaFile(hemfDC);
2565 ok(hemf != NULL, "failed to close EMF\n");
2566 DeleteEnhMetaFile(hemf);
2567 ReleaseDC(NULL,hdc);
2568 }
2569
2570 static void test_SetEnhMetaFileBits(void)
2571 {
2572 BYTE data[256];
2573 HENHMETAFILE hemf;
2574 ENHMETAHEADER *emh;
2575
2576 memset(data, 0xAA, sizeof(data));
2577 SetLastError(0xdeadbeef);
2578 hemf = SetEnhMetaFileBits(sizeof(data), data);
2579 ok(!hemf, "SetEnhMetaFileBits should fail\n");
2580 ok(GetLastError() == ERROR_INVALID_DATA ||
2581 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */
2582 "expected ERROR_INVALID_DATA or ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2583
2584 emh = (ENHMETAHEADER *)data;
2585 memset(emh, 0, sizeof(*emh));
2586
2587 emh->iType = EMR_HEADER;
2588 emh->nSize = sizeof(*emh);
2589 emh->dSignature = ENHMETA_SIGNATURE;
2590 /* emh->nVersion = 0x10000; XP doesn't care about version */
2591 emh->nBytes = sizeof(*emh);
2592 /* emh->nRecords = 1; XP doesn't care about records */
2593 emh->nHandles = 1; /* XP refuses to load a EMF if nHandles == 0 */
2594
2595 SetLastError(0xdeadbeef);
2596 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2597 ok(hemf != 0, "SetEnhMetaFileBits error %u\n", GetLastError());
2598 DeleteEnhMetaFile(hemf);
2599
2600 /* XP refuses to load unaligned EMF */
2601 emh->nBytes++;
2602 SetLastError(0xdeadbeef);
2603 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2604 ok(!hemf ||
2605 broken(hemf != NULL), /* Win9x, WinMe */
2606 "SetEnhMetaFileBits should fail\n");
2607 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2608 DeleteEnhMetaFile(hemf);
2609
2610 emh->dSignature = 0;
2611 emh->nBytes--;
2612 SetLastError(0xdeadbeef);
2613 hemf = SetEnhMetaFileBits(emh->nBytes, data);
2614 ok(!hemf ||
2615 broken(hemf != NULL), /* Win9x, WinMe */
2616 "SetEnhMetaFileBits should fail\n");
2617 ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError());
2618 DeleteEnhMetaFile(hemf);
2619 }
2620
2621 START_TEST(metafile)
2622 {
2623 init_function_pointers();
2624
2625 /* For enhanced metafiles (enhmfdrv) */
2626 test_ExtTextOut();
2627 test_SaveDC();
2628
2629 /* For win-format metafiles (mfdrv) */
2630 test_mf_SaveDC();
2631 test_mf_Blank();
2632 test_mf_Graphics();
2633 test_mf_PatternBrush();
2634 test_CopyMetaFile();
2635 test_SetMetaFileBits();
2636 test_mf_ExtTextOut_on_path();
2637 test_emf_ExtTextOut_on_path();
2638 test_emf_clipping();
2639
2640 /* For metafile conversions */
2641 test_mf_conversions();
2642 test_SetWinMetaFileBits();
2643 test_GetWinMetaFileBits();
2644
2645 test_gdiis();
2646 test_SetEnhMetaFileBits();
2647 }