2 * Unit test suite for metafiles
4 * Copyright (C) 2011 Vincent Povirk for CodeWeavers
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.
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.
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
24 #include "wine/test.h"
26 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
28 typedef struct emfplus_record
35 typedef struct emfplus_check_state
39 const struct emfplus_record
*expected
;
41 } emfplus_check_state
;
43 static void check_record(int count
, const char *desc
, const struct emfplus_record
*expected
, const struct emfplus_record
*actual
)
46 todo_wine
ok(expected
->record_type
== actual
->record_type
,
47 "%s.%i: Expected record type 0x%x, got 0x%x\n", desc
, count
,
48 expected
->record_type
, actual
->record_type
);
50 ok(expected
->record_type
== actual
->record_type
,
51 "%s.%i: Expected record type 0x%x, got 0x%x\n", desc
, count
,
52 expected
->record_type
, actual
->record_type
);
55 typedef struct EmfPlusRecordHeader
61 } EmfPlusRecordHeader
;
63 static int CALLBACK
enum_emf_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
64 int nObj
, LPARAM lpData
)
66 emfplus_check_state
*state
= (emfplus_check_state
*)lpData
;
67 emfplus_record actual
;
69 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
71 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
73 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
77 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
79 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
81 ok(record
->Size
== record
->DataSize
+ sizeof(EmfPlusRecordHeader
),
82 "%s: EMF+ record datasize %u and size %u mismatch\n", state
->desc
, record
->DataSize
, record
->Size
);
84 ok(offset
+ record
->DataSize
<= comment
->cbData
,
85 "%s: EMF+ record truncated\n", state
->desc
);
87 if (offset
+ record
->DataSize
> comment
->cbData
)
90 if (state
->expected
[state
->count
].record_type
)
93 actual
.record_type
= record
->Type
;
95 check_record(state
->count
, state
->desc
, &state
->expected
[state
->count
], &actual
);
101 ok(0, "%s: Unexpected EMF+ 0x%x record\n", state
->desc
, record
->Type
);
104 offset
+= record
->Size
;
107 ok(offset
== comment
->cbData
, "%s: truncated EMF+ record data?\n", state
->desc
);
113 if (state
->expected
[state
->count
].record_type
)
116 actual
.record_type
= lpEMFR
->iType
;
118 check_record(state
->count
, state
->desc
, &state
->expected
[state
->count
], &actual
);
124 ok(0, "%s: Unexpected EMF 0x%x record\n", state
->desc
, lpEMFR
->iType
);
130 static void check_emfplus(HENHMETAFILE hemf
, const emfplus_record
*expected
, const char *desc
)
132 emfplus_check_state state
;
136 state
.expected
= expected
;
138 EnumEnhMetaFile(0, hemf
, enum_emf_proc
, &state
, NULL
);
140 if (expected
[state
.count
].todo
)
141 todo_wine
ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
143 ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
146 static BOOL CALLBACK
enum_metafile_proc(EmfPlusRecordType record_type
, unsigned int flags
,
147 unsigned int dataSize
, const unsigned char *pStr
, void *userdata
)
149 emfplus_check_state
*state
= (emfplus_check_state
*)userdata
;
150 emfplus_record actual
;
153 actual
.record_type
= record_type
;
156 ok(pStr
== NULL
, "non-NULL pStr\n");
158 if (state
->expected
[state
->count
].record_type
)
160 check_record(state
->count
, state
->desc
, &state
->expected
[state
->count
], &actual
);
166 ok(0, "%s: Unexpected EMF 0x%x record\n", state
->desc
, record_type
);
172 static void check_metafile(GpMetafile
*metafile
, const emfplus_record
*expected
, const char *desc
,
173 const GpPointF
*dst_points
, const GpRectF
*src_rect
, Unit src_unit
)
177 GpGraphics
*graphics
;
178 emfplus_check_state state
;
182 state
.expected
= expected
;
183 state
.metafile
= metafile
;
185 hdc
= CreateCompatibleDC(0);
187 stat
= GdipCreateFromHDC(hdc
, &graphics
);
190 stat
= GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, dst_points
,
191 3, src_rect
, src_unit
, enum_metafile_proc
, &state
, NULL
);
194 if (expected
[state
.count
].todo
)
195 todo_wine
ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
197 ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
199 GdipDeleteGraphics(graphics
);
204 static BOOL CALLBACK
play_metafile_proc(EmfPlusRecordType record_type
, unsigned int flags
,
205 unsigned int dataSize
, const unsigned char *pStr
, void *userdata
)
207 emfplus_check_state
*state
= (emfplus_check_state
*)userdata
;
210 stat
= GdipPlayMetafileRecord(state
->metafile
, record_type
, flags
, dataSize
, pStr
);
212 if (state
->expected
[state
->count
].record_type
)
214 if (state
->expected
[state
->count
].playback_todo
)
215 todo_wine
ok(stat
== Ok
, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state
->desc
, state
->count
, stat
);
217 ok(stat
== Ok
, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state
->desc
, state
->count
, stat
);
222 if (state
->expected
[state
->count
].playback_todo
)
223 todo_wine
ok(0, "%s: too many records\n", state
->desc
);
225 ok(0, "%s: too many records\n", state
->desc
);
233 static void play_metafile(GpMetafile
*metafile
, GpGraphics
*graphics
, const emfplus_record
*expected
,
234 const char *desc
, const GpPointF
*dst_points
, const GpRectF
*src_rect
, Unit src_unit
)
237 emfplus_check_state state
;
241 state
.expected
= expected
;
242 state
.metafile
= metafile
;
244 stat
= GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, dst_points
,
245 3, src_rect
, src_unit
, play_metafile_proc
, &state
, NULL
);
249 static const emfplus_record empty_records
[] = {
251 {0, EmfPlusRecordTypeHeader
},
252 {0, EmfPlusRecordTypeEndOfFile
},
257 static void test_empty(void)
260 GpMetafile
*metafile
;
261 GpGraphics
*graphics
;
263 HENHMETAFILE hemf
, dummy
;
265 static const GpRectF frame
= {0.0, 0.0, 100.0, 100.0};
266 static const GpPointF dst_points
[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}};
267 static const WCHAR description
[] = {'w','i','n','e','t','e','s','t',0};
269 hdc
= CreateCompatibleDC(0);
271 stat
= GdipRecordMetafile(NULL
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
272 expect(InvalidParameter
, stat
);
274 stat
= GdipRecordMetafile(hdc
, MetafileTypeInvalid
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
275 expect(InvalidParameter
, stat
);
277 stat
= GdipRecordMetafile(hdc
, MetafileTypeWmf
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
278 expect(InvalidParameter
, stat
);
280 stat
= GdipRecordMetafile(hdc
, MetafileTypeWmfPlaceable
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
281 expect(InvalidParameter
, stat
);
283 stat
= GdipRecordMetafile(hdc
, MetafileTypeEmfPlusDual
+1, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
284 expect(InvalidParameter
, stat
);
286 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, NULL
);
287 expect(InvalidParameter
, stat
);
289 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
297 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
298 expect(InvalidParameter
, stat
);
300 stat
= GdipGetImageGraphicsContext((GpImage
*)metafile
, &graphics
);
303 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
304 expect(InvalidParameter
, stat
);
306 stat
= GdipDeleteGraphics(graphics
);
309 check_metafile(metafile
, empty_records
, "empty metafile", dst_points
, &frame
, UnitPixel
);
311 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
314 stat
= GdipGetHemfFromMetafile(metafile
, &dummy
);
315 expect(InvalidParameter
, stat
);
317 stat
= GdipDisposeImage((GpImage
*)metafile
);
320 check_emfplus(hemf
, empty_records
, "empty emf");
322 ret
= DeleteEnhMetaFile(hemf
);
323 ok(ret
!= 0, "Failed to delete enhmetafile %p\n", hemf
);
326 static const emfplus_record getdc_records
[] = {
328 {0, EmfPlusRecordTypeHeader
},
329 {0, EmfPlusRecordTypeGetDC
},
330 {0, EMR_CREATEBRUSHINDIRECT
},
331 {0, EMR_SELECTOBJECT
},
333 {0, EMR_SELECTOBJECT
},
334 {0, EMR_DELETEOBJECT
},
335 {0, EmfPlusRecordTypeEndOfFile
},
340 static void test_getdc(void)
343 GpMetafile
*metafile
;
344 GpGraphics
*graphics
;
345 HDC hdc
, metafile_dc
;
348 static const GpRectF frame
= {0.0, 0.0, 100.0, 100.0};
349 static const GpPointF dst_points
[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}};
350 static const GpPointF dst_points_half
[3] = {{0.0,0.0},{50.0,0.0},{0.0,50.0}};
351 static const WCHAR description
[] = {'w','i','n','e','t','e','s','t',0};
352 HBRUSH hbrush
, holdbrush
;
356 hdc
= CreateCompatibleDC(0);
358 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
366 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
367 expect(InvalidParameter
, stat
);
369 stat
= GdipGetImageGraphicsContext((GpImage
*)metafile
, &graphics
);
372 stat
= GdipGetDC(graphics
, &metafile_dc
);
377 GdipDeleteGraphics(graphics
);
378 GdipDisposeImage((GpImage
*)metafile
);
382 hbrush
= CreateSolidBrush(0xff0000);
384 holdbrush
= SelectObject(metafile_dc
, hbrush
);
386 Rectangle(metafile_dc
, 25, 25, 75, 75);
388 SelectObject(metafile_dc
, holdbrush
);
390 DeleteObject(hbrush
);
392 stat
= GdipReleaseDC(graphics
, metafile_dc
);
395 stat
= GdipDeleteGraphics(graphics
);
398 check_metafile(metafile
, getdc_records
, "getdc metafile", dst_points
, &frame
, UnitPixel
);
400 stat
= GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
403 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
406 play_metafile(metafile
, graphics
, getdc_records
, "getdc playback", dst_points
, &frame
, UnitPixel
);
408 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
412 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
414 expect(0xff0000ff, color
);
416 stat
= GdipBitmapSetPixel(bitmap
, 50, 50, 0);
419 play_metafile(metafile
, graphics
, getdc_records
, "getdc playback", dst_points_half
, &frame
, UnitPixel
);
421 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
423 expect(0xff0000ff, color
);
425 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
429 stat
= GdipBitmapSetPixel(bitmap
, 15, 15, 0);
432 stat
= GdipDrawImagePointsRect(graphics
, (GpImage
*)metafile
, dst_points
, 3,
433 0.0, 0.0, 100.0, 100.0, UnitPixel
, NULL
, NULL
, NULL
);
436 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
440 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
442 expect(0xff0000ff, color
);
444 stat
= GdipDeleteGraphics(graphics
);
447 stat
= GdipDisposeImage((GpImage
*)bitmap
);
450 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
453 stat
= GdipDisposeImage((GpImage
*)metafile
);
456 check_emfplus(hemf
, getdc_records
, "getdc emf");
458 ret
= DeleteEnhMetaFile(hemf
);
459 ok(ret
!= 0, "Failed to delete enhmetafile %p\n", hemf
);
462 static const emfplus_record emfonly_records
[] = {
464 {0, EMR_CREATEBRUSHINDIRECT
},
465 {0, EMR_SELECTOBJECT
},
467 {0, EMR_SELECTOBJECT
},
468 {0, EMR_DELETEOBJECT
},
473 static void test_emfonly(void)
476 GpMetafile
*metafile
;
478 GpGraphics
*graphics
;
479 HDC hdc
, metafile_dc
;
482 static const GpRectF frame
= {0.0, 0.0, 100.0, 100.0};
483 static const GpPointF dst_points
[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}};
484 static const WCHAR description
[] = {'w','i','n','e','t','e','s','t',0};
485 HBRUSH hbrush
, holdbrush
;
489 hdc
= CreateCompatibleDC(0);
491 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
499 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
500 expect(InvalidParameter
, stat
);
502 stat
= GdipGetImageGraphicsContext((GpImage
*)metafile
, &graphics
);
505 stat
= GdipGetDC(graphics
, &metafile_dc
);
510 GdipDeleteGraphics(graphics
);
511 GdipDisposeImage((GpImage
*)metafile
);
515 hbrush
= CreateSolidBrush(0xff0000);
517 holdbrush
= SelectObject(metafile_dc
, hbrush
);
519 Rectangle(metafile_dc
, 25, 25, 75, 75);
521 SelectObject(metafile_dc
, holdbrush
);
523 DeleteObject(hbrush
);
525 stat
= GdipReleaseDC(graphics
, metafile_dc
);
528 stat
= GdipDeleteGraphics(graphics
);
531 check_metafile(metafile
, emfonly_records
, "emfonly metafile", dst_points
, &frame
, UnitPixel
);
533 stat
= GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
536 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
539 play_metafile(metafile
, graphics
, emfonly_records
, "emfonly playback", dst_points
, &frame
, UnitPixel
);
541 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
545 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
547 expect(0xff0000ff, color
);
549 stat
= GdipBitmapSetPixel(bitmap
, 50, 50, 0);
552 stat
= GdipDrawImagePointsRect(graphics
, (GpImage
*)metafile
, dst_points
, 3,
553 0.0, 0.0, 100.0, 100.0, UnitPixel
, NULL
, NULL
, NULL
);
556 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
560 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
562 expect(0xff0000ff, color
);
564 stat
= GdipCloneImage((GpImage
*)metafile
, &clone
);
569 stat
= GdipBitmapSetPixel(bitmap
, 50, 50, 0);
572 stat
= GdipDrawImagePointsRect(graphics
, clone
, dst_points
, 3,
573 0.0, 0.0, 100.0, 100.0, UnitPixel
, NULL
, NULL
, NULL
);
576 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
580 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
582 expect(0xff0000ff, color
);
584 GdipDisposeImage(clone
);
587 stat
= GdipDeleteGraphics(graphics
);
590 stat
= GdipDisposeImage((GpImage
*)bitmap
);
593 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
596 stat
= GdipDisposeImage((GpImage
*)metafile
);
599 check_emfplus(hemf
, emfonly_records
, "emfonly emf");
601 ret
= DeleteEnhMetaFile(hemf
);
602 ok(ret
!= 0, "Failed to delete enhmetafile %p\n", hemf
);
607 struct GdiplusStartupInput gdiplusStartupInput
;
608 ULONG_PTR gdiplusToken
;
610 gdiplusStartupInput
.GdiplusVersion
= 1;
611 gdiplusStartupInput
.DebugEventCallback
= NULL
;
612 gdiplusStartupInput
.SuppressBackgroundThread
= 0;
613 gdiplusStartupInput
.SuppressExternalCodecs
= 0;
615 GdiplusStartup(&gdiplusToken
, &gdiplusStartupInput
, NULL
);
621 GdiplusShutdown(gdiplusToken
);