diff --git a/rostests/winetests/gdiplus/graphics.c b/rostests/winetests/gdiplus/graphics.c index 7d308d77fff..1ba522ea78a 100644 --- a/rostests/winetests/gdiplus/graphics.c +++ b/rostests/winetests/gdiplus/graphics.c @@ -332,6 +332,64 @@ static void test_save_restore(void) log_state(state_a, &state_log); + /* A state created by SaveGraphics cannot be restored with EndContainer. */ + GdipCreateFromHDC(hdc, &graphics1); + GdipSetInterpolationMode(graphics1, InterpolationModeBilinear); + stat = GdipSaveGraphics(graphics1, &state_a); + expect(Ok, stat); + GdipSetInterpolationMode(graphics1, InterpolationModeBicubic); + stat = GdipEndContainer(graphics1, state_a); + expect(Ok, stat); + GdipGetInterpolationMode(graphics1, &mode); + expect(InterpolationModeBicubic, mode); + stat = GdipRestoreGraphics(graphics1, state_a); + expect(Ok, stat); + GdipGetInterpolationMode(graphics1, &mode); + expect(InterpolationModeBilinear, mode); + GdipDeleteGraphics(graphics1); + + log_state(state_a, &state_log); + + /* A state created by BeginContainer cannot be restored with RestoreGraphics. */ + GdipCreateFromHDC(hdc, &graphics1); + GdipSetInterpolationMode(graphics1, InterpolationModeBilinear); + stat = GdipBeginContainer2(graphics1, &state_a); + expect(Ok, stat); + GdipSetInterpolationMode(graphics1, InterpolationModeBicubic); + stat = GdipRestoreGraphics(graphics1, state_a); + expect(Ok, stat); + GdipGetInterpolationMode(graphics1, &mode); + expect(InterpolationModeBicubic, mode); + stat = GdipEndContainer(graphics1, state_a); + expect(Ok, stat); + GdipGetInterpolationMode(graphics1, &mode); + expect(InterpolationModeBilinear, mode); + GdipDeleteGraphics(graphics1); + + log_state(state_a, &state_log); + + /* BeginContainer and SaveGraphics use the same stack. */ + GdipCreateFromHDC(hdc, &graphics1); + GdipSetInterpolationMode(graphics1, InterpolationModeBilinear); + stat = GdipBeginContainer2(graphics1, &state_a); + expect(Ok, stat); + GdipSetInterpolationMode(graphics1, InterpolationModeBicubic); + stat = GdipSaveGraphics(graphics1, &state_b); + expect(Ok, stat); + GdipSetInterpolationMode(graphics1, InterpolationModeNearestNeighbor); + stat = GdipEndContainer(graphics1, state_a); + expect(Ok, stat); + GdipGetInterpolationMode(graphics1, &mode); + expect(InterpolationModeBilinear, mode); + stat = GdipRestoreGraphics(graphics1, state_b); + expect(Ok, stat); + GdipGetInterpolationMode(graphics1, &mode); + expect(InterpolationModeBilinear, mode); + GdipDeleteGraphics(graphics1); + + log_state(state_a, &state_log); + log_state(state_b, &state_log); + /* The same state value should never be returned twice. */ todo_wine check_no_duplicates(state_log); @@ -3847,15 +3905,18 @@ static void test_pen_thickness(void) REAL res_x, res_y, scale; GpUnit pen_unit, page_unit; REAL pen_width; - INT cx, cy; + INT cx, cy, path_cx, path_cy; } td[] = { - { 10.0, 10.0, 1.0, UnitPixel, UnitPixel, 1.0, 1, 1 }, - { 10.0, 10.0, 3.0, UnitPixel, UnitPixel, 2.0, 2, 2 }, - { 10.0, 10.0, 30.0, UnitPixel, UnitInch, 1.0, 1, 1 }, - { 10.0, 10.0, 1.0, UnitWorld, UnitPixel, 1.0, 1, 1 }, - { 10.0, 10.0, 3.0, UnitWorld, UnitPixel, 2.0, 6, 6 }, - { 10.0, 10.0, 2.0, UnitWorld, UnitInch, 1.0, 20, 20 }, + { 10.0, 10.0, 1.0, UnitPixel, UnitPixel, 1.0, 1, 1, 1, 1 }, + { 10.0, 10.0, 1.0, UnitPixel, UnitPixel, 0.0, 0, 0, 1, 1 }, + { 10.0, 10.0, 1.0, UnitPixel, UnitPixel, 0.1, 1, 1, 1, 1 }, + { 10.0, 10.0, 3.0, UnitPixel, UnitPixel, 2.0, 2, 2, 2, 2 }, + { 10.0, 10.0, 30.0, UnitPixel, UnitInch, 1.0, 1, 1, 1, 1 }, + { 10.0, 10.0, 1.0, UnitWorld, UnitPixel, 1.0, 1, 1, 1, 1 }, + { 10.0, 10.0, 1.0, UnitWorld, UnitPixel, 0.0, 1, 1, 1, 1 }, + { 10.0, 10.0, 3.0, UnitWorld, UnitPixel, 2.0, 6, 6, 6, 6 }, + { 10.0, 10.0, 2.0, UnitWorld, UnitInch, 1.0, 20, 20, 20, 20 }, }; GpStatus status; int i, j; @@ -3867,6 +3928,7 @@ static void test_pen_thickness(void) } u; GpPen *pen; GpPointF corner; + GpPath *path; BitmapData bd; INT min, max, size; @@ -3956,6 +4018,82 @@ static void test_pen_thickness(void) status = GdipBitmapUnlockBits(u.bitmap, &bd); expect(Ok, status); + status = GdipGraphicsClear(graphics, 0xff000000); + expect(Ok, status); + + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + + status = GdipAddPathLine(path, corner.X/2, 0, corner.X/2, corner.Y); + expect(Ok, status); + + status = GdipClosePathFigure(path); + expect(Ok, status); + + status = GdipAddPathLine(path, 0, corner.Y/2, corner.X, corner.Y/2); + expect(Ok, status); + + status = GdipDrawPath(graphics, pen, path); + expect(Ok, status); + + GdipDeletePath(path); + + status = GdipBitmapLockBits(u.bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB, &bd); + expect(Ok, status); + + min = -1; + max = -2; + + for (j=0; j<100; j++) + { + if (((BYTE*)bd.Scan0)[j*3] == 0xff) + { + min = j; + break; + } + } + + for (j=99; j>=0; j--) + { + if (((BYTE*)bd.Scan0)[j*3] == 0xff) + { + max = j; + break; + } + } + + size = max-min+1; + + ok(size == td[i].path_cx, "%u: expected %d, got %d\n", i, td[i].path_cx, size); + + min = -1; + max = -2; + + for (j=0; j<100; j++) + { + if (((BYTE*)bd.Scan0)[bd.Stride*j] == 0xff) + { + min = j; + break; + } + } + + for (j=99; j>=0; j--) + { + if (((BYTE*)bd.Scan0)[bd.Stride*j] == 0xff) + { + max = j; + break; + } + } + + size = max-min+1; + + ok(size == td[i].path_cy, "%u: expected %d, got %d\n", i, td[i].path_cy, size); + + status = GdipBitmapUnlockBits(u.bitmap, &bd); + expect(Ok, status); + GdipDeletePen(pen); GdipDeleteGraphics(graphics); GdipDisposeImage(u.image); @@ -5845,6 +5983,178 @@ static void test_GdipGetVisibleClipBounds_memoryDC(void) ReleaseDC(hwnd, dc); } +static void test_container_rects(void) +{ + GpStatus status; + GpGraphics *graphics; + HDC hdc = GetDC( hwnd ); + GpRectF dstrect, srcrect; + GraphicsContainer state; + static const GpPointF test_points[3] = {{0.0,0.0}, {1.0,0.0}, {0.0,1.0}}; + GpPointF points[3]; + REAL dpix, dpiy; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + dstrect.X = 0.0; + dstrect.Y = 0.0; + dstrect.Width = 1.0; + dstrect.Height = 1.0; + srcrect = dstrect; + + status = GdipGetDpiX(graphics, &dpix); + expect(Ok, status); + + status = GdipGetDpiY(graphics, &dpiy); + expect(Ok, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitWorld, &state); + expect(InvalidParameter, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitDisplay, &state); + expect(InvalidParameter, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitMillimeter+1, &state); + expect(InvalidParameter, status); + + status = GdipBeginContainer(NULL, &dstrect, &srcrect, UnitPixel, &state); + expect(InvalidParameter, status); + + status = GdipBeginContainer(graphics, NULL, &srcrect, UnitPixel, &state); + expect(InvalidParameter, status); + + status = GdipBeginContainer(graphics, &dstrect, NULL, UnitPixel, &state); + expect(InvalidParameter, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, -1, &state); + expect(InvalidParameter, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitPixel, NULL); + expect(InvalidParameter, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitPixel, &state); + expect(Ok, status); + + memcpy(points, test_points, sizeof(points)); + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, points, 3); + expect(Ok, status); + expectf(0.0, points[0].X); + expectf(0.0, points[0].Y); + expectf(1.0, points[1].X); + expectf(0.0, points[1].Y); + expectf(0.0, points[2].X); + expectf(1.0, points[2].Y); + + status = GdipEndContainer(graphics, state); + expect(Ok, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitInch, &state); + expect(Ok, status); + + memcpy(points, test_points, sizeof(points)); + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, points, 3); + expect(Ok, status); + expectf(0.0, points[0].X); + expectf(0.0, points[0].Y); + expectf(1.0/dpix, points[1].X); + expectf(0.0, points[1].Y); + expectf(0.0, points[2].X); + expectf(1.0/dpiy, points[2].Y); + + status = GdipEndContainer(graphics, state); + expect(Ok, status); + + status = GdipScaleWorldTransform(graphics, 2.0, 2.0, MatrixOrderPrepend); + expect(Ok, status); + + dstrect.X = 1.0; + dstrect.Height = 3.0; + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitPixel, &state); + expect(Ok, status); + + memcpy(points, test_points, sizeof(points)); + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, points, 3); + expect(Ok, status); + expectf(2.0, points[0].X); + expectf(0.0, points[0].Y); + expectf(4.0, points[1].X); + expectf(0.0, points[1].Y); + expectf(2.0, points[2].X); + expectf(6.0, points[2].Y); + + status = GdipEndContainer(graphics, state); + expect(Ok, status); + + memcpy(points, test_points, sizeof(points)); + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, points, 3); + expect(Ok, status); + expectf(0.0, points[0].X); + expectf(0.0, points[0].Y); + expectf(2.0, points[1].X); + expectf(0.0, points[1].Y); + expectf(0.0, points[2].X); + expectf(2.0, points[2].Y); + + status = GdipResetWorldTransform(graphics); + expect(Ok, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitInch, &state); + expect(Ok, status); + + memcpy(points, test_points, sizeof(points)); + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, points, 3); + expect(Ok, status); + expectf(1.0, points[0].X); + expectf(0.0, points[0].Y); + expectf((dpix+1.0)/dpix, points[1].X); + expectf(0.0, points[1].Y); + expectf(1.0, points[2].X); + expectf(3.0/dpiy, points[2].Y); + + status = GdipEndContainer(graphics, state); + expect(Ok, status); + + status = GdipSetPageUnit(graphics, UnitInch); + expect(Ok, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitPixel, &state); + expect(Ok, status); + + memcpy(points, test_points, sizeof(points)); + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, points, 3); + expect(Ok, status); + expectf(dpix, points[0].X); + expectf(0.0, points[0].Y); + expectf(dpix*2, points[1].X); + expectf(0.0, points[1].Y); + expectf(dpix, points[2].X); + expectf(dpiy*3, points[2].Y); + + status = GdipEndContainer(graphics, state); + expect(Ok, status); + + status = GdipBeginContainer(graphics, &dstrect, &srcrect, UnitInch, &state); + expect(Ok, status); + + memcpy(points, test_points, sizeof(points)); + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, points, 3); + expect(Ok, status); + expectf(dpix, points[0].X); + expectf(0.0, points[0].Y); + expectf(dpix+1.0, points[1].X); + expectf(0.0, points[1].Y); + expectf(dpix, points[2].X); + expectf(3.0, points[2].Y); + + status = GdipEndContainer(graphics, state); + expect(Ok, status); + + GdipDeleteGraphics(graphics); + + ReleaseDC(hwnd, hdc); +} + START_TEST(graphics) { struct GdiplusStartupInput gdiplusStartupInput; @@ -5918,6 +6228,7 @@ START_TEST(graphics) test_bitmapfromgraphics(); test_GdipFillRectangles(); test_GdipGetVisibleClipBounds_memoryDC(); + test_container_rects(); GdiplusShutdown(gdiplusToken); DestroyWindow( hwnd ); diff --git a/rostests/winetests/gdiplus/graphicspath.c b/rostests/winetests/gdiplus/graphicspath.c index c28c6278b5d..25aea41b0bb 100644 --- a/rostests/winetests/gdiplus/graphicspath.c +++ b/rostests/winetests/gdiplus/graphicspath.c @@ -1077,6 +1077,7 @@ static void test_widen(void) GpPath *path; GpPen *pen; GpMatrix *m; + INT count=-1; status = GdipCreatePath(FillModeAlternate, &path); expect(Ok, status); @@ -1201,6 +1202,23 @@ static void test_widen(void) expect(Ok, status); ok_path(path, widenline_path, sizeof(widenline_path)/sizeof(path_test_t), FALSE); + /* pen width = 0 pixels - native fails to widen but can draw with this pen */ + GdipDeletePen(pen); + status = GdipCreatePen1(0xffffffff, 0.0, UnitPixel, &pen); + expect(Ok, status); + + status = GdipResetPath(path); + expect(Ok, status); + status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); + expect(Ok, status); + + status = GdipWidenPath(path, pen, m, 1.0); + expect(Ok, status); + + status = GdipGetPointCount(path, &count); + expect(Ok, status); + todo_wine expect(0, count); + GdipDeleteMatrix(m); GdipDeletePen(pen); GdipDeletePath(path); diff --git a/rostests/winetests/gdiplus/image.c b/rostests/winetests/gdiplus/image.c index d0ebea8ac16..60b8111008d 100644 --- a/rostests/winetests/gdiplus/image.c +++ b/rostests/winetests/gdiplus/image.c @@ -50,6 +50,12 @@ DEFINE_GUID(ColorBalanceEffectGuid, 0x537e597d, 0x251e, 0x48da, 0x96, 0x64, 0x29 DEFINE_GUID(RedEyeCorrectionEffectGuid, 0x74d29d05, 0x69a4, 0x4266, 0x95, 0x49, 0x3c, 0xc5, 0x28, 0x36, 0xb6, 0x32); DEFINE_GUID(ColorCurveEffectGuid, 0xdd6a0022, 0x58e4, 0x4a67, 0x9d, 0x9b, 0xd4, 0x8e, 0xb8, 0x81, 0xa5, 0x3d); +static GpStatus (WINAPI *pGdipBitmapGetHistogramSize)(HistogramFormat,UINT*); +static GpStatus (WINAPI *pGdipBitmapGetHistogram)(GpBitmap*,HistogramFormat,UINT,UINT*,UINT*,UINT*,UINT*); +static GpStatus (WINAPI *pGdipImageSetAbort)(GpImage*,GdiplusAbort*); + +static GpStatus (WINGDIPAPI *pGdipInitializePalette)(ColorPalette*,PaletteType,INT,BOOL,GpBitmap*); + #define expect(expected, got) ok((got) == (expected), "Expected %d, got %d\n", (UINT)(expected), (UINT)(got)) #define expectf(expected, got) ok(fabs((expected) - (got)) < 0.0001, "Expected %f, got %f\n", (expected), (got)) @@ -4657,14 +4663,13 @@ static void test_supported_encoders(void) { LPCWSTR mime; const GUID *format; - BOOL todo; } td[] = { - { bmp_mimetype, &ImageFormatBMP, FALSE }, - { jpeg_mimetype, &ImageFormatJPEG, FALSE }, - { gif_mimetype, &ImageFormatGIF, TRUE }, - { tiff_mimetype, &ImageFormatTIFF, FALSE }, - { png_mimetype, &ImageFormatPNG, FALSE } + { bmp_mimetype, &ImageFormatBMP }, + { jpeg_mimetype, &ImageFormatJPEG }, + { gif_mimetype, &ImageFormatGIF }, + { tiff_mimetype, &ImageFormatTIFF }, + { png_mimetype, &ImageFormatPNG } }; GUID format, clsid; BOOL ret; @@ -4690,8 +4695,7 @@ static void test_supported_encoders(void) ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr); status = GdipSaveImageToStream((GpImage *)bm, stream, &clsid, NULL); - todo_wine_if (td[i].todo) - ok(status == Ok, "GdipSaveImageToStream error %d\n", status); + ok(status == Ok, "GdipSaveImageToStream error %d\n", status); IStream_Release(stream); } @@ -4805,6 +4809,158 @@ static void test_getadjustedpalette(void) GdipDisposeImageAttributes(imageattributes); } +static void test_histogram(void) +{ + UINT ch0[256], ch1[256], ch2[256], ch3[256]; + HistogramFormat test_formats[] = + { + HistogramFormatARGB, + HistogramFormatPARGB, + HistogramFormatRGB, + HistogramFormatGray, + HistogramFormatB, + HistogramFormatG, + HistogramFormatR, + HistogramFormatA, + }; + const UINT WIDTH = 8, HEIGHT = 16; + UINT num, i, x; + GpStatus stat; + GpBitmap *bm; + + if (!pGdipBitmapGetHistogramSize) + { + win_skip("GdipBitmapGetHistogramSize is not supported\n"); + return; + } + + stat = pGdipBitmapGetHistogramSize(HistogramFormatARGB, NULL); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogramSize(0xff, NULL); + expect(InvalidParameter, stat); + + num = 123; + stat = pGdipBitmapGetHistogramSize(10, &num); + expect(Ok, stat); + expect(256, num); + + for (i = 0; i < sizeof(test_formats)/sizeof(test_formats[0]); i++) + { + num = 0; + stat = pGdipBitmapGetHistogramSize(test_formats[i], &num); + expect(Ok, stat); + expect(256, num); + } + + bm = NULL; + stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm); + expect(Ok, stat); + + /* Three solid rgb rows, next three rows are rgb shades. */ + for (x = 0; x < WIDTH; x++) + { + GdipBitmapSetPixel(bm, x, 0, 0xffff0000); + GdipBitmapSetPixel(bm, x, 1, 0xff00ff00); + GdipBitmapSetPixel(bm, x, 2, 0xff0000ff); + + GdipBitmapSetPixel(bm, x, 3, 0xff010000); + GdipBitmapSetPixel(bm, x, 4, 0xff003f00); + GdipBitmapSetPixel(bm, x, 5, 0xff000020); + } + + stat = pGdipBitmapGetHistogram(NULL, HistogramFormatRGB, 256, ch0, ch1, ch2, ch3); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, ch2, ch3); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, ch2, NULL); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, NULL, NULL); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, NULL, NULL, NULL); + expect(InvalidParameter, stat); + + /* Requested format matches bitmap format */ + stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 256, ch0, ch1, ch2, ch3); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 100, ch0, ch1, ch2, NULL); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 257, ch0, ch1, ch2, NULL); + expect(InvalidParameter, stat); + + /* Channel 3 is not used, must be NULL */ + stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 256, ch0, ch1, ch2, NULL); + expect(Ok, stat); + + ok(ch0[0xff] == WIDTH, "Got red (0xff) %u\n", ch0[0xff]); + ok(ch1[0xff] == WIDTH, "Got green (0xff) %u\n", ch1[0xff]); + ok(ch2[0xff] == WIDTH, "Got blue (0xff) %u\n", ch1[0xff]); + ok(ch0[0x01] == WIDTH, "Got red (0x01) %u\n", ch0[0x01]); + ok(ch1[0x3f] == WIDTH, "Got green (0x3f) %u\n", ch1[0x3f]); + ok(ch2[0x20] == WIDTH, "Got blue (0x20) %u\n", ch1[0x20]); + + /* ARGB histogram from RGB data. */ + stat = pGdipBitmapGetHistogram(bm, HistogramFormatARGB, 256, ch0, ch1, ch2, NULL); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, HistogramFormatARGB, 256, ch0, ch1, ch2, ch3); + expect(Ok, stat); + + ok(ch1[0xff] == WIDTH, "Got red (0xff) %u\n", ch1[0xff]); + ok(ch2[0xff] == WIDTH, "Got green (0xff) %u\n", ch2[0xff]); + ok(ch3[0xff] == WIDTH, "Got blue (0xff) %u\n", ch3[0xff]); + ok(ch1[0x01] == WIDTH, "Got red (0x01) %u\n", ch1[0x01]); + ok(ch2[0x3f] == WIDTH, "Got green (0x3f) %u\n", ch2[0x3f]); + ok(ch3[0x20] == WIDTH, "Got blue (0x20) %u\n", ch3[0x20]); + + ok(ch0[0xff] == WIDTH * HEIGHT, "Got alpha (0xff) %u\n", ch0[0xff]); + + /* Request grayscale histogram from RGB bitmap. */ + stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, ch2, ch3); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, ch2, NULL); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, NULL, NULL); + expect(InvalidParameter, stat); + + stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, NULL, NULL, NULL); + expect(Ok, stat); + + GdipDisposeImage((GpImage*)bm); +} + +static void test_imageabort(void) +{ + GpStatus stat; + GpBitmap *bm; + + if (!pGdipImageSetAbort) + { + win_skip("GdipImageSetAbort() is not supported.\n"); + return; + } + + bm = NULL; + stat = GdipCreateBitmapFromScan0(8, 8, 0, PixelFormat24bppRGB, NULL, &bm); + expect(Ok, stat); + + stat = pGdipImageSetAbort(NULL, NULL); + expect(InvalidParameter, stat); + + stat = pGdipImageSetAbort((GpImage*)bm, NULL); + expect(Ok, stat); + + GdipDisposeImage((GpImage*)bm); +} + /* RGB 24 bpp 1x1 pixel PNG image */ static const char png_1x1_data[] = { 0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a, @@ -4869,8 +5025,152 @@ static void test_png_color_formats(void) } } +static BYTE *init_bitmap(UINT *width, UINT *height, UINT *stride) +{ + BYTE *src; + UINT i, j, scale; + + *width = 256; + *height = 256; + *stride = (*width * 3 + 3) & ~3; + trace("width %d, height %d, stride %d\n", *width, *height, *stride); + + src = HeapAlloc(GetProcessHeap(), 0, *stride * *height); + + scale = 256 / *width; + if (!scale) scale = 1; + + for (i = 0; i < *height; i++) + { + for (j = 0; j < *width; j++) + { + src[i * *stride + j*3 + 0] = scale * i; + src[i * *stride + j*3 + 1] = scale * (255 - (i+j)/2); + src[i * *stride + j*3 + 2] = scale * j; + } + } + + return src; +} + +static void test_GdipInitializePalette(void) +{ + GpStatus status; + BYTE *data; + GpBitmap *bitmap; + ColorPalette *palette; + UINT width, height, stride; + + pGdipInitializePalette = (void *)GetProcAddress(GetModuleHandleA("gdiplus.dll"), "GdipInitializePalette"); + if (!pGdipInitializePalette) + { + win_skip("GdipInitializePalette is not supported on this platform\n"); + return; + } + + data = init_bitmap(&width, &height, &stride); + + status = GdipCreateBitmapFromScan0(width, height, stride, PixelFormat24bppRGB, data, &bitmap); + expect(Ok, status); + + palette = GdipAlloc(sizeof(*palette) + sizeof(ARGB) * 255); + + palette->Flags = 0; + palette->Count = 15; + status = pGdipInitializePalette(palette, PaletteTypeOptimal, 16, FALSE, bitmap); + expect(GenericError, status); + + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeOptimal, 16, FALSE, NULL); + expect(InvalidParameter, status); + + memset(palette->Entries, 0x11, sizeof(ARGB) * 256); + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeCustom, 16, FALSE, NULL); + expect(Ok, status); + expect(0, palette->Flags); + expect(256, palette->Count); + expect(0x11111111, palette->Entries[0]); + expect(0x11111111, palette->Entries[128]); + expect(0x11111111, palette->Entries[255]); + + memset(palette->Entries, 0x11, sizeof(ARGB) * 256); + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeFixedBW, 0, FALSE, bitmap); + expect(Ok, status); +todo_wine + expect(0x200, palette->Flags); + expect(2, palette->Count); + expect(0xff000000, palette->Entries[0]); + expect(0xffffffff, palette->Entries[1]); + + memset(palette->Entries, 0x11, sizeof(ARGB) * 256); + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone8, 1, FALSE, NULL); + expect(Ok, status); +todo_wine + expect(0x300, palette->Flags); + expect(16, palette->Count); + expect(0xff000000, palette->Entries[0]); + expect(0xffc0c0c0, palette->Entries[8]); + expect(0xff008080, palette->Entries[15]); + + memset(palette->Entries, 0x11, sizeof(ARGB) * 256); + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone8, 1, FALSE, bitmap); + expect(Ok, status); +todo_wine + expect(0x300, palette->Flags); + expect(16, palette->Count); + expect(0xff000000, palette->Entries[0]); + expect(0xffc0c0c0, palette->Entries[8]); + expect(0xff008080, palette->Entries[15]); + + memset(palette->Entries, 0x11, sizeof(ARGB) * 256); + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone252, 1, FALSE, bitmap); + expect(Ok, status); +todo_wine + expect(0x800, palette->Flags); + expect(252, palette->Count); + expect(0xff000000, palette->Entries[0]); + expect(0xff990066, palette->Entries[128]); + expect(0xffffffff, palette->Entries[251]); + + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeOptimal, 1, FALSE, bitmap); + expect(InvalidParameter, status); + + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeOptimal, 2, FALSE, bitmap); + expect(Ok, status); + expect(0, palette->Flags); + expect(2, palette->Count); + + palette->Flags = 0; + palette->Count = 256; + status = pGdipInitializePalette(palette, PaletteTypeOptimal, 16, FALSE, bitmap); + expect(Ok, status); + expect(0, palette->Flags); + expect(16, palette->Count); + + /* passing invalid enumeration palette type crashes under most Windows versions */ + + GdipFree(palette); + GdipDisposeImage((GpImage *)bitmap); +} + START_TEST(image) { + HMODULE mod = GetModuleHandleA("gdiplus.dll"); struct GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; @@ -4881,6 +5181,11 @@ START_TEST(image) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + pGdipBitmapGetHistogramSize = (void*)GetProcAddress(mod, "GdipBitmapGetHistogramSize"); + pGdipBitmapGetHistogram = (void*)GetProcAddress(mod, "GdipBitmapGetHistogram"); + pGdipImageSetAbort = (void*)GetProcAddress(mod, "GdipImageSetAbort"); + + test_GdipInitializePalette(); test_png_color_formats(); test_supported_encoders(); test_CloneBitmapArea(); @@ -4928,6 +5233,8 @@ START_TEST(image) test_dispose(); test_createeffect(); test_getadjustedpalette(); + test_histogram(); + test_imageabort(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/matrix.c b/rostests/winetests/gdiplus/matrix.c index db7551b0b66..be82f185a44 100644 --- a/rostests/winetests/gdiplus/matrix.c +++ b/rostests/winetests/gdiplus/matrix.c @@ -309,7 +309,42 @@ static void test_constructor3(void) expectf(0.0, values[4]); expectf(0.0, values[5]); - GdipDeleteMatrix(matrix);} + GdipDeleteMatrix(matrix); +} + +static void test_isidentity(void) +{ + GpMatrix *matrix; + GpStatus stat; + BOOL result; + + stat = GdipIsMatrixIdentity(NULL, NULL); + expect(InvalidParameter, stat); + + stat = GdipIsMatrixIdentity(NULL, &result); + expect(InvalidParameter, stat); + + stat = GdipCreateMatrix2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, &matrix); + expect(Ok, stat); + + stat = GdipIsMatrixIdentity(matrix, NULL); + expect(InvalidParameter, stat); + + result = FALSE; + stat = GdipIsMatrixIdentity(matrix, &result); + expect(Ok, stat); + ok(!!result, "got %d\n", result); + + stat = GdipSetMatrixElements(matrix, 1.0, 0.0, 0.0, 1.0, 0.1, 0.0); + expect(Ok, stat); + + result = TRUE; + stat = GdipIsMatrixIdentity(matrix, &result); + expect(Ok, stat); + ok(!result, "got %d\n", result); + + GdipDeleteMatrix(matrix); +} START_TEST(matrix) { @@ -329,6 +364,7 @@ START_TEST(matrix) test_invert(); test_shear(); test_constructor3(); + test_isidentity(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/metafile.c b/rostests/winetests/gdiplus/metafile.c index c268d9efa8f..b5351ef2339 100644 --- a/rostests/winetests/gdiplus/metafile.c +++ b/rostests/winetests/gdiplus/metafile.c @@ -34,12 +34,15 @@ #define expectf(expected, got) expectf_((expected), (got), 0.001) static BOOL save_metafiles; +static BOOL load_metafiles; typedef struct emfplus_record { BOOL todo; ULONG record_type; BOOL playback_todo; + void (*playback_fn)(GpMetafile* metafile, EmfPlusRecordType record_type, + unsigned int flags, unsigned int dataSize, const unsigned char *pStr); } emfplus_record; typedef struct emfplus_check_state @@ -209,18 +212,29 @@ static BOOL CALLBACK play_metafile_proc(EmfPlusRecordType record_type, unsigned emfplus_check_state *state = (emfplus_check_state*)userdata; GpStatus stat; - stat = GdipPlayMetafileRecord(state->metafile, record_type, flags, dataSize, pStr); - if (state->expected[state->count].record_type) { - todo_wine_if (state->expected[state->count].playback_todo) - ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat); + BOOL match = (state->expected[state->count].record_type == record_type); + + if (match && state->expected[state->count].playback_fn) + state->expected[state->count].playback_fn(state->metafile, record_type, flags, dataSize, pStr); + else + { + stat = GdipPlayMetafileRecord(state->metafile, record_type, flags, dataSize, pStr); + todo_wine_if (state->expected[state->count].playback_todo) + ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat); + } + + todo_wine_if (state->expected[state->count].todo) + ok(state->expected[state->count].record_type == record_type, + "%s.%i: expected record type 0x%x, got 0x%x\n", state->desc, state->count, + state->expected[state->count].record_type, record_type); state->count++; } else { todo_wine_if (state->expected[state->count].playback_todo) - ok(0, "%s: too many records\n", state->desc); + ok(0, "%s: unexpected record 0x%x\n", state->desc, record_type); return FALSE; } @@ -244,15 +258,17 @@ static void play_metafile(GpMetafile *metafile, GpGraphics *graphics, const emfp expect(Ok, stat); } -static void save_metafile(GpMetafile *metafile, const char *filename) +/* When 'save' or 'load' is specified on the command line, save or + * load the specified filename. */ +static void sync_metafile(GpMetafile **metafile, const char *filename) { + GpStatus stat; if (save_metafiles) { GpMetafile *clone; HENHMETAFILE hemf; - GpStatus stat; - stat = GdipCloneImage((GpImage*)metafile, (GpImage**)&clone); + stat = GdipCloneImage((GpImage*)*metafile, (GpImage**)&clone); expect(Ok, stat); stat = GdipGetHemfFromMetafile(clone, &hemf); @@ -265,6 +281,20 @@ static void save_metafile(GpMetafile *metafile, const char *filename) stat = GdipDisposeImage((GpImage*)clone); expect(Ok, stat); } + else if (load_metafiles) + { + HENHMETAFILE hemf; + + stat = GdipDisposeImage((GpImage*)*metafile); + expect(Ok, stat); + *metafile = NULL; + + hemf = GetEnhMetaFileA(filename); + ok(hemf != NULL, "%s could not be opened\n", filename); + + stat = GdipCreateMetafileFromEmf(hemf, TRUE, metafile); + expect(Ok, stat); + } } static const emfplus_record empty_records[] = { @@ -332,7 +362,7 @@ static void test_empty(void) check_metafile(metafile, empty_records, "empty metafile", dst_points, &frame, UnitPixel); - save_metafile(metafile, "empty.emf"); + sync_metafile(&metafile, "empty.emf"); stat = GdipGetImageBounds((GpImage*)metafile, &bounds, &unit); expect(Ok, stat); @@ -348,6 +378,34 @@ static void test_empty(void) stat = GdipGetImageVerticalResolution((GpImage*)metafile, &yres); expect(Ok, stat); + memset(&header, 0xaa, sizeof(header)); + stat = GdipGetMetafileHeaderFromMetafile(metafile, &header); + expect(Ok, stat); + expect(MetafileTypeEmfPlusOnly, header.Type); + expect(U(header).EmfHeader.nBytes, header.Size); + ok(header.Version == 0xdbc01001 || header.Version == 0xdbc01002, "Unexpected version %x\n", header.Version); + expect(1, header.EmfPlusFlags); /* reference device was display, not printer */ + expectf(xres, header.DpiX); + expectf(xres, U(header).EmfHeader.szlDevice.cx / (REAL)U(header).EmfHeader.szlMillimeters.cx * 25.4); + expectf(yres, header.DpiY); + expectf(yres, U(header).EmfHeader.szlDevice.cy / (REAL)U(header).EmfHeader.szlMillimeters.cy * 25.4); + expect(0, header.X); + expect(0, header.Y); + expect(100, header.Width); + expect(100, header.Height); + expect(28, header.EmfPlusHeaderSize); + expect(96, header.LogicalDpiX); + expect(96, header.LogicalDpiX); + expect(EMR_HEADER, U(header).EmfHeader.iType); + expect(0, U(header).EmfHeader.rclBounds.left); + expect(0, U(header).EmfHeader.rclBounds.top); + expect(-1, U(header).EmfHeader.rclBounds.right); + expect(-1, U(header).EmfHeader.rclBounds.bottom); + expect(0, U(header).EmfHeader.rclFrame.left); + expect(0, U(header).EmfHeader.rclFrame.top); + expectf_(100.0, U(header).EmfHeader.rclFrame.right * xres / 2540.0, 2.0); + expectf_(100.0, U(header).EmfHeader.rclFrame.bottom * yres / 2540.0, 2.0); + stat = GdipGetHemfFromMetafile(metafile, &hemf); expect(Ok, stat); @@ -406,6 +464,34 @@ static void test_empty(void) expect(Ok, stat); expectf(header.DpiY, yres); + memset(&header, 0xaa, sizeof(header)); + stat = GdipGetMetafileHeaderFromMetafile(metafile, &header); + expect(Ok, stat); + expect(MetafileTypeEmfPlusOnly, header.Type); + expect(U(header).EmfHeader.nBytes, header.Size); + ok(header.Version == 0xdbc01001 || header.Version == 0xdbc01002, "Unexpected version %x\n", header.Version); + expect(1, header.EmfPlusFlags); /* reference device was display, not printer */ + expectf(xres, header.DpiX); + expectf(xres, U(header).EmfHeader.szlDevice.cx / (REAL)U(header).EmfHeader.szlMillimeters.cx * 25.4); + expectf(yres, header.DpiY); + expectf(yres, U(header).EmfHeader.szlDevice.cy / (REAL)U(header).EmfHeader.szlMillimeters.cy * 25.4); + expect(0, header.X); + expect(0, header.Y); + expect(100, header.Width); + expect(100, header.Height); + expect(28, header.EmfPlusHeaderSize); + expect(96, header.LogicalDpiX); + expect(96, header.LogicalDpiX); + expect(EMR_HEADER, U(header).EmfHeader.iType); + expect(0, U(header).EmfHeader.rclBounds.left); + expect(0, U(header).EmfHeader.rclBounds.top); + expect(-1, U(header).EmfHeader.rclBounds.right); + expect(-1, U(header).EmfHeader.rclBounds.bottom); + expect(0, U(header).EmfHeader.rclFrame.left); + expect(0, U(header).EmfHeader.rclFrame.top); + expectf_(100.0, U(header).EmfHeader.rclFrame.right * xres / 2540.0, 2.0); + expectf_(100.0, U(header).EmfHeader.rclFrame.bottom * yres / 2540.0, 2.0); + stat = GdipDisposeImage((GpImage*)metafile); expect(Ok, stat); } @@ -484,7 +570,7 @@ static void test_getdc(void) check_metafile(metafile, getdc_records, "getdc metafile", dst_points, &frame, UnitPixel); - save_metafile(metafile, "getdc.emf"); + sync_metafile(&metafile, "getdc.emf"); stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); expect(Ok, stat); @@ -591,6 +677,13 @@ static void test_emfonly(void) 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); + /* The rest is zeroed or seemingly random/uninitialized garbage. */ + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); expect(Ok, stat); @@ -622,7 +715,7 @@ static void test_emfonly(void) check_metafile(metafile, emfonly_records, "emfonly metafile", dst_points, &frame, UnitPixel); - save_metafile(metafile, "emfonly.emf"); + sync_metafile(&metafile, "emfonly.emf"); stat = GdipGetImageBounds((GpImage*)metafile, &bounds, &unit); expect(Ok, stat); @@ -638,6 +731,35 @@ static void test_emfonly(void) stat = GdipGetImageVerticalResolution((GpImage*)metafile, &yres); expect(Ok, stat); + memset(&header, 0xaa, sizeof(header)); + stat = GdipGetMetafileHeaderFromMetafile(metafile, &header); + expect(Ok, stat); + expect(MetafileTypeEmf, header.Type); + expect(U(header).EmfHeader.nBytes, header.Size); + /* For some reason a recoreded EMF Metafile has an EMF+ version. */ + todo_wine ok(header.Version == 0xdbc01001 || header.Version == 0xdbc01002, "Unexpected version %x\n", header.Version); + expect(0, header.EmfPlusFlags); + expectf(xres, header.DpiX); + expectf(xres, U(header).EmfHeader.szlDevice.cx / (REAL)U(header).EmfHeader.szlMillimeters.cx * 25.4); + expectf(yres, header.DpiY); + expectf(yres, U(header).EmfHeader.szlDevice.cy / (REAL)U(header).EmfHeader.szlMillimeters.cy * 25.4); + expect(0, header.X); + expect(0, header.Y); + expect(100, header.Width); + expect(100, header.Height); + expect(0, header.EmfPlusHeaderSize); + expect(0, header.LogicalDpiX); + expect(0, header.LogicalDpiX); + expect(EMR_HEADER, U(header).EmfHeader.iType); + expect(25, U(header).EmfHeader.rclBounds.left); + expect(25, U(header).EmfHeader.rclBounds.top); + expect(74, U(header).EmfHeader.rclBounds.right); + expect(74, U(header).EmfHeader.rclBounds.bottom); + expect(0, U(header).EmfHeader.rclFrame.left); + expect(0, U(header).EmfHeader.rclFrame.top); + expectf_(100.0, U(header).EmfHeader.rclFrame.right * xres / 2540.0, 2.0); + expectf_(100.0, U(header).EmfHeader.rclFrame.bottom * yres / 2540.0, 2.0); + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); expect(Ok, stat); @@ -753,6 +875,34 @@ static void test_emfonly(void) expect(Ok, stat); expectf(header.DpiY, yres); + memset(&header, 0xaa, sizeof(header)); + stat = GdipGetMetafileHeaderFromMetafile(metafile, &header); + expect(Ok, stat); + expect(MetafileTypeEmf, header.Type); + expect(U(header).EmfHeader.nBytes, header.Size); + expect(0x10000, header.Version); + expect(0, header.EmfPlusFlags); + expectf(xres, header.DpiX); + expectf(xres, U(header).EmfHeader.szlDevice.cx / (REAL)U(header).EmfHeader.szlMillimeters.cx * 25.4); + expectf(yres, header.DpiY); + expectf(yres, U(header).EmfHeader.szlDevice.cy / (REAL)U(header).EmfHeader.szlMillimeters.cy * 25.4); + expect(0, header.X); + expect(0, header.Y); + expect(100, header.Width); + expect(100, header.Height); + expect(0, header.EmfPlusHeaderSize); + expect(0, header.LogicalDpiX); + expect(0, header.LogicalDpiX); + expect(EMR_HEADER, U(header).EmfHeader.iType); + expect(25, U(header).EmfHeader.rclBounds.left); + expect(25, U(header).EmfHeader.rclBounds.top); + expect(74, U(header).EmfHeader.rclBounds.right); + expect(74, U(header).EmfHeader.rclBounds.bottom); + expect(0, U(header).EmfHeader.rclFrame.left); + expect(0, U(header).EmfHeader.rclFrame.top); + expectf_(100.0, U(header).EmfHeader.rclFrame.right * xres / 2540.0, 2.0); + expectf_(100.0, U(header).EmfHeader.rclFrame.bottom * yres / 2540.0, 2.0); + stat = GdipDisposeImage((GpImage*)metafile); expect(Ok, stat); } @@ -811,7 +961,7 @@ static void test_fillrect(void) check_metafile(metafile, fillrect_records, "fillrect metafile", dst_points, &frame, UnitPixel); - save_metafile(metafile, "fillrect.emf"); + sync_metafile(&metafile, "fillrect.emf"); stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); expect(Ok, stat); @@ -915,7 +1065,7 @@ static void test_clear(void) stat = GdipDeleteGraphics(graphics); expect(Ok, stat); - save_metafile(metafile, "clear.emf"); + sync_metafile(&metafile, "clear.emf"); stat = GdipCreateBitmapFromScan0(30, 30, 0, PixelFormat32bppRGB, NULL, &bitmap); expect(Ok, stat); @@ -1228,7 +1378,7 @@ static void test_pagetransform(void) check_metafile(metafile, pagetransform_records, "pagetransform metafile", dst_points, &frame, UnitPixel); - save_metafile(metafile, "pagetransform.emf"); + sync_metafile(&metafile, "pagetransform.emf"); stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); expect(Ok, stat); @@ -1280,6 +1430,14 @@ static const emfplus_record worldtransform_records[] = { {0, EmfPlusRecordTypeFillRects}, {0, EmfPlusRecordTypeResetWorldTransform}, {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeMultiplyWorldTransform}, + {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeRotateWorldTransform}, + {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeSetWorldTransform}, + {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeTranslateWorldTransform}, + {0, EmfPlusRecordTypeFillRects}, {0, EmfPlusRecordTypeEndOfFile}, {0, EMR_EOF}, {0} @@ -1379,6 +1537,112 @@ static void test_worldtransform(void) stat = GdipDeleteBrush(brush); expect(Ok, stat); + /* multiply transform */ + stat = GdipSetMatrixElements(transform, 2.0, 0.0, 0.0, 1.0, 0.0, 0.0); + expect(Ok, stat); + + stat = GdipMultiplyWorldTransform(graphics, transform, MatrixOrderPrepend); + expect(Ok, stat); + + stat = GdipGetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetMatrixElements(transform, elements); + expect(Ok, stat); + expectf(2.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(1.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); + + stat = GdipCreateSolidFill((ARGB)0xffff0000, (GpSolidFill**)&brush); + expect(Ok, stat); + + stat = GdipFillRectangle(graphics, brush, 1.0, 1.0, 0.5, 1.0); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + + /* rotate transform */ + stat = GdipRotateWorldTransform(graphics, 90.0, MatrixOrderAppend); + expect(Ok, stat); + + stat = GdipGetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetMatrixElements(transform, elements); + expect(Ok, stat); + expectf(0.0, elements[0]); + expectf(2.0, elements[1]); + expectf(-1.0, elements[2]); + expectf(0.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); + + stat = GdipCreateSolidFill((ARGB)0xffff00ff, (GpSolidFill**)&brush); + expect(Ok, stat); + + stat = GdipFillRectangle(graphics, brush, 1.0, -1.0, 0.5, 1.0); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + + /* set transform */ + stat = GdipSetMatrixElements(transform, 1.0, 0.0, 0.0, 3.0, 0.0, 0.0); + expect(Ok, stat); + + stat = GdipSetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetMatrixElements(transform, elements); + expect(Ok, stat); + expectf(1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(3.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); + + stat = GdipCreateSolidFill((ARGB)0xffffff00, (GpSolidFill**)&brush); + expect(Ok, stat); + + stat = GdipFillRectangle(graphics, brush, 1.0, 1.0, 1.0, 1.0); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + + /* translate transform */ + stat = GdipTranslateWorldTransform(graphics, -1.0, 0.0, MatrixOrderAppend); + expect(Ok, stat); + + stat = GdipGetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetMatrixElements(transform, elements); + expect(Ok, stat); + expectf(1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(3.0, elements[3]); + expectf(-1.0, elements[4]); + expectf(0.0, elements[5]); + + stat = GdipCreateSolidFill((ARGB)0xffffffff, (GpSolidFill**)&brush); + expect(Ok, stat); + + stat = GdipFillRectangle(graphics, brush, 1.0, 1.0, 1.0, 1.0); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + stat = GdipDeleteMatrix(transform); expect(Ok, stat); @@ -1387,7 +1651,7 @@ static void test_worldtransform(void) check_metafile(metafile, worldtransform_records, "worldtransform metafile", dst_points, &frame, UnitPixel); - save_metafile(metafile, "worldtransform.emf"); + sync_metafile(&metafile, "worldtransform.emf"); stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); expect(Ok, stat); @@ -1413,6 +1677,22 @@ static void test_worldtransform(void) expect(Ok, stat); expect(0xff00ffff, color); + stat = GdipBitmapGetPixel(bitmap, 50, 30, &color); + expect(Ok, stat); + expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 10, 50, &color); + expect(Ok, stat); + expect(0xffff00ff, color); + + stat = GdipBitmapGetPixel(bitmap, 30, 90, &color); + expect(Ok, stat); + expect(0xffffff00, color); + + stat = GdipBitmapGetPixel(bitmap, 10, 90, &color); + expect(Ok, stat); + expect(0xffffffff, color); + stat = GdipDeleteGraphics(graphics); expect(Ok, stat); @@ -1567,6 +1847,436 @@ static void test_frameunit(void) expect(Ok, stat); } +static const emfplus_record container_records[] = { + {0, EMR_HEADER}, + {0, EmfPlusRecordTypeHeader}, + {0, EmfPlusRecordTypeBeginContainerNoParams}, + {0, EmfPlusRecordTypeScaleWorldTransform}, + {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeEndContainer}, + {0, EmfPlusRecordTypeScaleWorldTransform}, + {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeSave}, + {0, EmfPlusRecordTypeRestore}, + {0, EmfPlusRecordTypeScaleWorldTransform}, + {0, EmfPlusRecordTypeBeginContainerNoParams}, + {0, EmfPlusRecordTypeScaleWorldTransform}, + {0, EmfPlusRecordTypeBeginContainerNoParams}, + {0, EmfPlusRecordTypeEndContainer}, + {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeBeginContainer}, + {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeEndContainer}, + {0, EmfPlusRecordTypeBeginContainerNoParams}, + {0, EmfPlusRecordTypeEndOfFile}, + {0, EMR_EOF}, + {0} +}; + +static void test_containers(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}; + GraphicsContainer state1, state2; + GpRectF srcrect, dstrect; + REAL dpix, dpiy; + + 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; @@ -1583,8 +2293,13 @@ START_TEST(metafile) myARGC = winetest_get_mainargs( &myARGV ); - if (myARGC >= 3 && !strcmp(myARGV[2], "save")) - save_metafiles = TRUE; + if (myARGC >= 3) + { + if (!strcmp(myARGV[2], "save")) + save_metafiles = TRUE; + else if (!strcmp(myARGV[2], "load")) + load_metafiles = TRUE; + } test_empty(); test_getdc(); @@ -1596,6 +2311,9 @@ START_TEST(metafile) test_worldtransform(); test_converttoemfplus(); test_frameunit(); + test_containers(); + test_clipping(); + test_gditransform(); GdiplusShutdown(gdiplusToken); }