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
21 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
25 //#include "windows.h"
26 #include <wine/test.h>
31 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
33 typedef struct emfplus_record
40 typedef struct emfplus_check_state
44 const struct emfplus_record
*expected
;
46 } emfplus_check_state
;
48 static void check_record(int count
, const char *desc
, const struct emfplus_record
*expected
, const struct emfplus_record
*actual
)
51 todo_wine
ok(expected
->record_type
== actual
->record_type
,
52 "%s.%i: Expected record type 0x%x, got 0x%x\n", desc
, count
,
53 expected
->record_type
, actual
->record_type
);
55 ok(expected
->record_type
== actual
->record_type
,
56 "%s.%i: Expected record type 0x%x, got 0x%x\n", desc
, count
,
57 expected
->record_type
, actual
->record_type
);
60 typedef struct EmfPlusRecordHeader
66 } EmfPlusRecordHeader
;
68 static int CALLBACK
enum_emf_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
69 int nObj
, LPARAM lpData
)
71 emfplus_check_state
*state
= (emfplus_check_state
*)lpData
;
72 emfplus_record actual
;
74 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
76 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
78 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
82 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
84 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
86 ok(record
->Size
== record
->DataSize
+ sizeof(EmfPlusRecordHeader
),
87 "%s: EMF+ record datasize %u and size %u mismatch\n", state
->desc
, record
->DataSize
, record
->Size
);
89 ok(offset
+ record
->DataSize
<= comment
->cbData
,
90 "%s: EMF+ record truncated\n", state
->desc
);
92 if (offset
+ record
->DataSize
> comment
->cbData
)
95 if (state
->expected
[state
->count
].record_type
)
98 actual
.record_type
= record
->Type
;
100 check_record(state
->count
, state
->desc
, &state
->expected
[state
->count
], &actual
);
106 ok(0, "%s: Unexpected EMF+ 0x%x record\n", state
->desc
, record
->Type
);
109 offset
+= record
->Size
;
112 ok(offset
== comment
->cbData
, "%s: truncated EMF+ record data?\n", state
->desc
);
118 if (state
->expected
[state
->count
].record_type
)
121 actual
.record_type
= lpEMFR
->iType
;
123 check_record(state
->count
, state
->desc
, &state
->expected
[state
->count
], &actual
);
129 ok(0, "%s: Unexpected EMF 0x%x record\n", state
->desc
, lpEMFR
->iType
);
135 static void check_emfplus(HENHMETAFILE hemf
, const emfplus_record
*expected
, const char *desc
)
137 emfplus_check_state state
;
141 state
.expected
= expected
;
143 EnumEnhMetaFile(0, hemf
, enum_emf_proc
, &state
, NULL
);
145 if (expected
[state
.count
].todo
)
146 todo_wine
ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
148 ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
151 static BOOL CALLBACK
enum_metafile_proc(EmfPlusRecordType record_type
, unsigned int flags
,
152 unsigned int dataSize
, const unsigned char *pStr
, void *userdata
)
154 emfplus_check_state
*state
= (emfplus_check_state
*)userdata
;
155 emfplus_record actual
;
158 actual
.record_type
= record_type
;
161 ok(pStr
== NULL
, "non-NULL pStr\n");
163 if (state
->expected
[state
->count
].record_type
)
165 check_record(state
->count
, state
->desc
, &state
->expected
[state
->count
], &actual
);
171 ok(0, "%s: Unexpected EMF 0x%x record\n", state
->desc
, record_type
);
177 static void check_metafile(GpMetafile
*metafile
, const emfplus_record
*expected
, const char *desc
,
178 const GpPointF
*dst_points
, const GpRectF
*src_rect
, Unit src_unit
)
182 GpGraphics
*graphics
;
183 emfplus_check_state state
;
187 state
.expected
= expected
;
188 state
.metafile
= metafile
;
190 hdc
= CreateCompatibleDC(0);
192 stat
= GdipCreateFromHDC(hdc
, &graphics
);
195 stat
= GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, dst_points
,
196 3, src_rect
, src_unit
, enum_metafile_proc
, &state
, NULL
);
199 if (expected
[state
.count
].todo
)
200 todo_wine
ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
202 ok(expected
[state
.count
].record_type
== 0, "%s: Got %i records, expecting more\n", desc
, state
.count
);
204 GdipDeleteGraphics(graphics
);
209 static BOOL CALLBACK
play_metafile_proc(EmfPlusRecordType record_type
, unsigned int flags
,
210 unsigned int dataSize
, const unsigned char *pStr
, void *userdata
)
212 emfplus_check_state
*state
= (emfplus_check_state
*)userdata
;
215 stat
= GdipPlayMetafileRecord(state
->metafile
, record_type
, flags
, dataSize
, pStr
);
217 if (state
->expected
[state
->count
].record_type
)
219 if (state
->expected
[state
->count
].playback_todo
)
220 todo_wine
ok(stat
== Ok
, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state
->desc
, state
->count
, stat
);
222 ok(stat
== Ok
, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state
->desc
, state
->count
, stat
);
227 if (state
->expected
[state
->count
].playback_todo
)
228 todo_wine
ok(0, "%s: too many records\n", state
->desc
);
230 ok(0, "%s: too many records\n", state
->desc
);
238 static void play_metafile(GpMetafile
*metafile
, GpGraphics
*graphics
, const emfplus_record
*expected
,
239 const char *desc
, const GpPointF
*dst_points
, const GpRectF
*src_rect
, Unit src_unit
)
242 emfplus_check_state state
;
246 state
.expected
= expected
;
247 state
.metafile
= metafile
;
249 stat
= GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, dst_points
,
250 3, src_rect
, src_unit
, play_metafile_proc
, &state
, NULL
);
254 static const emfplus_record empty_records
[] = {
256 {0, EmfPlusRecordTypeHeader
},
257 {0, EmfPlusRecordTypeEndOfFile
},
262 static void test_empty(void)
265 GpMetafile
*metafile
;
266 GpGraphics
*graphics
;
268 HENHMETAFILE hemf
, dummy
;
270 static const GpRectF frame
= {0.0, 0.0, 100.0, 100.0};
271 static const GpPointF dst_points
[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}};
272 static const WCHAR description
[] = {'w','i','n','e','t','e','s','t',0};
274 hdc
= CreateCompatibleDC(0);
276 stat
= GdipRecordMetafile(NULL
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
277 expect(InvalidParameter
, stat
);
279 stat
= GdipRecordMetafile(hdc
, MetafileTypeInvalid
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
280 expect(InvalidParameter
, stat
);
282 stat
= GdipRecordMetafile(hdc
, MetafileTypeWmf
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
283 expect(InvalidParameter
, stat
);
285 stat
= GdipRecordMetafile(hdc
, MetafileTypeWmfPlaceable
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
286 expect(InvalidParameter
, stat
);
288 stat
= GdipRecordMetafile(hdc
, MetafileTypeEmfPlusDual
+1, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
289 expect(InvalidParameter
, stat
);
291 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, NULL
);
292 expect(InvalidParameter
, stat
);
294 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
302 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
303 expect(InvalidParameter
, stat
);
305 stat
= GdipGetImageGraphicsContext((GpImage
*)metafile
, &graphics
);
308 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
309 expect(InvalidParameter
, stat
);
311 stat
= GdipDeleteGraphics(graphics
);
314 check_metafile(metafile
, empty_records
, "empty metafile", dst_points
, &frame
, UnitPixel
);
316 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
319 stat
= GdipGetHemfFromMetafile(metafile
, &dummy
);
320 expect(InvalidParameter
, stat
);
322 stat
= GdipDisposeImage((GpImage
*)metafile
);
325 check_emfplus(hemf
, empty_records
, "empty emf");
327 ret
= DeleteEnhMetaFile(hemf
);
328 ok(ret
!= 0, "Failed to delete enhmetafile %p\n", hemf
);
331 static const emfplus_record getdc_records
[] = {
333 {0, EmfPlusRecordTypeHeader
},
334 {0, EmfPlusRecordTypeGetDC
},
335 {0, EMR_CREATEBRUSHINDIRECT
},
336 {0, EMR_SELECTOBJECT
},
338 {0, EMR_SELECTOBJECT
},
339 {0, EMR_DELETEOBJECT
},
340 {0, EmfPlusRecordTypeEndOfFile
},
345 static void test_getdc(void)
348 GpMetafile
*metafile
;
349 GpGraphics
*graphics
;
350 HDC hdc
, metafile_dc
;
353 static const GpRectF frame
= {0.0, 0.0, 100.0, 100.0};
354 static const GpPointF dst_points
[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}};
355 static const GpPointF dst_points_half
[3] = {{0.0,0.0},{50.0,0.0},{0.0,50.0}};
356 static const WCHAR description
[] = {'w','i','n','e','t','e','s','t',0};
357 HBRUSH hbrush
, holdbrush
;
361 hdc
= CreateCompatibleDC(0);
363 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfPlusOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
371 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
372 expect(InvalidParameter
, stat
);
374 stat
= GdipGetImageGraphicsContext((GpImage
*)metafile
, &graphics
);
377 stat
= GdipGetDC(graphics
, &metafile_dc
);
382 GdipDeleteGraphics(graphics
);
383 GdipDisposeImage((GpImage
*)metafile
);
387 hbrush
= CreateSolidBrush(0xff0000);
389 holdbrush
= SelectObject(metafile_dc
, hbrush
);
391 Rectangle(metafile_dc
, 25, 25, 75, 75);
393 SelectObject(metafile_dc
, holdbrush
);
395 DeleteObject(hbrush
);
397 stat
= GdipReleaseDC(graphics
, metafile_dc
);
400 stat
= GdipDeleteGraphics(graphics
);
403 check_metafile(metafile
, getdc_records
, "getdc metafile", dst_points
, &frame
, UnitPixel
);
405 stat
= GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
408 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
411 play_metafile(metafile
, graphics
, getdc_records
, "getdc playback", dst_points
, &frame
, UnitPixel
);
413 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
417 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
419 expect(0xff0000ff, color
);
421 stat
= GdipBitmapSetPixel(bitmap
, 50, 50, 0);
424 play_metafile(metafile
, graphics
, getdc_records
, "getdc playback", dst_points_half
, &frame
, UnitPixel
);
426 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
428 expect(0xff0000ff, color
);
430 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
434 stat
= GdipBitmapSetPixel(bitmap
, 15, 15, 0);
437 stat
= GdipDrawImagePointsRect(graphics
, (GpImage
*)metafile
, dst_points
, 3,
438 0.0, 0.0, 100.0, 100.0, UnitPixel
, NULL
, NULL
, NULL
);
441 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
445 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
447 expect(0xff0000ff, color
);
449 stat
= GdipDeleteGraphics(graphics
);
452 stat
= GdipDisposeImage((GpImage
*)bitmap
);
455 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
458 stat
= GdipDisposeImage((GpImage
*)metafile
);
461 check_emfplus(hemf
, getdc_records
, "getdc emf");
463 ret
= DeleteEnhMetaFile(hemf
);
464 ok(ret
!= 0, "Failed to delete enhmetafile %p\n", hemf
);
467 static const emfplus_record emfonly_records
[] = {
469 {0, EMR_CREATEBRUSHINDIRECT
},
470 {0, EMR_SELECTOBJECT
},
472 {0, EMR_SELECTOBJECT
},
473 {0, EMR_DELETEOBJECT
},
478 static void test_emfonly(void)
481 GpMetafile
*metafile
;
483 GpGraphics
*graphics
;
484 HDC hdc
, metafile_dc
;
487 static const GpRectF frame
= {0.0, 0.0, 100.0, 100.0};
488 static const GpPointF dst_points
[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}};
489 static const WCHAR description
[] = {'w','i','n','e','t','e','s','t',0};
490 HBRUSH hbrush
, holdbrush
;
494 hdc
= CreateCompatibleDC(0);
496 stat
= GdipRecordMetafile(hdc
, EmfTypeEmfOnly
, &frame
, MetafileFrameUnitPixel
, description
, &metafile
);
504 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
505 expect(InvalidParameter
, stat
);
507 stat
= GdipGetImageGraphicsContext((GpImage
*)metafile
, &graphics
);
510 stat
= GdipGetDC(graphics
, &metafile_dc
);
515 GdipDeleteGraphics(graphics
);
516 GdipDisposeImage((GpImage
*)metafile
);
520 hbrush
= CreateSolidBrush(0xff0000);
522 holdbrush
= SelectObject(metafile_dc
, hbrush
);
524 Rectangle(metafile_dc
, 25, 25, 75, 75);
526 SelectObject(metafile_dc
, holdbrush
);
528 DeleteObject(hbrush
);
530 stat
= GdipReleaseDC(graphics
, metafile_dc
);
533 stat
= GdipDeleteGraphics(graphics
);
536 check_metafile(metafile
, emfonly_records
, "emfonly metafile", dst_points
, &frame
, UnitPixel
);
538 stat
= GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
541 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
544 play_metafile(metafile
, graphics
, emfonly_records
, "emfonly playback", dst_points
, &frame
, UnitPixel
);
546 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
550 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
552 expect(0xff0000ff, color
);
554 stat
= GdipBitmapSetPixel(bitmap
, 50, 50, 0);
557 stat
= GdipDrawImagePointsRect(graphics
, (GpImage
*)metafile
, dst_points
, 3,
558 0.0, 0.0, 100.0, 100.0, UnitPixel
, NULL
, NULL
, NULL
);
561 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
565 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
567 expect(0xff0000ff, color
);
569 stat
= GdipCloneImage((GpImage
*)metafile
, &clone
);
574 stat
= GdipBitmapSetPixel(bitmap
, 50, 50, 0);
577 stat
= GdipDrawImagePointsRect(graphics
, clone
, dst_points
, 3,
578 0.0, 0.0, 100.0, 100.0, UnitPixel
, NULL
, NULL
, NULL
);
581 stat
= GdipBitmapGetPixel(bitmap
, 15, 15, &color
);
585 stat
= GdipBitmapGetPixel(bitmap
, 50, 50, &color
);
587 expect(0xff0000ff, color
);
589 GdipDisposeImage(clone
);
592 stat
= GdipDeleteGraphics(graphics
);
595 stat
= GdipDisposeImage((GpImage
*)bitmap
);
598 stat
= GdipGetHemfFromMetafile(metafile
, &hemf
);
601 stat
= GdipDisposeImage((GpImage
*)metafile
);
604 check_emfplus(hemf
, emfonly_records
, "emfonly emf");
606 ret
= DeleteEnhMetaFile(hemf
);
607 ok(ret
!= 0, "Failed to delete enhmetafile %p\n", hemf
);
612 struct GdiplusStartupInput gdiplusStartupInput
;
613 ULONG_PTR gdiplusToken
;
615 gdiplusStartupInput
.GdiplusVersion
= 1;
616 gdiplusStartupInput
.DebugEventCallback
= NULL
;
617 gdiplusStartupInput
.SuppressBackgroundThread
= 0;
618 gdiplusStartupInput
.SuppressExternalCodecs
= 0;
620 GdiplusStartup(&gdiplusToken
, &gdiplusStartupInput
, NULL
);
626 GdiplusShutdown(gdiplusToken
);