#define expectf_(expected, got, precision) ok(fabs((expected) - (got)) <= (precision), "Expected %f, got %f\n", (expected), (got))
#define expectf(expected, got) expectf_((expected), (got), 0.001)
+static GpStatus (WINAPI *pGdipGraphicsSetAbort)(GpGraphics*,GdiplusAbort*);
+
static const REAL mm_per_inch = 25.4;
static const REAL point_per_inch = 72.0;
static HWND hwnd;
status = GdipTransformPoints(graphics, CoordinateSpacePage, CoordinateSpaceWorld, ptf, -1);
expect(InvalidParameter, status);
+ status = GdipTransformPoints(graphics, CoordinateSpaceDevice+1, CoordinateSpaceWorld, ptf, 2);
+ expect(InvalidParameter, status);
+ status = GdipTransformPoints(graphics, -1, CoordinateSpaceWorld, ptf, 2);
+ expect(InvalidParameter, status);
+ status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceDevice+1, ptf, 2);
+ expect(InvalidParameter, status);
+ status = GdipTransformPoints(graphics, CoordinateSpaceDevice, -1, ptf, 2);
+ expect(InvalidParameter, status);
+
ptf[0].X = 1.0;
ptf[0].Y = 0.0;
ptf[1].X = 0.0;
ok(rect.X == 100.0 && rect.Y == 100.0 && rect.Width == 100.0 && rect.Height == 100.0,
"expected 100.0,100.0-100.0,100.0, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
+ /* Clip region does not account for changes to gdi32 transform */
+ SetViewportOrgEx(hdc, 10, 10, NULL);
+
+ status = GdipGetClipBounds(graphics, &rect);
+ expect(Ok, status);
+ ok(rect.X == 100.0 && rect.Y == 100.0 && rect.Width == 100.0 && rect.Height == 100.0,
+ "expected 100.0,100.0-100.0,100.0, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
+
+ SetViewportOrgEx(hdc, 0, 0, NULL);
+
status = GdipSetEmpty(region);
expect(Ok, status);
status = GdipGetClip(graphics, region);
ReleaseDC(hwnd, hdc);
}
+static void test_GdipGraphicsSetAbort(void)
+{
+ HDC hdc;
+ GpStatus status;
+ GpGraphics *graphics;
+
+ if (!pGdipGraphicsSetAbort)
+ {
+ win_skip("GdipGraphicsSetAbort() is not supported.\n");
+ return;
+ }
+
+ hdc = GetDC(hwnd);
+
+ status = GdipCreateFromHDC(hdc, &graphics);
+ expect(Ok, status);
+
+ status = pGdipGraphicsSetAbort(NULL, NULL);
+ expect(InvalidParameter, status);
+
+ status = pGdipGraphicsSetAbort(graphics, NULL);
+ expect(Ok, status);
+
+ GdipDeleteGraphics(graphics);
+
+ ReleaseDC(hwnd, hdc);
+}
+
+#define BLUE_COLOR (0xff0000ff)
+#define is_blue_color(color) ( ((color) & 0x00ffffff) == 0xff )
+#define get_bitmap_pixel(x,y) pixel[(y)*(width) + (x)]
+static DWORD* GetBitmapPixelBuffer(HDC hdc, HBITMAP hbmp, int width, int height)
+{
+ BITMAPINFOHEADER bi;
+ UINT lines = 0;
+ DWORD *buffer = (DWORD *)GdipAlloc(width*height*4);
+
+ bi.biSize = sizeof(BITMAPINFOHEADER);
+ bi.biWidth = width;
+ bi.biHeight = -height; /*very Important, set negative, indicating a top-down DIB*/
+ bi.biPlanes = 1;
+ bi.biBitCount = 32;
+ bi.biCompression = BI_RGB;
+ bi.biSizeImage = 0;
+ bi.biXPelsPerMeter = 0;
+ bi.biYPelsPerMeter = 0;
+ bi.biClrUsed = 0;
+ bi.biClrImportant = 0;
+
+ lines = GetDIBits(hdc, hbmp, 0, height, buffer, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
+ ok(lines == height, "Expected GetDIBits:%p,%d->%d,%d\n", buffer, height, lines, GetLastError());
+
+ return buffer;
+}
+
+static void ReleaseBitmapPixelBuffer(DWORD* buffer)
+{
+ if (buffer) GdipFree(buffer);
+}
+
+static void test_GdipFillRectanglesOnMemoryDCSolidBrush(void)
+{
+ ARGB color[6] = {0,0,0,0,0,0};
+ POINT pt = {0,0};
+ RECT rect = {100, 100, 180, 180};
+ UINT width = rect.right - rect.left;
+ UINT height = rect.bottom - rect.top;
+ GpStatus status = 0;
+ GpSolidFill *brush = NULL;
+ GpGraphics *graphics = NULL;
+ HDC dc = GetDC( hwnd);
+ HDC hdc = CreateCompatibleDC(dc);
+ HBITMAP bmp = CreateCompatibleBitmap(dc, width, height);
+ HGDIOBJ old = SelectObject(hdc, bmp);
+ DWORD* pixel = NULL;
+
+ /*Change the window origin is the key test point*/
+ SetWindowOrgEx(hdc, rect.left, rect.top, &pt);
+
+ status = GdipCreateSolidFill(BLUE_COLOR, &brush);
+ expect(Ok, status);
+
+ status = GdipCreateFromHDC(hdc, &graphics);
+ expect(Ok, status);
+
+ status = GdipSetClipRectI(graphics, rect.left+width/2, rect.top+height/2,
+ width, height, CombineModeReplace);
+ expect(Ok, status);
+
+ status = GdipFillRectangleI(graphics, (GpBrush*)brush, 0, 0, rect.right, rect.bottom);
+ expect(Ok, status);
+
+ GdipDeleteBrush((GpBrush*)brush);
+ GdipDeleteGraphics(graphics);
+
+ pixel = GetBitmapPixelBuffer(hdc, bmp, width, height);
+ if (pixel)
+ {
+ color[0] = get_bitmap_pixel(width/2, height/2);
+ color[1] = get_bitmap_pixel(width/2+1, height/2);
+ color[2] = get_bitmap_pixel(width/2, height/2+1);
+ color[3] = get_bitmap_pixel(width/2-1, height/2-1);
+ color[4] = get_bitmap_pixel(width/2-1, height-1);
+ color[5] = get_bitmap_pixel(width-1, height/2-1);
+ }
+
+ ok(is_blue_color(color[0]) && is_blue_color(color[1]) && is_blue_color(color[2]) &&
+ color[3] == 0 && color[4] == 0 && color[5] == 0,
+ "Expected GdipFillRectangleI take effect!\n" );
+ ReleaseBitmapPixelBuffer(pixel);
+
+ SelectObject(hdc, old);
+ DeleteObject(bmp);
+ DeleteDC(hdc);
+ ReleaseDC(hwnd, dc);
+}
+
+static void test_GdipFillRectanglesOnMemoryDCTextureBrush(void)
+{
+ ARGB color[6] = {0,0,0,0,0,0};
+ POINT pt = {0,0};
+ RECT rect = {100, 100, 180, 180};
+ UINT width = rect.right - rect.left;
+ UINT height = rect.bottom - rect.top;
+ GpStatus status = 0;
+ union
+ {
+ GpBitmap *bitmap;
+ GpImage *image;
+ } src_img;
+ GpTexture *brush = NULL;
+ GpGraphics *graphics = NULL;
+ HDC dc = GetDC( hwnd);
+ HDC hdc = CreateCompatibleDC(dc);
+ HBITMAP bmp = CreateCompatibleBitmap(dc, width, height);
+ HGDIOBJ old = SelectObject(hdc, bmp);
+
+ UINT x = 0;
+ UINT y = 0;
+ UINT src_img_width = width/2;
+ UINT src_img_height = height/2;
+ BYTE *src_img_data = GdipAlloc(src_img_width*src_img_height*4);
+ DWORD *pixel = (DWORD *)src_img_data;
+ ok(pixel != NULL, "Expected src_img_data is valid\n");
+
+ /*Change the window origin is the key test point*/
+ SetWindowOrgEx(hdc, rect.left, rect.top, &pt);
+
+ /*build a blue solid image!*/
+ for(y = 0; y < src_img_height; ++y)
+ {
+ for(x = 0; x < src_img_width; ++x)
+ {
+ pixel[x] = BLUE_COLOR;
+ }
+
+ pixel += src_img_width;
+ }
+
+ status = GdipCreateBitmapFromScan0(src_img_width, src_img_height, src_img_width*4,
+ PixelFormat32bppARGB, src_img_data, &src_img.bitmap);
+ expect(Ok, status);
+
+ status = GdipCreateTexture(src_img.image, 0, &brush);
+ expect(Ok, status);
+
+ status = GdipCreateFromHDC(hdc, &graphics);
+ expect(Ok, status);
+
+ status = GdipSetClipRectI(graphics, rect.left+width/2, rect.top+height/2,
+ width, height, CombineModeReplace);
+ expect(Ok, status);
+
+ status = GdipFillRectangleI(graphics, (GpBrush*)brush, 0, 0, rect.right, rect.bottom);
+ expect(Ok, status);
+
+ GdipDisposeImage(src_img.image);
+ GdipDeleteBrush((GpBrush*)brush);
+ GdipDeleteGraphics(graphics);
+ GdipFree(src_img_data);
+
+ pixel = GetBitmapPixelBuffer(hdc, bmp, width, height);
+ if (pixel)
+ {
+ color[0] = get_bitmap_pixel(width/2, height/2);
+ color[1] = get_bitmap_pixel(width/2+1, height/2);
+ color[2] = get_bitmap_pixel(width/2, height/2+1);
+ color[3] = get_bitmap_pixel(width/2-1, height/2-1);
+ color[4] = get_bitmap_pixel(width/2-1, height-1);
+ color[5] = get_bitmap_pixel(width-1, height/2-1);
+ }
+ ok(is_blue_color(color[0]) && is_blue_color(color[1]) && is_blue_color(color[2]) &&
+ color[3] == 0 && color[4] == 0 && color[5] == 0,
+ "Expected GdipFillRectangleI take effect!\n" );
+ ReleaseBitmapPixelBuffer(pixel);
+
+ SelectObject(hdc, old);
+ DeleteObject(bmp);
+ DeleteDC(hdc);
+ ReleaseDC(hwnd, dc);
+}
+
+static void test_GdipFillRectanglesOnBitmapTextureBrush(void)
+{
+ ARGB color[6] = {0,0,0,0,0,0};
+ UINT x = 0;
+ UINT y = 0;
+ RECT rect = {100, 100, 180, 180};
+ UINT width = rect.right - rect.left;
+ UINT height = rect.bottom - rect.top;
+ UINT src_img_width = width/2;
+ UINT src_img_height = height/2;
+
+ GpStatus status = 0;
+ union
+ {
+ GpBitmap *bitmap;
+ GpImage *image;
+ } src_img;
+ union
+ {
+ GpBitmap *bitmap;
+ GpImage *image;
+ } dst_img;
+
+ GpTexture *brush = NULL;
+ GpGraphics *graphics = NULL;
+ BYTE *src_img_data = GdipAlloc(src_img_width*src_img_height*4);
+ DWORD *pixel = (DWORD *)src_img_data;
+ ok(pixel != NULL, "Expected src_img_data is valid\n");
+
+ status = GdipCreateBitmapFromScan0(width, height, width*4,
+ PixelFormat32bppARGB, NULL, &dst_img.bitmap);
+ expect(Ok, status);
+
+ /*build a blue solid image!*/
+ for(y = 0; y < src_img_height; ++y)
+ {
+ for(x = 0; x < src_img_width; ++x)
+ {
+ pixel[x] = BLUE_COLOR;
+ }
+
+ pixel += src_img_width;
+ }
+
+ status = GdipCreateBitmapFromScan0(src_img_width, src_img_height, src_img_width*4,
+ PixelFormat32bppARGB, src_img_data, &src_img.bitmap);
+ expect(Ok, status);
+
+ status = GdipCreateTexture(src_img.image, 0, &brush);
+ expect(Ok, status);
+
+ status = GdipGetImageGraphicsContext(dst_img.image, &graphics);
+ expect(Ok, status);
+
+ status = GdipSetClipRectI(graphics, 0, 0, width, height, CombineModeReplace);
+ expect(Ok, status);
+
+ status = GdipFillRectangleI(graphics, (GpBrush*)brush, 0, 0, width/2, height/2);
+ expect(Ok, status);
+
+ GdipDeleteBrush((GpBrush*)brush);
+ GdipDeleteGraphics(graphics);
+
+ GdipBitmapGetPixel(dst_img.bitmap, 0, 0, &color[0]);
+ GdipBitmapGetPixel(dst_img.bitmap, 0, 1, &color[1]);
+ GdipBitmapGetPixel(dst_img.bitmap, 1, 0, &color[2]);
+ GdipBitmapGetPixel(dst_img.bitmap, width/2, 0, &color[3]);
+ GdipBitmapGetPixel(dst_img.bitmap, width/2, height/2, &color[4]);
+ GdipBitmapGetPixel(dst_img.bitmap, 0, height/2, &color[5]);
+
+ ok(is_blue_color(color[0]) && is_blue_color(color[1]) && is_blue_color(color[2]) &&
+ color[3] == 0 && color[4] == 0 && color[5] == 0,
+ "Expected GdipFillRectangleI take effect!\n" );
+
+ GdipDisposeImage(src_img.image);
+ GdipDisposeImage(dst_img.image);
+ GdipFree(src_img_data);
+}
+
+static void test_GdipDrawImagePointsRectOnMemoryDC(void)
+{
+ ARGB color[6] = {0,0,0,0,0,0};
+ POINT pt = {0,0};
+ RECT rect = {100, 100, 180, 180};
+ UINT width = rect.right - rect.left;
+ UINT height = rect.bottom - rect.top;
+ GpStatus status = 0;
+ union
+ {
+ GpBitmap *bitmap;
+ GpImage *image;
+ } src_img;
+ GpGraphics *graphics = NULL;
+ HDC dc = GetDC( hwnd);
+ HDC hdc = CreateCompatibleDC(dc);
+ HBITMAP bmp = CreateCompatibleBitmap(dc, width, height);
+ HGDIOBJ old = SelectObject(hdc, bmp);
+
+ UINT x = 0;
+ UINT y = 0;
+ UINT src_img_width = width/2;
+ UINT src_img_height = height/2;
+ BYTE *src_img_data = GdipAlloc(src_img_width*src_img_height*4);
+ DWORD *pixel = (DWORD *)src_img_data;
+ ok(pixel != NULL, "Expected src_img_data is valid\n");
+
+ /*Change the window origin is the key test point*/
+ SetWindowOrgEx(hdc, rect.left, rect.top, &pt);
+
+ /*build a blue solid image!*/
+ for(y = 0; y < src_img_height; ++y)
+ {
+ for(x = 0; x < src_img_width; ++x)
+ {
+ pixel[x] = BLUE_COLOR;
+ }
+
+ pixel += src_img_width;
+ }
+
+ status = GdipCreateBitmapFromScan0(src_img_width, src_img_height, src_img_width*4,
+ PixelFormat32bppARGB, src_img_data, &src_img.bitmap);
+ expect(Ok, status);
+
+ status = GdipCreateFromHDC(hdc, &graphics);
+ expect(Ok, status);
+
+ status = GdipDrawImageRectRectI(graphics, src_img.image,
+ rect.left+width/2, rect.top+height/2, width/2, height/2,
+ 0, 0, src_img_width, src_img_height, UnitPixel, NULL, NULL, NULL);
+ expect(Ok, status);
+
+ GdipDisposeImage(src_img.image);
+ GdipDeleteGraphics(graphics);
+ GdipFree(src_img_data);
+
+ pixel = GetBitmapPixelBuffer(hdc, bmp, width, height);
+ if (pixel)
+ {
+ color[0] = get_bitmap_pixel(width/2, height/2);
+ color[1] = get_bitmap_pixel(width/2+1, height/2);
+ color[2] = get_bitmap_pixel(width/2, height/2+1);
+ color[3] = get_bitmap_pixel(width/2-1, height/2-1);
+ color[4] = get_bitmap_pixel(width/2-1, height-1);
+ color[5] = get_bitmap_pixel(width-1, height/2-1);
+ }
+ ok(is_blue_color(color[0]) && is_blue_color(color[1]) && is_blue_color(color[2]) &&
+ color[3] == 0 && color[4] == 0 && color[5] == 0,
+ "Expected GdipDrawImageRectRectI take effect!\n" );
+ ReleaseBitmapPixelBuffer(pixel);
+
+ SelectObject(hdc, old);
+ DeleteObject(bmp);
+ DeleteDC(hdc);
+ ReleaseDC(hwnd, dc);
+}
+
START_TEST(graphics)
{
struct GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
WNDCLASSA class;
+ HMODULE gdiplus_mod = GetModuleHandleA("gdiplus.dll");
+ HMODULE hmsvcrt;
+ int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask);
+
+ /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */
+ hmsvcrt = LoadLibraryA("msvcrt");
+ _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s");
+ if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e);
+
+ pGdipGraphicsSetAbort = (void*)GetProcAddress(gdiplus_mod, "GdipGraphicsSetAbort");
memset( &class, 0, sizeof(class) );
class.lpszClassName = "gdiplus_test";
test_bitmapfromgraphics();
test_GdipFillRectangles();
test_GdipGetVisibleClipBounds_memoryDC();
+ test_GdipFillRectanglesOnMemoryDCSolidBrush();
+ test_GdipFillRectanglesOnMemoryDCTextureBrush();
+ test_GdipFillRectanglesOnBitmapTextureBrush();
+ test_GdipDrawImagePointsRectOnMemoryDC();
test_container_rects();
+ test_GdipGraphicsSetAbort();
GdiplusShutdown(gdiplusToken);
DestroyWindow( hwnd );