+ hdc = CreateCompatibleDC(0);
+
+ stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile);
+ expect(Ok, stat);
+
+ DeleteDC(hdc);
+
+ if (stat != Ok)
+ return;
+
+ stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics);
+ expect(Ok, stat);
+
+ /* Normal usage */
+ stat = GdipBeginContainer2(graphics, &state1);
+ expect(Ok, stat);
+
+ stat = GdipScaleWorldTransform(graphics, 2.0, 2.0, MatrixOrderPrepend);
+ expect(Ok, stat);
+
+ stat = GdipCreateSolidFill((ARGB)0xff000000, (GpSolidFill**)&brush);
+ expect(Ok, stat);
+
+ stat = GdipFillRectangle(graphics, brush, 5.0, 5.0, 5.0, 5.0);
+ expect(Ok, stat);
+
+ stat = GdipDeleteBrush(brush);
+ expect(Ok, stat);
+
+ stat = GdipEndContainer(graphics, state1);
+ expect(Ok, stat);
+
+ stat = GdipScaleWorldTransform(graphics, 1.0, 1.0, MatrixOrderPrepend);
+ expect(Ok, stat);
+
+ stat = GdipCreateSolidFill((ARGB)0xff0000ff, (GpSolidFill**)&brush);
+ expect(Ok, stat);
+
+ stat = GdipFillRectangle(graphics, brush, 5.0, 5.0, 5.0, 5.0);
+ expect(Ok, stat);
+
+ stat = GdipDeleteBrush(brush);
+ expect(Ok, stat);
+
+ stat = GdipSaveGraphics(graphics, &state1);
+ expect(Ok, stat);
+
+ stat = GdipRestoreGraphics(graphics, state1);
+ expect(Ok, stat);
+
+ /* Popping two states at once */
+ stat = GdipScaleWorldTransform(graphics, 2.0, 2.0, MatrixOrderPrepend);
+ expect(Ok, stat);
+
+ stat = GdipBeginContainer2(graphics, &state1);
+ expect(Ok, stat);
+
+ stat = GdipScaleWorldTransform(graphics, 4.0, 4.0, MatrixOrderPrepend);
+ expect(Ok, stat);
+
+ stat = GdipBeginContainer2(graphics, &state2);
+ expect(Ok, stat);
+
+ stat = GdipEndContainer(graphics, state1);
+ expect(Ok, stat);
+
+ stat = GdipCreateSolidFill((ARGB)0xff00ff00, (GpSolidFill**)&brush);
+ expect(Ok, stat);
+
+ stat = GdipFillRectangle(graphics, brush, 20.0, 20.0, 5.0, 5.0);
+ expect(Ok, stat);
+
+ stat = GdipDeleteBrush(brush);
+ expect(Ok, stat);
+
+ /* With transform applied */
+ stat = GdipGetDpiX(graphics, &dpix);
+ expect(Ok, stat);
+
+ stat = GdipGetDpiY(graphics, &dpiy);
+ expect(Ok, stat);
+
+ srcrect.X = 0.0;
+ srcrect.Y = 0.0;
+ srcrect.Width = 1.0;
+ srcrect.Height = 1.0;
+
+ dstrect.X = 25.0;
+ dstrect.Y = 0.0;
+ dstrect.Width = 5.0;
+ dstrect.Height = 5.0;
+
+ stat = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitInch, &state1);
+ expect(Ok, stat);
+
+ stat = GdipCreateSolidFill((ARGB)0xff00ffff, (GpSolidFill**)&brush);
+ expect(Ok, stat);
+
+ stat = GdipFillRectangle(graphics, brush, 0.0, 0.0, dpix, dpiy);
+ expect(Ok, stat);
+
+ stat = GdipDeleteBrush(brush);
+ expect(Ok, stat);
+
+ stat = GdipEndContainer(graphics, state1);
+ expect(Ok, stat);
+
+ /* Restoring an invalid state seems to break the graphics object? */
+ if (0) {
+ stat = GdipEndContainer(graphics, state1);
+ expect(Ok, stat);
+ }
+
+ /* Ending metafile with a state open */
+ stat = GdipBeginContainer2(graphics, &state1);
+ expect(Ok, stat);
+
+ stat = GdipDeleteGraphics(graphics);
+ expect(Ok, stat);
+
+ check_metafile(metafile, container_records, "container metafile", dst_points, &frame, UnitPixel);
+
+ sync_metafile(&metafile, "container.emf");
+
+ stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap);
+ expect(Ok, stat);
+
+ stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
+ expect(Ok, stat);
+
+ play_metafile(metafile, graphics, container_records, "container playback", dst_points, &frame, UnitPixel);
+
+ stat = GdipBitmapGetPixel(bitmap, 80, 80, &color);
+ expect(Ok, stat);
+ expect(0, color);
+
+ stat = GdipBitmapGetPixel(bitmap, 12, 12, &color);
+ expect(Ok, stat);
+ expect(0xff000000, color);
+
+ stat = GdipBitmapGetPixel(bitmap, 8, 8, &color);
+ expect(Ok, stat);
+ expect(0xff0000ff, color);
+
+ stat = GdipBitmapGetPixel(bitmap, 42, 42, &color);
+ expect(Ok, stat);
+ expect(0xff00ff00, color);
+
+ stat = GdipBitmapGetPixel(bitmap, 55, 5, &color);
+ expect(Ok, stat);
+ expect(0xff00ffff, color);
+
+ stat = GdipDeleteGraphics(graphics);
+ expect(Ok, stat);
+
+ stat = GdipDisposeImage((GpImage*)bitmap);
+ expect(Ok, stat);
+
+ stat = GdipDisposeImage((GpImage*)metafile);
+ expect(Ok, stat);
+}
+
+static const emfplus_record clipping_records[] = {
+ {0, EMR_HEADER},
+ {0, EmfPlusRecordTypeHeader},
+ {0, EmfPlusRecordTypeSave},
+ {0, EmfPlusRecordTypeSetClipRect},
+ {0, EmfPlusRecordTypeFillRects},
+ {0, EmfPlusRecordTypeRestore},
+ {0, EmfPlusRecordTypeSetClipRect},
+ {0, EmfPlusRecordTypeFillRects},
+ {0, EmfPlusRecordTypeEndOfFile},
+ {0, EMR_EOF},
+ {0}
+};
+
+static void test_clipping(void)
+{
+ GpStatus stat;
+ GpMetafile *metafile;
+ GpGraphics *graphics;
+ GpBitmap *bitmap;
+ GpBrush *brush;
+ ARGB color;
+ HDC hdc;
+ static const GpRectF frame = {0.0, 0.0, 100.0, 100.0};
+ static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}};
+ static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0};
+ GraphicsState state;
+
+ hdc = CreateCompatibleDC(0);
+
+ stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile);
+ expect(Ok, stat);
+
+ DeleteDC(hdc);
+
+ if (stat != Ok)
+ return;
+
+ stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics);
+ expect(Ok, stat);
+
+ stat = GdipSaveGraphics(graphics, &state);
+ expect(Ok, stat);
+
+ stat = GdipSetClipRect(graphics, 30, 30, 10, 10, CombineModeReplace);
+ expect(Ok, stat);
+
+ stat = GdipCreateSolidFill((ARGB)0xff000000, (GpSolidFill**)&brush);
+ expect(Ok, stat);
+
+ stat = GdipFillRectangle(graphics, brush, 0, 0, 100, 100);
+ expect(Ok, stat);
+
+ stat = GdipDeleteBrush(brush);
+ expect(Ok, stat);
+
+ stat = GdipRestoreGraphics(graphics, state);
+ expect(Ok, stat);
+
+ stat = GdipSetClipRect(graphics, 30, 30, 10, 10, CombineModeXor);
+ expect(Ok, stat);
+
+ stat = GdipCreateSolidFill((ARGB)0xff0000ff, (GpSolidFill**)&brush);
+ expect(Ok, stat);
+
+ stat = GdipFillRectangle(graphics, brush, 30, 30, 20, 10);
+ expect(Ok, stat);
+
+ stat = GdipDeleteBrush(brush);
+ expect(Ok, stat);
+
+ stat = GdipDeleteGraphics(graphics);
+ expect(Ok, stat);
+
+ check_metafile(metafile, clipping_records, "clipping metafile", dst_points, &frame, UnitPixel);
+
+ sync_metafile(&metafile, "clipping.emf");
+
+ stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap);
+ expect(Ok, stat);
+
+ stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
+ expect(Ok, stat);
+
+ play_metafile(metafile, graphics, clipping_records, "clipping playback", dst_points, &frame, UnitPixel);
+
+ stat = GdipBitmapGetPixel(bitmap, 80, 80, &color);
+ expect(Ok, stat);
+ expect(0, color);
+
+ stat = GdipBitmapGetPixel(bitmap, 35, 35, &color);
+ expect(Ok, stat);
+ expect(0xff000000, color);
+
+ stat = GdipBitmapGetPixel(bitmap, 45, 35, &color);
+ expect(Ok, stat);
+ expect(0xff0000ff, color);
+
+ stat = GdipDeleteGraphics(graphics);
+ expect(Ok, stat);
+
+ stat = GdipDisposeImage((GpImage*)bitmap);
+ expect(Ok, stat);
+
+ stat = GdipDisposeImage((GpImage*)metafile);
+ expect(Ok, stat);
+}
+
+static void test_gditransform_cb(GpMetafile* metafile, EmfPlusRecordType record_type,
+ unsigned int flags, unsigned int dataSize, const unsigned char *pStr)
+{
+ static const XFORM xform = {0.5, 0, 0, 0.5, 0, 0};
+ static const RECTL rectangle = {0,0,100,100};
+ GpStatus stat;
+
+ stat = GdipPlayMetafileRecord(metafile, EMR_SETWORLDTRANSFORM, 0, sizeof(xform), (void*)&xform);
+ expect(Ok, stat);
+
+ stat = GdipPlayMetafileRecord(metafile, EMR_RECTANGLE, 0, sizeof(rectangle), (void*)&rectangle);
+ expect(Ok, stat);
+}
+
+static const emfplus_record gditransform_records[] = {
+ {0, EMR_HEADER},
+ {0, EMR_CREATEBRUSHINDIRECT},
+ {0, EMR_SELECTOBJECT},
+ {0, EMR_GDICOMMENT, 0, test_gditransform_cb},
+ {0, EMR_SELECTOBJECT},
+ {0, EMR_DELETEOBJECT},
+ {0, EMR_EOF},
+ {0}
+};
+
+static void test_gditransform(void)
+{
+ GpStatus stat;
+ GpMetafile *metafile;
+ GpGraphics *graphics;
+ HDC hdc, metafile_dc;
+ HENHMETAFILE hemf;
+ MetafileHeader header;
+ static const GpRectF frame = {0.0, 0.0, 100.0, 100.0};
+ static const GpPointF dst_points[3] = {{0.0,0.0},{40.0,0.0},{0.0,40.0}};
+ static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0};
+ HBRUSH hbrush, holdbrush;
+ GpBitmap *bitmap;
+ ARGB color;
+
+ hdc = CreateCompatibleDC(0);
+
+ stat = GdipRecordMetafile(hdc, EmfTypeEmfOnly, &frame, MetafileFrameUnitPixel, description, &metafile);
+ expect(Ok, stat);
+
+ DeleteDC(hdc);
+
+ if (stat != Ok)
+ return;
+
+ stat = GdipGetHemfFromMetafile(metafile, &hemf);
+ expect(InvalidParameter, stat);
+
+ memset(&header, 0xaa, sizeof(header));
+ stat = GdipGetMetafileHeaderFromMetafile(metafile, &header);
+ expect(Ok, stat);
+ expect(MetafileTypeEmf, header.Type);
+ ok(header.Version == 0xdbc01001 || header.Version == 0xdbc01002, "Unexpected version %x\n", header.Version);
+
+ stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics);
+ expect(Ok, stat);
+
+ stat = GdipGetDC(graphics, &metafile_dc);
+ expect(Ok, stat);
+
+ if (stat != Ok)
+ {
+ GdipDeleteGraphics(graphics);
+ GdipDisposeImage((GpImage*)metafile);
+ return;
+ }
+
+ hbrush = CreateSolidBrush(0xff);
+
+ holdbrush = SelectObject(metafile_dc, hbrush);
+
+ GdiComment(metafile_dc, 8, (const BYTE*)"winetest");
+
+ SelectObject(metafile_dc, holdbrush);
+
+ DeleteObject(hbrush);
+
+ stat = GdipReleaseDC(graphics, metafile_dc);
+ expect(Ok, stat);
+
+ stat = GdipDeleteGraphics(graphics);
+ expect(Ok, stat);
+
+ check_metafile(metafile, gditransform_records, "gditransform metafile", dst_points, &frame, UnitPixel);
+
+ sync_metafile(&metafile, "gditransform.emf");
+
+ stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap);
+ expect(Ok, stat);
+
+ stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
+ expect(Ok, stat);
+
+ play_metafile(metafile, graphics, gditransform_records, "gditransform playback", dst_points, &frame, UnitPixel);
+
+ stat = GdipBitmapGetPixel(bitmap, 10, 10, &color);
+ expect(Ok, stat);
+ expect(0xffff0000, color);
+
+ stat = GdipBitmapGetPixel(bitmap, 30, 30, &color);
+ expect(Ok, stat);
+ expect(0x00000000, color);
+
+ stat = GdipDeleteGraphics(graphics);
+ expect(Ok, stat);
+
+ stat = GdipDisposeImage((GpImage*)bitmap);
+ expect(Ok, stat);
+
+ stat = GdipDisposeImage((GpImage*)metafile);
+ expect(Ok, stat);
+}
+
+START_TEST(metafile)
+{
+ struct GdiplusStartupInput gdiplusStartupInput;
+ ULONG_PTR gdiplusToken;
+ int myARGC;
+ char **myARGV;
+
+ gdiplusStartupInput.GdiplusVersion = 1;
+ gdiplusStartupInput.DebugEventCallback = NULL;
+ gdiplusStartupInput.SuppressBackgroundThread = 0;