diff --git a/modules/rostests/winetests/gdiplus/brush.c b/modules/rostests/winetests/gdiplus/brush.c index bb645ffef93..3ff73c02e47 100644 --- a/modules/rostests/winetests/gdiplus/brush.c +++ b/modules/rostests/winetests/gdiplus/brush.c @@ -18,13 +18,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS #include #include "objbase.h" #include "gdiplus.h" #include "wine/test.h" -#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#ifdef __REACTOS__ +#include "ole2.h" +#endif + +#define expect(expected,got) expect_(__LINE__, expected, got) +static inline void expect_(unsigned line, DWORD expected, DWORD got) +{ + ok_(__FILE__, line)(expected == got, "Expected %.8ld, got %.8ld\n", expected, got); +} #define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got) static HWND hwnd; @@ -274,6 +283,37 @@ static void test_transform(void) GpPointF start, end; GpRectF rectf; REAL elements[6]; + UINT buf[15]; + HBITMAP hbmp,old; + HDC dcmem; + BITMAP bm; + GpImage *image; + IStream *stream; + HGLOBAL hglob; + VOID *data; + HRESULT hr; + LONG size; + + /* 3*5 bmp 32bit*/ + static const unsigned char bmpimage[] = { + 0x42,0x4d,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00, + 0x00,0x00,0x28,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x05,0x00, + 0x00,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x3e,0x00, + 0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00, + 0xff,0x11,0xff,0x00,0xff,0x11,0xff,0x00,0xff,0x11,0xff,0x00, + 0xff,0x33,0xff,0x00,0xff,0x33,0xff,0x00,0xff,0x33,0xff,0x00, + 0xff,0x55,0xff,0x00,0xff,0x55,0xff,0x00,0xff,0x55,0xff,0x00, + 0xff,0xaa,0xff,0x00,0xff,0xaa,0xff,0x00,0xff,0xaa,0xff,0x00, + 0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00, + 0x00,0x00,0x00,0x00}; + + static const UINT buf_rotate_180[15] = { + 0xffffffff, 0xffffffff, 0xffffffff, + 0xffff11ff, 0xffff11ff, 0xffff11ff, + 0xffff33ff, 0xffff33ff, 0xffff33ff, + 0xffff55ff, 0xffff55ff, 0xffff55ff, + 0xffffaaff, 0xffffaaff, 0xffffaaff}; /* GpTexture */ status = GdipCreateMatrix2(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, &m); @@ -556,6 +596,38 @@ static void test_transform(void) expect(Ok, status); status = GdipDeleteBrush((GpBrush*)line); expect(Ok,status); + GdipDeleteGraphics(graphics); + + dcmem = CreateCompatibleDC(hdc); + hbmp = CreateBitmap(3, 5, 1, 32, NULL); + old = SelectObject(dcmem, hbmp); + status = GdipCreateFromHDC(dcmem, &graphics); + expect(Ok, status); + hglob = GlobalAlloc(0, sizeof(bmpimage)); + data = GlobalLock (hglob); + memcpy(data, bmpimage, sizeof(bmpimage)); + GlobalUnlock(hglob); + hr = CreateStreamOnHGlobal(hglob, TRUE, &stream); + expect(S_OK, hr); + status = GdipLoadImageFromStream(stream, &image); + expect(Ok, status); + status = GdipCreateTexture(image, WrapModeTile, &texture); + expect(Ok, status); + status = GdipRotateTextureTransform(texture, 180.0f, MatrixOrderPrepend); + expect(Ok, status); + status = GdipFillRectangle(graphics, (GpBrush*)texture, .0f, .0f, (REAL)3, (REAL)5); + expect(Ok, status); + GdipDeleteBrush((GpBrush*)texture); + GdipDisposeImage(image); + GdipDeleteGraphics(graphics); + IStream_Release(stream); + hbmp = SelectObject(dcmem, old); + GetObjectW(hbmp, sizeof(bm), &bm); + size = GetBitmapBits(hbmp, sizeof(buf), buf); + expect(sizeof(buf), size); + DeleteObject(hbmp); + DeleteDC(dcmem); + ok(!memcmp(buf, buf_rotate_180, sizeof(buf)), "Failed to rotate image.\n"); if(0){ /* enable to visually compare with Windows */ @@ -1299,6 +1371,7 @@ static void test_pathgradientcenterpoint(void) { static const GpPointF path_points[] = {{0,0}, {3,0}, {0,4}}; GpStatus status; + GpPath* path; GpPathGradient *grad; GpPointF point; @@ -1341,8 +1414,28 @@ static void test_pathgradientcenterpoint(void) status = GdipGetPathGradientCenterPoint(grad, &point); expect(Ok, status); - todo_wine expectf(1.0, point.X); - todo_wine expectf(4.0/3.0, point.Y); + expectf(1.0, point.X); + expectf(4.0/3.0, point.Y); + + status = GdipDeleteBrush((GpBrush*)grad); + expect(Ok, status); + + status = GdipCreatePath(FillModeWinding, &path); + expect(Ok, status); + + status = GdipAddPathEllipse(path, 0, 0, 100, 50); + expect(Ok, status); + + status = GdipCreatePathGradientFromPath(path, &grad); + expect(Ok, status); + + status = GdipGetPathGradientCenterPoint(grad, &point); + expect(Ok, status); + expectf(700.0/13.0, point.X); + expectf(25.0, point.Y); + + status = GdipDeletePath(path); + expect(Ok, status); status = GdipDeleteBrush((GpBrush*)grad); expect(Ok, status); @@ -1613,6 +1706,239 @@ static void test_getHatchStyle(void) GdipDeleteBrush((GpBrush *)brush); } +static ARGB COLORREF2ARGB(COLORREF color) +{ + return 0xff000000 | + (color & 0xff) << 16 | + (color & 0xff00) | + (color & 0xff0000) >> 16; +} + +extern BOOL color_match(ARGB c1, ARGB c2, BYTE max_diff); + +static void test_hatchBrushStyles(void) +{ + static const struct + { + short pattern[8]; + GpHatchStyle hs; + } + styles[] = + { + { {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff}, HatchStyleHorizontal }, + { {0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000}, HatchStyleVertical }, + { {0x4006, 0x0019, 0x0064, 0x0190, 0x0640, 0x1900, 0x6400, 0x9001}, HatchStyleForwardDiagonal }, + { {0x9001, 0x6400, 0x1900, 0x0640, 0x0190, 0x0064, 0x0019, 0x4006}, HatchStyleBackwardDiagonal }, + { {0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xffff}, HatchStyleCross }, + { {0x9006, 0x6419, 0x1964, 0x0690, 0x0690, 0x1964, 0x6419, 0x9006}, HatchStyleDiagonalCross }, + { {0x0000, 0x0000, 0x0000, 0x00c0, 0x0000, 0x0000, 0x0000, 0xc000}, HatchStyle05Percent }, + { {0x0000, 0x00c0, 0x0000, 0xc000, 0x0000, 0x00c0, 0x0000, 0xc000}, HatchStyle10Percent }, + { {0x0000, 0x0c0c, 0x0000, 0xc0c0, 0x0000, 0x0c0c, 0x0000, 0xc0c0}, HatchStyle20Percent }, + { {0x0c0c, 0xc0c0, 0x0c0c, 0xc0c0, 0x0c0c, 0xc0c0, 0x0c0c, 0xc0c0}, HatchStyle25Percent }, + { {0x0303, 0xcccc, 0x3030, 0xcccc, 0x0303, 0xcccc, 0x3030, 0xcccc}, HatchStyle30Percent }, + { {0x0333, 0xcccc, 0x3333, 0xcccc, 0x3303, 0xcccc, 0x3333, 0xcccc}, HatchStyle40Percent }, + { {0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc}, HatchStyle50Percent }, + { {0x3333, 0xcfcf, 0x3333, 0xfcfc, 0x3333, 0xcfcf, 0x3333, 0xfcfc}, HatchStyle60Percent }, + { {0xf3f3, 0x3f3f, 0xf3f3, 0x3f3f, 0xf3f3, 0x3f3f, 0xf3f3, 0x3f3f}, HatchStyle70Percent }, + { {0xffff, 0xf3f3, 0xffff, 0x3f3f, 0xffff, 0xf3f3, 0xffff, 0x3f3f}, HatchStyle75Percent }, + { {0xffff, 0xfffc, 0xffff, 0xfcff, 0xffff, 0xfffc, 0xffff, 0xfcff}, HatchStyle80Percent }, + { {0x3fff, 0xffff, 0xffff, 0xffff, 0xff3f, 0xffff, 0xffff, 0xffff}, HatchStyle90Percent }, + { {0x0303, 0x0c0c, 0x3030, 0xc0c0, 0x0303, 0x0c0c, 0x3030, 0xc0c0}, HatchStyleLightDownwardDiagonal }, + { {0xc0c0, 0x3030, 0x0c0c, 0x0303, 0xc0c0, 0x3030, 0x0c0c, 0x0303}, HatchStyleLightUpwardDiagonal }, + { {0xc3c3, 0x0f0f, 0x3c3c, 0xf0f0, 0xc3c3, 0x0f0f, 0x3c3c, 0xf0f0}, HatchStyleDarkDownwardDiagonal }, + { {0xc3c3, 0xf0f0, 0x3c3c, 0x0f0f, 0xc3c3, 0xf0f0, 0x3c3c, 0x0f0f}, HatchStyleDarkUpwardDiagonal }, + { {0xc00f, 0x003f, 0x00fc, 0x03f0, 0x0fc0, 0x3f00, 0xfc00, 0xf003}, HatchStyleWideDownwardDiagonal }, + { {0xf003, 0xfc00, 0x3f00, 0x0fc0, 0x03f0, 0x00fc, 0x003f, 0xc00f}, HatchStyleWideUpwardDiagonal }, + { {0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0}, HatchStyleLightVertical }, + { {0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff}, HatchStyleLightHorizontal }, + { {0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333}, HatchStyleNarrowVertical }, + { {0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff}, HatchStyleNarrowHorizontal }, + { {0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0}, HatchStyleDarkVertical }, + { {0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff}, HatchStyleDarkHorizontal }, + { {0x0000, 0x0000, 0x0303, 0x0c0c, 0x3030, 0xc0c0, 0x0000, 0x0000}, HatchStyleDashedDownwardDiagonal }, + { {0x0000, 0x0000, 0xc0c0, 0x3030, 0x0c0c, 0x0303, 0x0000, 0x0000}, HatchStyleDashedUpwardDiagonal }, + { {0x0000, 0x0000, 0x0000, 0x00ff, 0x0000, 0x0000, 0x0000, 0xff00}, HatchStyleDashedHorizontal }, + { {0x00c0, 0x00c0, 0x00c0, 0x00c0, 0xc000, 0xc000, 0xc000, 0xc000}, HatchStyleDashedVertical }, + { {0x0030, 0x0c00, 0x0003, 0x0300, 0x000c, 0x3000, 0x00c0, 0xc000}, HatchStyleSmallConfetti }, + { {0xc0f3, 0x00f0, 0xf000, 0xf3c0, 0x03cf, 0x000f, 0x0f00, 0xcf03}, HatchStyleLargeConfetti }, + { {0x03c0, 0x0c30, 0x300c, 0xc003, 0x03c0, 0x0c30, 0x300c, 0xc003}, HatchStyleZigZag }, + { {0xf000, 0x0c33, 0x03c0, 0x0000, 0xf000, 0x0c33, 0x03c0, 0x0000}, HatchStyleWave }, + { {0xc003, 0x300c, 0x0c30, 0x03c0, 0x00c0, 0x0030, 0x000c, 0x0003}, HatchStyleDiagonalBrick }, + { {0x00c0, 0x00c0, 0x00c0, 0xffff, 0xc000, 0xc000, 0xc000, 0xffff}, HatchStyleHorizontalBrick }, + { {0x3303, 0x0c0c, 0x0330, 0xc0c0, 0x3033, 0x0c0c, 0x3330, 0xc0c0}, HatchStyleWeave }, + { {0xff00, 0xff00, 0xff00, 0xff00, 0x3333, 0xcccc, 0x3333, 0xcccc}, HatchStylePlaid }, + { {0xc000, 0x0003, 0xc000, 0x0000, 0x0300, 0x00c0, 0x0300, 0x0000}, HatchStyleDivot }, + { {0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xcccc}, HatchStyleDottedGrid }, + { {0x0000, 0x0c0c, 0x0000, 0x00c0, 0x0000, 0x0c0c, 0x0000, 0xc000}, HatchStyleDottedDiamond }, + { {0x0003, 0x0003, 0x000c, 0x00f0, 0x0f00, 0x30c0, 0xc030, 0x000f}, HatchStyleShingle }, + { {0xc3c3, 0xffff, 0x3c3c, 0xffff, 0xc3c3, 0xffff, 0x3c3c, 0xffff}, HatchStyleTrellis }, + { {0xffc0, 0xffc0, 0xc3c0, 0x3f3f, 0xc0ff, 0xc0ff, 0xc0c3, 0x3f3f}, HatchStyleSphere }, + { {0xc0c0, 0xc0c0, 0xc0c0, 0xffff, 0xc0c0, 0xc0c0, 0xc0c0, 0xffff}, HatchStyleSmallGrid }, + { {0xc3c3, 0x3c3c, 0x3c3c, 0xc3c3, 0xc3c3, 0x3c3c, 0x3c3c, 0xc3c3}, HatchStyleSmallCheckerBoard }, + { {0x00ff, 0x00ff, 0x00ff, 0x00ff, 0xff00, 0xff00, 0xff00, 0xff00}, HatchStyleLargeCheckerBoard }, + { {0x0003, 0xc00c, 0x3030, 0x0cc0, 0x0300, 0x0cc0, 0x3030, 0xc00c}, HatchStyleOutlinedDiamond }, + { {0x0000, 0x0300, 0x0fc0, 0x3ff0, 0xfffc, 0x3ff0, 0x0fc0, 0x0300}, HatchStyleSolidDiamond }, + }; + static const ARGB exp_colors[] = { 0xffffffff, 0xffbfbfbf, 0xff151515, 0xff000000 }; + static const ARGB fore_color = 0xff000000; + static const ARGB back_color = 0xffffffff; + static const int width = 16, height = 16; + GpStatus status; + HDC hdc; + GpGraphics *graphics_hdc; + GpGraphics *graphics_image; + GpBitmap *bitmap; + GpHatch *brush = NULL; + BOOL match_hdc; + BOOL match_image; + int x, y; + int i; + + hdc = GetDC(hwnd); + status = GdipCreateFromHDC(hdc, &graphics_hdc); + expect(Ok, status); + ok(graphics_hdc != NULL, "Expected the graphics context to be initialized.\n"); + + status = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppRGB, NULL, &bitmap); + expect(Ok, status); + status = GdipGetImageGraphicsContext((GpImage *)bitmap, &graphics_image); + expect(Ok, status); + ok(graphics_image != NULL, "Expected the graphics context to be initialized.\n"); + + for (i = 0; i < ARRAY_SIZE(styles); i++) + { + status = GdipCreateHatchBrush(styles[i].hs, fore_color, back_color, &brush); + expect(Ok, status); + ok(brush != NULL, "Expected the brush to be initialized.\n"); + status = GdipFillRectangleI(graphics_hdc, (GpBrush *)brush, 0, 0, width, height); + expect(Ok, status); + status = GdipFillRectangleI(graphics_image, (GpBrush *)brush, 0, 0, width, height); + expect(Ok, status); + status = GdipDeleteBrush((GpBrush *)brush); + expect(Ok, status); + brush = NULL; + + match_hdc = TRUE; + match_image = TRUE; + for(y = 0; y < width && (match_hdc || match_image); y++) + { + for(x = 0; x < height && (match_hdc || match_image); x++) + { + ARGB color; + int cindex = (styles[i].pattern[7-(y%8)] >> (2*(7-(x%8)))) & 3; + + color = COLORREF2ARGB(GetPixel(hdc, x, y)); + if (!color_match(color, exp_colors[cindex], 1)) + match_hdc = FALSE; + + GdipBitmapGetPixel(bitmap, x, y, &color); + if (!color_match(color, exp_colors[cindex], 1)) + match_image = FALSE; + } + } + ok(match_hdc, "Unexpected pattern for hatch style %#x with hdc.\n", styles[i].hs); + ok(match_image, "Unexpected pattern for hatch style %#x with image.\n", styles[i].hs); + } + + status = GdipDeleteGraphics(graphics_image); + expect(Ok, status); + status = GdipDisposeImage((GpImage*)bitmap); + expect(Ok, status); + + status = GdipDeleteGraphics(graphics_hdc); + expect(Ok, status); + ReleaseDC(hwnd, hdc); +} + +static void test_renderingOrigin(void) +{ + static const int width = 8, height = 8; + GpStatus status; + HDC hdc; + GpBitmap *bitmap; + GpGraphics *graphics_hdc; + GpGraphics *graphics_image; + GpHatch *brush; + BOOL match_hdc; + BOOL match_image; + static const INT tests[][2] = {{3, 6}, {-7, -4}}; + static const ARGB fore_color = 0xff000000; + static const ARGB back_color = 0xffffffff; + INT x, y; + int i; + + hdc = GetDC(hwnd); + GdipCreateFromHDC(hdc, &graphics_hdc); + + GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppRGB, NULL, &bitmap); + GdipGetImageGraphicsContext((GpImage *)bitmap, &graphics_image); + + GdipCreateHatchBrush(HatchStyleCross, fore_color, back_color, &brush); + + x = y = 0xdeadbeef; + status = GdipGetRenderingOrigin(graphics_image, &x, &y); + expect(Ok, status); + ok(x == 0 && y == 0, "Expected (%d, %d) got (%d, %d)\n", 0, 0, x, y); + x = y = 0xdeadbeef; + status = GdipGetRenderingOrigin(graphics_image, &x, &y); + expect(Ok, status); + ok(x == 0 && y == 0, "Expected (%d, %d) got (%d, %d)\n", 0, 0, x, y); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + const INT exp_x = tests[i][0] & 7; + const INT exp_y = tests[i][1] & 7; + + status = GdipSetRenderingOrigin(graphics_image, tests[i][0], tests[i][1]); + expect(Ok, status); + status = GdipSetRenderingOrigin(graphics_hdc, tests[i][0], tests[i][1]); + expect(Ok, status); + + status = GdipGetRenderingOrigin(graphics_image, &x, &y); + expect(Ok, status); + ok(x == tests[i][0] && y == tests[i][1], "Expected (%d, %d) got (%d, %d)\n", + tests[i][0], tests[i][1], x, y); + status = GdipGetRenderingOrigin(graphics_image, &x, &y); + expect(Ok, status); + ok(x == tests[i][0] && y == tests[i][1], "Expected (%d, %d) got (%d, %d)\n", + tests[i][0], tests[i][1], x, y); + + GdipFillRectangleI(graphics_image, (GpBrush *)brush, 0, 0, width, height); + GdipFillRectangleI(graphics_hdc, (GpBrush *)brush, 0, 0, width, height); + + match_hdc = TRUE; + match_image = TRUE; + for (y = 0; y < height && (match_hdc || match_image); y++) + { + for (x = 0; x < width && (match_hdc || match_image); x++) + { + ARGB color; + const ARGB exp_color = (x == exp_x || y == exp_y) ? fore_color : back_color; + + color = COLORREF2ARGB(GetPixel(hdc, x, y)); + if (color != exp_color) + match_hdc = FALSE; + + GdipBitmapGetPixel(bitmap, x, y, &color); + if (color != exp_color) + match_image = FALSE; + } + } + ok(match_hdc, "Hatch brush rendered incorrectly on hdc with rendering origin (%d, %d).\n", + tests[i][0], tests[i][1]); + ok(match_image, "Hatch brush rendered incorrectly on image with rendering origin (%d, %d).\n", + tests[i][0], tests[i][1]); + } + + GdipDeleteBrush((GpBrush *)brush); + + GdipDeleteGraphics(graphics_image); + GdipDisposeImage((GpImage*)bitmap); + + GdipDeleteGraphics(graphics_hdc); + ReleaseDC(hwnd, hdc); +} + START_TEST(brush) { struct GdiplusStartupInput gdiplusStartupInput; @@ -1665,6 +1991,8 @@ START_TEST(brush) test_pathgradientpresetblend(); test_pathgradientblend(); test_getHatchStyle(); + test_hatchBrushStyles(); + test_renderingOrigin(); GdiplusShutdown(gdiplusToken); DestroyWindow(hwnd); diff --git a/modules/rostests/winetests/gdiplus/customlinecap.c b/modules/rostests/winetests/gdiplus/customlinecap.c index e4ec329b935..26175ca8f66 100644 --- a/modules/rostests/winetests/gdiplus/customlinecap.c +++ b/modules/rostests/winetests/gdiplus/customlinecap.c @@ -283,12 +283,12 @@ static void test_create_adjustable_cap(void) ok(base == LineCapTriangle, "Unexpected base cap %d\n", base); stat = GdipSetCustomLineCapBaseCap((GpCustomLineCap*)cap, LineCapSquare); -todo_wine + todo_wine ok(stat == Ok, "Unexpected return code, %d\n", stat); stat = GdipGetCustomLineCapBaseCap((GpCustomLineCap*)cap, &base); ok(stat == Ok, "Unexpected return code, %d\n", stat); -todo_wine + todo_wine ok(base == LineCapSquare, "Unexpected base cap %d\n", base); /* Base inset */ diff --git a/modules/rostests/winetests/gdiplus/font.c b/modules/rostests/winetests/gdiplus/font.c index 03e7a04e081..ccdb7a2ef96 100644 --- a/modules/rostests/winetests/gdiplus/font.c +++ b/modules/rostests/winetests/gdiplus/font.c @@ -25,16 +25,16 @@ #include "gdiplus.h" #include "wine/test.h" -#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) -#define expect_(expected, got, precision) ok(abs((expected) - (got)) <= (precision), "Expected %d, got %d\n", (expected), (got)) +#define expect(expected,got) expect_inline(__LINE__, expected, got) +static inline void expect_inline(unsigned line, DWORD expected, DWORD got) +{ + ok_(__FILE__, line)(expected == got, "Expected %ld, got %ld\n", expected, got); +} + +#define expect_(expected, got, precision) ok(abs((expected) - (got)) <= (precision), "Expected %d, got %ld\n", (expected), (got)) #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 const WCHAR nonexistent[] = {'T','h','i','s','F','o','n','t','s','h','o','u','l','d','N','o','t','E','x','i','s','t','\0'}; -static const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; -static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'}; -static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0}; - static void set_rect_empty(RectF *rc) { rc->X = 0.0; @@ -54,7 +54,7 @@ static void create_testfontfile(const WCHAR *filename, int resource, WCHAR pathW lstrcatW(pathW, filename); file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); - ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW), GetLastError()); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", wine_dbgstr_w(pathW), GetLastError()); res = FindResourceA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(resource), (LPCSTR)RT_RCDATA); ok(res != 0, "couldn't find resource\n"); @@ -68,24 +68,23 @@ static void create_testfontfile(const WCHAR *filename, int resource, WCHAR pathW static void _delete_testfontfile(const WCHAR *filename, int line) { BOOL ret = DeleteFileW(filename); - ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError()); + ok_(__FILE__,line)(ret, "failed to delete file %s, error %ld\n", wine_dbgstr_w(filename), GetLastError()); } static void test_long_name(void) { WCHAR path[MAX_PATH]; - static const WCHAR path_longname[] = {'w','i','n','e','_','l','o','n','g','n','a','m','e','.','t','t','f',0}; GpStatus stat; GpFontCollection *fonts; INT num_families; - GpFontFamily *family; + GpFontFamily *family, *cloned_family; WCHAR family_name[LF_FACESIZE]; GpFont *font; stat = GdipNewPrivateFontCollection(&fonts); ok(stat == Ok, "GdipNewPrivateFontCollection failed: %d\n", stat); - create_testfontfile(path_longname, 1, path); + create_testfontfile(L"wine_longname.ttf", 1, path); stat = GdipPrivateAddFontFile(fonts, path); ok(stat == Ok, "GdipPrivateAddFontFile failed: %d\n", stat); @@ -104,6 +103,10 @@ static void test_long_name(void) stat = GdipCreateFont(family, 256.0, FontStyleRegular, UnitPixel, &font); ok(stat == Ok, "GdipCreateFont failed: %d\n", stat); + stat = GdipCloneFontFamily(family, &cloned_family); + ok(stat == Ok, "GdipCloneFontFamily failed: %d\n", stat); + ok(family == cloned_family, "GdipCloneFontFamily returned new object\n"); + /* Cleanup */ stat = GdipDeleteFont(font); @@ -112,6 +115,13 @@ static void test_long_name(void) stat = GdipDeletePrivateFontCollection(&fonts); ok(stat == Ok, "GdipDeletePrivateFontCollection failed: %d\n", stat); + /* Cloned family survives after collection is deleted */ + stat = GdipGetFamilyName(cloned_family, family_name, LANG_NEUTRAL); + ok(stat == Ok, "GdipGetFamilyName failed: %d\n", stat); + + stat = GdipDeleteFontFamily(cloned_family); + ok(stat == Ok, "GdipDeleteFontFamily failed: %d\n", stat); + DELETE_FONTFILE(path); } @@ -125,11 +135,11 @@ static void test_createfont(void) REAL size; WCHAR familyname[LF_FACESIZE]; - stat = GdipCreateFontFamilyFromName(nonexistent, NULL, &fontfamily); + stat = GdipCreateFontFamilyFromName(L"ThisFontShouldNotExist", NULL, &fontfamily); expect (FontFamilyNotFound, stat); stat = GdipDeleteFont(font); expect (InvalidParameter, stat); - stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &fontfamily); + stat = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &fontfamily); expect (Ok, stat); stat = GdipCreateFont(fontfamily, 12, FontStyleRegular, UnitPoint, &font); expect (Ok, stat); @@ -141,7 +151,8 @@ static void test_createfont(void) expect(Ok, stat); stat = GdipGetFamilyName(fontfamily2, familyname, 0); expect(Ok, stat); - ok (lstrcmpiW(Tahoma, familyname) == 0, "Expected Tahoma, got %s\n", + ok (fontfamily == fontfamily2, "Unexpected family instance.\n"); + ok (lstrcmpiW(L"Tahoma", familyname) == 0, "Expected Tahoma, got %s\n", wine_dbgstr_w(familyname)); stat = GdipDeleteFontFamily(fontfamily2); expect(Ok, stat); @@ -299,6 +310,56 @@ static void test_logfont(void) GdipDeleteFontFamily(family); GdipDeleteFont(font); + font = NULL; + + /* The next test must be done with a font where tmHeight - + tmInternalLeading != tmAscent. Times New Roman is such a font, + so make sure we really have it before continuing. */ + memset(&lfa, 0, sizeof(lfa)); + lstrcpyA(lfa.lfFaceName, "Times New Roman"); + + stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); + expect(Ok, stat); + + memset(&lfa2, 0, sizeof(lfa2)); + stat = GdipGetLogFontA(font, graphics, &lfa2); + expect(Ok, stat); + + GdipDeleteFont(font); + font = NULL; + + if (!lstrlenA(lfa.lfFaceName) || lstrcmpA(lfa.lfFaceName, lfa2.lfFaceName)) + { + skip("Times New Roman not installed\n"); + } + else + { + static const struct + { + INT input; + REAL expected; + } test_sizes[] = {{12, 9.0}, {36, 32.0}, {48, 42.0}, {72, 63.0}, {144, 127.0}}; + + UINT i; + + memset(&lfa, 0, sizeof(lfa)); + lstrcpyA(lfa.lfFaceName, "Times New Roman"); + + for (i = 0; i < ARRAY_SIZE(test_sizes); ++i) + { + lfa.lfHeight = test_sizes[i].input; + + stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); + expect(Ok, stat); + + stat = GdipGetFontSize(font, &rval); + expect(Ok, stat); + expectf(test_sizes[i].expected, rval); + + GdipDeleteFont(font); + font = NULL; + } + } GdipDeleteGraphics(graphics); ReleaseDC(0, hdc); @@ -311,42 +372,40 @@ static void test_fontfamily (void) GpStatus stat; /* FontFamily cannot be NULL */ - stat = GdipCreateFontFamilyFromName (Tahoma , NULL, NULL); + stat = GdipCreateFontFamilyFromName (L"Tahoma" , NULL, NULL); expect (InvalidParameter, stat); /* FontFamily must be able to actually find the family. * If it can't, any subsequent calls should fail. */ - stat = GdipCreateFontFamilyFromName (nonexistent, NULL, &family); + stat = GdipCreateFontFamilyFromName (L"ThisFontShouldNotExist", NULL, &family); expect (FontFamilyNotFound, stat); /* Bitmap fonts are not found */ - stat = GdipCreateFontFamilyFromName (MSSansSerif, NULL, &family); + stat = GdipCreateFontFamilyFromName (L"MS Sans Serif", NULL, &family); expect (FontFamilyNotFound, stat); if(stat == Ok) GdipDeleteFontFamily(family); - stat = GdipCreateFontFamilyFromName (Tahoma, NULL, &family); + stat = GdipCreateFontFamilyFromName (L"Tahoma", NULL, &family); expect (Ok, stat); stat = GdipGetFamilyName (family, itsName, LANG_NEUTRAL); expect (Ok, stat); - expect (0, lstrcmpiW(itsName, Tahoma)); + expect (0, lstrcmpiW(itsName, L"Tahoma")); - if (0) - { - /* Crashes on Windows XP SP2, Vista, and so Wine as well */ - stat = GdipGetFamilyName (family, NULL, LANG_NEUTRAL); - expect (Ok, stat); - } + /* Crashes on Windows XP SP2 and Vista */ + stat = GdipGetFamilyName (family, NULL, LANG_NEUTRAL); + expect (Ok, stat); /* Make sure we don't read old data */ ZeroMemory (itsName, sizeof(itsName)); stat = GdipCloneFontFamily(family, &clonedFontFamily); expect (Ok, stat); + ok (family == clonedFontFamily, "Unexpected family instance.\n"); GdipDeleteFontFamily(family); stat = GdipGetFamilyName(clonedFontFamily, itsName, LANG_NEUTRAL); expect(Ok, stat); - expect(0, lstrcmpiW(itsName, Tahoma)); + expect(0, lstrcmpiW(itsName, L"Tahoma")); GdipDeleteFontFamily(clonedFontFamily); } @@ -357,7 +416,7 @@ static void test_fontfamily_properties (void) GpStatus stat; UINT16 result = 0; - stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &FontFamily); + stat = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &FontFamily); expect(Ok, stat); stat = GdipGetLineSpacing(FontFamily, FontStyleRegular, &result); @@ -377,7 +436,7 @@ static void test_fontfamily_properties (void) ok(result == 423, "Expected 423, got %d\n", result); GdipDeleteFontFamily(FontFamily); - stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, &FontFamily); + stat = GdipCreateFontFamilyFromName(L"Times New Roman", NULL, &FontFamily); if(stat == FontFamilyNotFound) skip("Times New Roman not installed\n"); else @@ -481,7 +540,7 @@ static void test_heightgivendpi(void) REAL height; Unit unit; - stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &fontfamily); + stat = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &fontfamily); expect(Ok, stat); stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitPixel, &font); @@ -682,7 +741,7 @@ static void test_font_metrics(void) memset(&lf, 0, sizeof(lf)); /* Tahoma,-13 */ - lstrcpyW(lf.lfFaceName, Tahoma); + lstrcpyW(lf.lfFaceName, L"Tahoma"); lf.lfHeight = -13; stat = GdipCreateFontFromLogfontW(hdc, &lf, &font); expect(Ok, stat); @@ -693,14 +752,14 @@ static void test_font_metrics(void) gdip_get_font_metrics(font, &fm_gdip); trace("gdiplus:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent, fm_gdip.font_height, fm_gdip.font_size); gdi_get_font_metrics(&lf, &fm_gdi); trace("gdi:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, fm_gdi.font_height, fm_gdi.font_size); @@ -709,10 +768,10 @@ static void test_font_metrics(void) stat = GdipGetLogFontW(font, graphics, &lf); expect(Ok, stat); - ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight); + ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %ld\n", lf.lfHeight); gdi_get_font_metrics(&lf, &fm_gdi); trace("gdi:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, fm_gdi.font_height, fm_gdi.font_size); @@ -723,7 +782,7 @@ static void test_font_metrics(void) GdipDeleteFont(font); /* Tahoma,13 */ - lstrcpyW(lf.lfFaceName, Tahoma); + lstrcpyW(lf.lfFaceName, L"Tahoma"); lf.lfHeight = 13; stat = GdipCreateFontFromLogfontW(hdc, &lf, &font); expect(Ok, stat); @@ -734,14 +793,14 @@ static void test_font_metrics(void) gdip_get_font_metrics(font, &fm_gdip); trace("gdiplus:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent, fm_gdip.font_height, fm_gdip.font_size); gdi_get_font_metrics(&lf, &fm_gdi); trace("gdi:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, fm_gdi.font_height, fm_gdi.font_size); @@ -750,10 +809,10 @@ static void test_font_metrics(void) stat = GdipGetLogFontW(font, graphics, &lf); expect(Ok, stat); - ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight); + ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %ld\n", lf.lfHeight); gdi_get_font_metrics(&lf, &fm_gdi); trace("gdi:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, fm_gdi.font_height, fm_gdi.font_size); @@ -763,7 +822,7 @@ static void test_font_metrics(void) GdipDeleteFont(font); - stat = GdipCreateFontFamilyFromName(Tahoma, NULL, &family); + stat = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &family); expect(Ok, stat); /* Tahoma,13 */ @@ -772,17 +831,17 @@ static void test_font_metrics(void) gdip_get_font_metrics(font, &fm_gdip); trace("gdiplus:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdip.em_height, fm_gdip.line_spacing, fm_gdip.ascent, fm_gdip.descent, fm_gdip.font_height, fm_gdip.font_size); stat = GdipGetLogFontW(font, graphics, &lf); expect(Ok, stat); - ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %d\n", lf.lfHeight); + ok(lf.lfHeight < 0, "lf.lfHeight should be negative, got %ld\n", lf.lfHeight); gdi_get_font_metrics(&lf, &fm_gdi); trace("gdi:\n"); - trace("%s,%d: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", + trace("%s,%ld: EmHeight %u, LineSpacing %u, CellAscent %u, CellDescent %u, FontHeight %f, FontSize %f\n", wine_dbgstr_w(lf.lfFaceName), lf.lfHeight, fm_gdi.em_height, fm_gdi.line_spacing, fm_gdi.ascent, fm_gdi.descent, fm_gdi.font_height, fm_gdi.font_size); @@ -806,52 +865,43 @@ static void test_font_metrics(void) static void test_font_substitution(void) { - WCHAR ms_shell_dlg[LF_FACESIZE]; char fallback_font[LF_FACESIZE]; HDC hdc; - HFONT hfont; LOGFONTA lf; GpStatus status; GpGraphics *graphics; GpFont *font; GpFontFamily *family; - int ret; hdc = CreateCompatibleDC(0); status = GdipCreateFromHDC(hdc, &graphics); expect(Ok, status); - hfont = GetStockObject(DEFAULT_GUI_FONT); - ok(hfont != 0, "GetStockObject(DEFAULT_GUI_FONT) failed\n"); - - memset(&lf, 0xfe, sizeof(lf)); - ret = GetObjectA(hfont, sizeof(lf), &lf); - ok(ret == sizeof(lf), "GetObject failed\n"); - ok(!lstrcmpA(lf.lfFaceName, "MS Shell Dlg"), "wrong face name %s\n", lf.lfFaceName); - MultiByteToWideChar(CP_ACP, 0, lf.lfFaceName, -1, ms_shell_dlg, LF_FACESIZE); + memset(&lf, 0, sizeof(lf)); + lstrcpyA(lf.lfFaceName, "MS Shell Dlg"); status = GdipCreateFontFromLogfontA(hdc, &lf, &font); expect(Ok, status); memset(&lf, 0xfe, sizeof(lf)); status = GdipGetLogFontA(font, graphics, &lf); expect(Ok, status); - ok(!lstrcmpA(lf.lfFaceName, "Microsoft Sans Serif") || - !lstrcmpA(lf.lfFaceName, "Tahoma"), "wrong face name %s\n", lf.lfFaceName); + ok(lstrcmpA(lf.lfFaceName, "MS Shell Dlg") != 0, "expected substitution of MS Shell Dlg\n"); GdipDeleteFont(font); - status = GdipCreateFontFamilyFromName(ms_shell_dlg, NULL, &family); + family = NULL; + status = GdipCreateFontFamilyFromName(L"MS Shell Dlg", NULL, &family); expect(Ok, status); + font = NULL; status = GdipCreateFont(family, 12, FontStyleRegular, UnitPoint, &font); expect(Ok, status); memset(&lf, 0xfe, sizeof(lf)); status = GdipGetLogFontA(font, graphics, &lf); expect(Ok, status); - ok(!lstrcmpA(lf.lfFaceName, "Microsoft Sans Serif") || - !lstrcmpA(lf.lfFaceName, "Tahoma"), "wrong face name %s\n", lf.lfFaceName); + ok(lstrcmpA(lf.lfFaceName, "MS Shell Dlg") != 0, "expected substitution of MS Shell Dlg\n"); GdipDeleteFont(font); GdipDeleteFontFamily(family); - status = GdipCreateFontFamilyFromName(nonexistent, NULL, &family); + status = GdipCreateFontFamilyFromName(L"ThisFontShouldNotExist", NULL, &family); ok(status == FontFamilyNotFound, "expected FontFamilyNotFound, got %d\n", status); /* nonexistent fonts fallback to Arial, or something else if it's missing */ @@ -889,7 +939,7 @@ static void test_font_substitution(void) lstrcpyA(lf.lfFaceName, "ThisFontShouldNotExist"); font = NULL; status = GdipCreateFontFromLogfontA(hdc, &lf, &font); -todo_wine + todo_wine ok(status == NotTrueTypeFont || broken(status == FileNotFound), /* before XP */ "expected NotTrueTypeFont, got %d\n", status); /* FIXME: remove when wine is fixed */ @@ -899,7 +949,7 @@ todo_wine lf.lfFaceName[0] = 0; font = NULL; status = GdipCreateFontFromLogfontA(hdc, &lf, &font); -todo_wine + todo_wine ok(status == NotTrueTypeFont || broken(status == FileNotFound), /* before XP */ "expected NotTrueTypeFont, got %d\n", status); /* FIXME: remove when wine is fixed */ @@ -911,7 +961,7 @@ todo_wine static void test_font_transform(void) { - static const WCHAR string[] = { 'A',0 }; + static const WCHAR string[] = L"A"; GpStatus status; HDC hdc; LOGFONTA lf; @@ -964,7 +1014,7 @@ static void test_font_transform(void) expect(Ok, status); expectf(0.0, bounds.X); expectf(0.0, bounds.Y); -todo_wine + todo_wine expectf(height + margin_y, bounds.Height); set_rect_empty(&rect); set_rect_empty(&bounds); @@ -1008,7 +1058,7 @@ todo_wine expect(Ok, status); expectf(0.0, bounds.X); expectf(0.0, bounds.Y); -todo_wine + todo_wine expectf(height + margin_y, bounds.Height); set_rect_empty(&rect); set_rect_empty(&bounds); @@ -1029,9 +1079,9 @@ todo_wine DriverStringOptionsCmapLookup, matrix, &bounds); expect(Ok, status); expectf(0.0, bounds.X); -todo_wine + todo_wine expectf_(-300.0, bounds.Y, 0.15); -todo_wine + todo_wine expectf(height * 3.0, bounds.Height); /* scale + ratate matrix */ @@ -1054,7 +1104,7 @@ todo_wine expect(Ok, status); expectf(0.0, bounds.X); expectf(0.0, bounds.Y); -todo_wine + todo_wine expectf(height + margin_y, bounds.Height); set_rect_empty(&rect); set_rect_empty(&bounds); @@ -1074,11 +1124,11 @@ todo_wine status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos, DriverStringOptionsCmapLookup, matrix, &bounds); expect(Ok, status); -todo_wine + todo_wine expectf_(-43.814377, bounds.X, 0.05); -todo_wine + todo_wine expectf_(-212.235611, bounds.Y, 0.05); -todo_wine + todo_wine expectf_(340.847534, bounds.Height, 0.05); /* scale + ratate + shear matrix */ @@ -1088,7 +1138,7 @@ todo_wine expect(Ok, status); status = GdipGetLogFontA(font, graphics, &lf); expect(Ok, status); -todo_wine + todo_wine expect(1032, lf.lfHeight); expect(0, lf.lfWidth); expect_(3099, lf.lfEscapement, 1); @@ -1102,7 +1152,7 @@ todo_wine expect(Ok, status); expectf(0.0, bounds.X); expectf(0.0, bounds.Y); -todo_wine + todo_wine expectf(height + margin_y, bounds.Height); set_rect_empty(&rect); set_rect_empty(&bounds); @@ -1122,11 +1172,11 @@ todo_wine status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos, DriverStringOptionsCmapLookup, matrix, &bounds); expect(Ok, status); -todo_wine + todo_wine expectf_(-636.706848, bounds.X, 0.05); -todo_wine + todo_wine expectf_(-175.257523, bounds.Y, 0.05); -todo_wine + todo_wine expectf_(1532.984985, bounds.Height, 0.05); /* scale + ratate + shear + translate matrix */ @@ -1136,7 +1186,7 @@ todo_wine expect(Ok, status); status = GdipGetLogFontA(font, graphics, &lf); expect(Ok, status); -todo_wine + todo_wine expect(1032, lf.lfHeight); expect(0, lf.lfWidth); expect_(3099, lf.lfEscapement, 1); @@ -1150,7 +1200,7 @@ todo_wine expect(Ok, status); expectf(0.0, bounds.X); expectf(0.0, bounds.Y); -todo_wine + todo_wine expectf(height + margin_y, bounds.Height); set_rect_empty(&rect); set_rect_empty(&bounds); @@ -1170,11 +1220,11 @@ todo_wine status = GdipMeasureDriverString(graphics, (const UINT16 *)string, -1, font, pos, DriverStringOptionsCmapLookup, matrix, &bounds); expect(Ok, status); -todo_wine + todo_wine expectf_(-626.706848, bounds.X, 0.05); -todo_wine + todo_wine expectf_(-155.257523, bounds.Y, 0.05); -todo_wine + todo_wine expectf_(1532.984985, bounds.Height, 0.05); GdipDeleteMatrix(matrix); @@ -1187,8 +1237,9 @@ todo_wine static void test_GdipGetFontCollectionFamilyList(void) { - GpFontFamily *family, *family2; + GpFontFamily *family, *family2, **families; GpFontCollection *collection; + UINT i; INT found, count; GpStatus status; @@ -1228,15 +1279,31 @@ static void test_GdipGetFontCollectionFamilyList(void) ok(found == 1, "Unexpected list count %d.\n", found); ok(family != NULL, "Expected family instance.\n"); - family = NULL; + family2 = NULL; found = 0; status = GdipGetFontCollectionFamilyList(collection, 1, &family2, &found); ok(status == Ok, "Failed to get family list, status %d.\n", status); ok(found == 1, "Unexpected list count %d.\n", found); - ok(family2 != family, "Unexpected family instance.\n"); + ok(family2 == family, "Unexpected family instance.\n"); - GdipDeleteFontFamily(family); - GdipDeleteFontFamily(family2); + status = GdipDeleteFontFamily(family); + expect(Ok, status); + + status = GdipDeleteFontFamily(family2); + expect(Ok, status); + + families = GdipAlloc((count + 1) * sizeof(*families)); + found = 0; + status = GdipGetFontCollectionFamilyList(collection, count + 1, families, &found); + ok(status == Ok, "Failed to get family list, status %d.\n", status); + ok(found == count, "Unexpected list count %d, extected %d.\n", found, count); + + for (i = 0; i < found; i++) + { + status = GdipDeleteFontFamily(families[i]); + expect(Ok, status); + } + GdipFree(families); } static void test_GdipGetFontCollectionFamilyCount(void) @@ -1260,6 +1327,107 @@ static void test_GdipGetFontCollectionFamilyCount(void) ok(status == InvalidParameter, "Unexpected status %d.\n", status); } +static BOOL is_family_in_collection(GpFontCollection *collection, GpFontFamily *family) +{ + GpStatus status; + GpFontFamily **list; + int count, i; + BOOL found = FALSE; + + status = GdipGetFontCollectionFamilyCount(collection, &count); + expect(Ok, status); + + list = GdipAlloc(count * sizeof(GpFontFamily *)); + status = GdipGetFontCollectionFamilyList(collection, count, list, &count); + expect(Ok, status); + + for (i = 0; i < count; i++) + { + if (list[i] == family) + { + found = TRUE; + break; + } + } + + GdipFree(list); + + return found; +} + +static void test_CloneFont(void) +{ + GpStatus status; + GpFontCollection *collection, *collection2; + GpFont *font, *font2; + GpFontFamily *family, *family2; + REAL height; + Unit unit; + int style; + BOOL ret; + + status = GdipNewInstalledFontCollection(&collection); + expect(Ok, status); + + status = GdipNewInstalledFontCollection(&collection2); + expect(Ok, status); + ok(collection == collection2, "got %p\n", collection2); + + status = GdipCreateFontFamilyFromName(L"ThisFontShouldNotExist", NULL, &family); + expect(FontFamilyNotFound, status); + + status = GdipCreateFontFamilyFromName(L"ThisFontShouldNotExist", collection, &family); + expect(FontFamilyNotFound, status); + + status = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &family); + expect(Ok, status); + + ret = is_family_in_collection(collection, family); + ok(ret, "family is not in collection\n"); + + status = GdipCreateFont(family, 30.0f, FontStyleRegular, UnitPixel, &font); + expect(Ok, status); + + status = GdipGetFontUnit(font, &unit); + expect(Ok, status); + ok(unit == UnitPixel, "got %u\n", unit); + + status = GdipGetFontSize(font, &height); + expect(Ok, status); + ok(height == 30.0f, "got %f\n", height); + + status = GdipGetFontStyle(font, &style); + expect(Ok, status); + ok(style == FontStyleRegular, "got %d\n", style); + + status = GdipGetFamily(font, &family2); + expect(Ok, status); + ok(family == family2, "got %p\n", family2); + + status = GdipCloneFont(font, &font2); + expect(Ok, status); + + status = GdipGetFontUnit(font2, &unit); + expect(Ok, status); + ok(unit == UnitPixel, "got %u\n", unit); + + status = GdipGetFontSize(font2, &height); + expect(Ok, status); + ok(height == 30.0f, "got %f\n", height); + + status = GdipGetFontStyle(font2, &style); + expect(Ok, status); + ok(style == FontStyleRegular, "got %d\n", style); + + status = GdipGetFamily(font2, &family2); + expect(Ok, status); + ok(family == family2, "got %p\n", family2); + + GdipDeleteFont(font2); + GdipDeleteFont(font); + GdipDeleteFontFamily(family); +} + START_TEST(font) { struct GdiplusStartupInput gdiplusStartupInput; @@ -1279,6 +1447,7 @@ START_TEST(font) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + test_CloneFont(); test_long_name(); test_font_transform(); test_font_substitution(); diff --git a/modules/rostests/winetests/gdiplus/graphics.c b/modules/rostests/winetests/gdiplus/graphics.c index f2ff589ab5b..0ee2b73c413 100644 --- a/modules/rostests/winetests/gdiplus/graphics.c +++ b/modules/rostests/winetests/gdiplus/graphics.c @@ -23,6 +23,7 @@ #include "objbase.h" #include "gdiplus.h" +#include "winspool.h" #include "wine/test.h" #define expect(expected, got) ok((got) == (expected), "Expected %d, got %d\n", (INT)(expected), (INT)(got)) @@ -1312,21 +1313,20 @@ static void test_GdipDrawImagePointsRect(void) GpGraphics *graphics = NULL; GpPointF ptf[4]; GpBitmap *bm = NULL; - BYTE rbmi[sizeof(BITMAPINFOHEADER)]; BYTE buff[400]; - BITMAPINFO *bmi = (BITMAPINFO*)rbmi; + BITMAPINFOHEADER bmihdr; HDC hdc = GetDC( hwnd ); if (!hdc) return; - memset(rbmi, 0, sizeof(rbmi)); - bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi->bmiHeader.biWidth = 10; - bmi->bmiHeader.biHeight = 10; - bmi->bmiHeader.biPlanes = 1; - bmi->bmiHeader.biBitCount = 32; - bmi->bmiHeader.biCompression = BI_RGB; - status = GdipCreateBitmapFromGdiDib(bmi, buff, &bm); + memset(&bmihdr, 0, sizeof(bmihdr)); + bmihdr.biSize = sizeof(BITMAPINFOHEADER); + bmihdr.biWidth = 10; + bmihdr.biHeight = 10; + bmihdr.biPlanes = 1; + bmihdr.biBitCount = 32; + bmihdr.biCompression = BI_RGB; + status = GdipCreateBitmapFromGdiDib((BITMAPINFO*)&bmihdr, buff, &bm); expect(Ok, status); ok(NULL != bm, "Expected bitmap to be initialized\n"); status = GdipCreateFromHDC(hdc, &graphics); @@ -2279,7 +2279,7 @@ static void test_GdipDrawString(void) GpBrush *brush; LOGFONTA logfont; HDC hdc = GetDC( hwnd ); - static const WCHAR string[] = {'T','e','s','t',0}; + static const WCHAR string[] = L"Test"; static const PointF positions[4] = {{0,0}, {1,1}, {2,2}, {3,3}}; GpMatrix *matrix; @@ -3178,7 +3178,7 @@ static void test_GdipGetNearestColor(void) todo_wine ok(color == 0xffa8b8e8 || broken(color == 0xffa0b8e0), /* Win98/WinMe */ - "Expected ffa8b8e8, got %.8x\n", color); + "Expected ffa8b8e8, got %.8lx\n", color); GdipDeleteGraphics(graphics); GdipDisposeImage((GpImage*)bitmap); @@ -3195,9 +3195,8 @@ static void test_string_functions(void) GpBrush *brush; ARGB color = 0xff000000; HDC hdc = GetDC( hwnd ); - const WCHAR fontname[] = {'T','a','h','o','m','a',0}; - const WCHAR teststring[] = {'M','M',' ','M','\n','M',0}; - const WCHAR teststring2[] = {'j',0}; + const WCHAR teststring[] = L"MM M\nM"; + const WCHAR teststring2[] = L"j"; REAL char_width, char_height; INT codepointsfitted, linesfilled; GpStringFormat *format; @@ -3213,7 +3212,7 @@ static void test_string_functions(void) expect(Ok, status); ok(graphics != NULL, "Expected graphics to be initialized\n"); - status = GdipCreateFontFamilyFromName(fontname, NULL, &family); + status = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &family); expect(Ok, status); status = GdipCreateFont(family, 10.0, FontStyleRegular, UnitPixel, &font); @@ -3744,8 +3743,7 @@ static void test_GdipMeasureString(void) { 200.0, 600.0, 1.0, UnitPixel }, { 200.0, 600.0, 2.0, UnitPixel }, }; - static const WCHAR tahomaW[] = { 'T','a','h','o','m','a',0 }; - static const WCHAR string[] = { '1','2','3','4','5','6','7',0 }; + static const WCHAR string[] = L"1234567"; GpStatus status; GpGraphics *graphics; GpFontFamily *family; @@ -3761,7 +3759,7 @@ static void test_GdipMeasureString(void) status = GdipCreateStringFormat(0, LANG_NEUTRAL, &format); expect(Ok, status); - status = GdipCreateFontFamilyFromName(tahomaW, NULL, &family); + status = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &family); expect(Ok, status); /* font size in pixels */ @@ -3786,7 +3784,7 @@ static void test_GdipMeasureString(void) height = units_to_pixels(font_size, td[i].unit, td[i].res_y); if (td[i].unit != UnitDisplay) height *= td[i].page_scale; - ok(-lf.lfHeight == (LONG)(height + 0.5), "%u: expected %d (%f), got %d\n", + ok(-lf.lfHeight == (LONG)(height + 0.5), "%u: expected %ld (%f), got %ld\n", i, (LONG)(height + 0.5), height, lf.lfHeight); height = font_size + 2.0 * font_size / 6.0; @@ -3804,7 +3802,7 @@ static void test_GdipMeasureString(void) expectf(0.0, bounds.X); expectf(0.0, bounds.Y); -todo_wine + todo_wine expectf_(height, bounds.Height, height / 100.0); expectf_(bounds.Height / base_cy, bounds.Width / base_cx, 0.1); expect(7, chars); @@ -3821,7 +3819,7 @@ todo_wine expect(Ok, status); expectf(50.0, bounds.X); expectf(50.0, bounds.Y); -todo_wine + todo_wine expectf_(height, bounds.Height, height / 100.0); expectf_(bounds.Height / base_cy, bounds.Width / base_cx, 0.1); expect(7, chars); @@ -3867,7 +3865,7 @@ todo_wine else height = units_to_pixels(font_size, font_unit, td[i].res_y); /*trace("%.1f font units = %f pixels with %.1f dpi, page_scale %.1f\n", font_size, height, td[i].res_y, td[i].page_scale);*/ - ok(-lf.lfHeight == (LONG)(height + 0.5), "%u: expected %d (%f), got %d\n", + ok(-lf.lfHeight == (LONG)(height + 0.5), "%u: expected %ld (%f), got %ld\n", i, (LONG)(height + 0.5), height, lf.lfHeight); if (td[i].unit == UnitDisplay || td[i].unit == UnitPixel) @@ -3893,7 +3891,7 @@ todo_wine expectf(0.0, bounds.X); expectf(0.0, bounds.Y); -todo_wine + todo_wine expectf_(height, bounds.Height, height / 85.0); expectf_(bounds.Height / base_cy, bounds.Width / base_cx, 0.1); expect(7, chars); @@ -3910,7 +3908,7 @@ todo_wine expect(Ok, status); expectf(50.0, bounds.X); expectf(50.0, bounds.Y); -todo_wine + todo_wine expectf_(height, bounds.Height, height / 85.0); expectf_(bounds.Height / base_cy, bounds.Width / base_cx, 0.1); expect(7, chars); @@ -3922,7 +3920,7 @@ todo_wine height *= td[i].page_scale; /*trace("%u: unit %u, %.1fx%.1f dpi, scale %.1f, height %f, pixels %f\n", i, td[i].unit, td[i].res_x, td[i].res_y, td[i].page_scale, bounds.Height, height);*/ -todo_wine + todo_wine expectf_(100.0, height, 1.1); status = GdipDeleteGraphics(graphics); @@ -3957,7 +3955,7 @@ todo_wine lf.lfHeight = 0xdeadbeef; status = GdipGetLogFontW(font, graphics, &lf); expect(Ok, status); - ok(lf.lfHeight == -100, "%u: expected -100, got %d\n", i, lf.lfHeight); + ok(lf.lfHeight == -100, "%u: expected -100, got %ld\n", i, lf.lfHeight); set_rect_empty(&rc); set_rect_empty(&bounds); @@ -4141,7 +4139,7 @@ static void test_pen_thickness(void) size = max-min+1; - ok(size == td[i].cx, "%u: expected %d, got %d\n", i, td[i].cx, size); + ok(size == td[i].cx || broken (i == 1 && size == 1), "%u: expected %d, got %d\n", i, td[i].cx, size); min = -1; max = -2; @@ -4166,7 +4164,7 @@ static void test_pen_thickness(void) size = max-min+1; - ok(size == td[i].cy, "%u: expected %d, got %d\n", i, td[i].cy, size); + ok(size == td[i].cy || broken (i == 1 && size == 1), "%u: expected %d, got %d\n", i, td[i].cy, size); status = GdipBitmapUnlockBits(u.bitmap, &bd); expect(Ok, status); @@ -4259,8 +4257,7 @@ static void test_pen_thickness(void) */ static void test_font_height_scaling(void) { - static const WCHAR tahomaW[] = { 'T','a','h','o','m','a',0 }; - static const WCHAR string[] = { '1','2','3','4','5','6','7',0 }; + static const WCHAR string[] = L"1234567"; HDC hdc; GpStringFormat *format; CharacterRange range = { 0, 7 }; @@ -4281,7 +4278,7 @@ static void test_font_height_scaling(void) status = GdipCreateRegion(®ion); expect(Ok, status); - status = GdipCreateFontFamilyFromName(tahomaW, NULL, &family); + status = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &family); expect(Ok, status); hdc = CreateCompatibleDC(0); @@ -4360,7 +4357,6 @@ static void test_font_height_scaling(void) /* UnitPixel = 2, UnitPoint = 3, UnitInch = 4, UnitDocument = 5, UnitMillimeter = 6 */ for (gfx_unit = 2; gfx_unit <= 6; gfx_unit++) { - static const WCHAR doubleW[2] = { 'W','W' }; RectF bounds_1, bounds_2; REAL margin, margin_y, font_height; int match; @@ -4379,7 +4375,7 @@ static void test_font_height_scaling(void) status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, NULL, NULL); expect(Ok, status); /*trace("bounds: %f,%f,%f,%f\n", bounds.X, bounds.Y, bounds.Width, bounds.Height);*/ -todo_wine + todo_wine expectf_(font_height + margin_y, bounds.Height, 0.005); ptf.X = 0; @@ -4387,25 +4383,25 @@ todo_wine status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &ptf, 1); expect(Ok, status); match = fabs(100.0 - ptf.Y) <= 1.0; -todo_wine + todo_wine ok(match, "Expected 100.0, got %f\n", ptf.Y); /* verify the result */ ptf.Y = units_to_pixels(bounds.Height, gfx_unit, dpi); ptf.Y /= 100.0; match = fabs(100.0 - ptf.Y) <= 1.0; -todo_wine + todo_wine ok(match, "Expected 100.0, got %f\n", ptf.Y); /* bounds.width of 1 glyph: [margin]+[width]+[margin] */ set_rect_empty(&rect); set_rect_empty(&bounds_1); - status = GdipMeasureString(graphics, doubleW, 1, font, &rect, format, &bounds_1, NULL, NULL); + status = GdipMeasureString(graphics, L"W", 1, font, &rect, format, &bounds_1, NULL, NULL); expect(Ok, status); /* bounds.width of 2 identical glyphs: [margin]+[width]+[width]+[margin] */ set_rect_empty(&rect); set_rect_empty(&bounds_2); - status = GdipMeasureString(graphics, doubleW, 2, font, &rect, format, &bounds_2, NULL, NULL); + status = GdipMeasureString(graphics, L"WW", 2, font, &rect, format, &bounds_2, NULL, NULL); expect(Ok, status); /* margin = [bounds.width of 1] - [bounds.width of 2] / 2*/ @@ -4447,10 +4443,10 @@ cleanup: static void test_measure_string(void) { - static const WCHAR tahomaW[] = { 'T','a','h','o','m','a',0 }; - static const WCHAR string[] = { 'A','0','1',0 }; + static const WCHAR string[] = L"A01"; + static const WCHAR string2[] = L"M MM"; HDC hdc; - GpStringFormat *format; + GpStringFormat *format, *format_no_wrap; CharacterRange range; GpRegion *region; GpGraphics *graphics; @@ -4458,7 +4454,7 @@ static void test_measure_string(void) GpFont *font; GpStatus status; RectF bounds, rect; - REAL width, height, width_1, width_2; + REAL width, height, width_1, width_2, width_MM, width_M_M; REAL margin_x, margin_y, width_rgn, height_rgn; int lines, glyphs; @@ -4469,7 +4465,7 @@ static void test_measure_string(void) status = GdipCreateRegion(®ion); expect(Ok, status); - status = GdipCreateFontFamilyFromName(tahomaW, NULL, &family); + status = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &family); expect(Ok, status); hdc = CreateCompatibleDC(0); @@ -4502,7 +4498,7 @@ static void test_measure_string(void) expectf(0.0, bounds.X); expectf(0.0, bounds.Y); expectf(width, bounds.Width); -todo_wine + todo_wine expectf(height / 2.0, bounds.Height); range.First = 0; @@ -4522,7 +4518,7 @@ todo_wine expectf_(5.0 + margin_x, bounds.X, 1.0); expectf(5.0, bounds.Y); expectf_(width - margin_x*2.0, bounds.Width, 1.0); -todo_wine + todo_wine expectf_(height - margin_y, bounds.Height, 1.0); width_rgn = bounds.Width; @@ -4578,7 +4574,7 @@ todo_wine expectf_(5.0 + margin_x, bounds.X, 1.0); expectf(5.0, bounds.Y); expectf_(width_1, bounds.Width, 1.0); -todo_wine + todo_wine expectf_(height - margin_y, bounds.Height, 1.0); status = GdipSetStringFormatFlags(format, StringFormatFlagsNoWrap | StringFormatFlagsNoClip); @@ -4621,7 +4617,7 @@ todo_wine expectf(0.0, bounds.X); expectf(0.0, bounds.Y); expectf_(width, bounds.Width, 0.01); -todo_wine + todo_wine expectf(height, bounds.Height); set_rect_empty(&rect); @@ -4714,7 +4710,7 @@ todo_wine expectf_(5.0 + margin_x, bounds.X, 1.0); expectf(5.0, bounds.Y); expectf_(width - margin_x*2.0, bounds.Width, 1.0); -todo_wine + todo_wine expectf_(height - margin_y, bounds.Height, 1.0); width_rgn = bounds.Width; @@ -4733,9 +4729,9 @@ todo_wine expect(Ok, status); expect(3, glyphs); expect(1, lines); -todo_wine + todo_wine expectf_(5.0 + width/2.0, bounds.X, 0.01); -todo_wine + todo_wine expectf(5.0 + height/2.0, bounds.Y); expectf_(width, bounds.Width, 0.01); expectf(height, bounds.Height); @@ -4749,9 +4745,9 @@ todo_wine expect(Ok, status); expect(3, glyphs); expect(1, lines); -todo_wine + todo_wine expectf_(5.0 - width/2.0, bounds.X, 0.01); -todo_wine + todo_wine expectf(5.0 - height/2.0, bounds.Y); expectf_(width, bounds.Width, 0.01); expectf(height, bounds.Height); @@ -4765,9 +4761,9 @@ todo_wine set_rect_empty(&bounds); status = GdipGetRegionBounds(region, graphics, &bounds); expect(Ok, status); -todo_wine + todo_wine expectf_(5.0 + width_rgn/2.0, bounds.X, 1.0); -todo_wine + todo_wine expectf_(5.0 + height_rgn/2.0, bounds.Y, 1.0); expectf_(width_rgn, bounds.Width, 1.0); expectf_(height_rgn, bounds.Height, 1.0); @@ -4781,9 +4777,9 @@ todo_wine set_rect_empty(&bounds); status = GdipGetRegionBounds(region, graphics, &bounds); expect(Ok, status); -todo_wine + todo_wine expectf_(5.0 - width_rgn/2.0, bounds.X, 1.0); -todo_wine + todo_wine expectf_(5.0 - height_rgn/2.0, bounds.Y, 1.0); expectf_(width_rgn, bounds.Width, 1.0); expectf_(height_rgn, bounds.Height, 1.0); @@ -4801,9 +4797,9 @@ todo_wine expect(Ok, status); expect(3, glyphs); expect(1, lines); -todo_wine + todo_wine expectf_(5.0 + width, bounds.X, 0.01); -todo_wine + todo_wine expectf(5.0 + height, bounds.Y); expectf_(width, bounds.Width, 0.01); expectf(height, bounds.Height); @@ -4817,9 +4813,9 @@ todo_wine expect(Ok, status); expect(3, glyphs); expect(1, lines); -todo_wine + todo_wine expectf_(5.0 - width, bounds.X, 0.01); -todo_wine + todo_wine expectf(5.0 - height, bounds.Y); expectf_(width, bounds.Width, 0.01); expectf(height, bounds.Height); @@ -4833,9 +4829,9 @@ todo_wine set_rect_empty(&bounds); status = GdipGetRegionBounds(region, graphics, &bounds); expect(Ok, status); -todo_wine + todo_wine expectf_(5.0 + width_rgn, bounds.X, 2.0); -todo_wine + todo_wine expectf_(5.0 + height_rgn, bounds.Y, 1.0); expectf_(width_rgn, bounds.Width, 1.0); expectf_(height_rgn, bounds.Height, 1.0); @@ -4849,13 +4845,60 @@ todo_wine set_rect_empty(&bounds); status = GdipGetRegionBounds(region, graphics, &bounds); expect(Ok, status); -todo_wine + todo_wine expectf_(5.0 - width_rgn, bounds.X, 2.0); -todo_wine + todo_wine expectf_(5.0 - height_rgn, bounds.Y, 1.0); expectf_(width_rgn, bounds.Width, 1.0); expectf_(height_rgn, bounds.Height, 1.0); + /* Measure "MM" */ + rect.X = 5.0; + rect.Y = 5.0; + rect.Width = 32000.0; + rect.Height = 32000.0; + status = GdipMeasureString(graphics, string2 + 2, 2, font, &rect, NULL, &bounds, &glyphs, &lines); + expect(Ok, status); + expect(2, glyphs); + expect(1, lines); + width_MM = bounds.Width; + + /* Measure "M M" */ + rect.X = 5.0; + rect.Y = 5.0; + rect.Width = 32000.0; + rect.Height = 32000.0; + status = GdipMeasureString(graphics, string2, 3, font, &rect, NULL, &bounds, &glyphs, &lines); + expect(Ok, status); + expect(3, glyphs); + expect(1, lines); + width_M_M = bounds.Width; + + /* With wrap */ + rect.X = 5.0; + rect.Y = 5.0; + rect.Width = width_M_M; + rect.Height = 32000.0; + status = GdipMeasureString(graphics, string2, -1, font, &rect, NULL, &bounds, &glyphs, &lines); + expect(Ok, status); + expectf_(width_MM, bounds.Width, 0.1); + expect(4, glyphs); + expect(2, lines); + + /* Without wrap */ + status = GdipCreateStringFormat(StringFormatFlagsNoWrap, LANG_NEUTRAL, &format_no_wrap); + expect(Ok, status); + + rect.X = 5.0; + rect.Y = 5.0; + rect.Width = width_M_M; + rect.Height = 32000.0; + status = GdipMeasureString(graphics, string2, -1, font, &rect, format_no_wrap, &bounds, &glyphs, &lines); + expect(Ok, status); + expectf_(width_M_M, bounds.Width, 0.1); + expect(3, glyphs); + expect(1, lines); + status = GdipDeleteFont(font); expect(Ok, status); @@ -4866,12 +4909,11 @@ todo_wine GdipDeleteFontFamily(family); GdipDeleteRegion(region); GdipDeleteStringFormat(format); + GdipDeleteStringFormat(format_no_wrap); } static void test_measured_extra_space(void) { - static const WCHAR tahomaW[] = { 'T','a','h','o','m','a',0 }; - static const WCHAR string[2] = { 'W','W' }; GpStringFormat *format; HDC hdc; GpGraphics *graphics; @@ -4885,7 +4927,7 @@ static void test_measured_extra_space(void) status = GdipCreateStringFormat(0, LANG_NEUTRAL, &format); expect(Ok, status); - status = GdipCreateFontFamilyFromName(tahomaW, NULL, &family); + status = GdipCreateFontFamilyFromName(L"Tahoma", NULL, &family); expect(Ok, status); hdc = CreateCompatibleDC(0); status = GdipCreateFromHDC(hdc, &graphics); @@ -4915,12 +4957,12 @@ static void test_measured_extra_space(void) /* bounds.width of 1 glyph: [margin]+[width]+[margin] */ set_rect_empty(&rect); set_rect_empty(&bounds_1); - status = GdipMeasureString(graphics, string, 1, font, &rect, format, &bounds_1, NULL, NULL); + status = GdipMeasureString(graphics, L"W", 1, font, &rect, format, &bounds_1, NULL, NULL); expect(Ok, status); /* bounds.width of 2 identical glyphs: [margin]+[width]+[width]+[margin] */ set_rect_empty(&rect); set_rect_empty(&bounds_2); - status = GdipMeasureString(graphics, string, 2, font, &rect, format, &bounds_2, NULL, NULL); + status = GdipMeasureString(graphics, L"WW", 2, font, &rect, format, &bounds_2, NULL, NULL); expect(Ok, status); /* margin = [bounds.width of 1] - [bounds.width of 2] / 2*/ @@ -5071,6 +5113,7 @@ static void test_clipping(void) GpRegion *region, *region100x100; GpMatrix *matrix; GpRectF rect; + GpRect recti; GpPointF ptf[4]; GpUnit unit; HRGN hrgn; @@ -5107,6 +5150,11 @@ static void test_clipping(void) 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); + status = GdipGetClipBoundsI(graphics, &recti); + expect(Ok, status); + ok(recti.X == 100 && recti.Y == 100 && recti.Width == 100 && recti.Height == 100, + "expected 100,100-100,100, got %i,%i-%i,%i\n", recti.X, recti.Y, recti.Width, recti.Height); + /* Clip region does not account for changes to gdi32 transform */ SetViewportOrgEx(hdc, 10, 10, NULL); @@ -5149,6 +5197,11 @@ static void test_clipping(void) ok(rect.X == 45.0 && rect.Y == 20.0 && rect.Width == 50.0 && rect.Height == 25.0, "expected 45.0,20.0-50.0,25.0, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height); + status = GdipGetClipBoundsI(graphics, &recti); + expect(Ok, status); + ok(recti.X == 45 && recti.Y == 20 && recti.Width == 50 && recti.Height == 25, + "expected 45,20-50,25, got %i,%i-%i,%i\n", recti.X, recti.Y, recti.Width, recti.Height); + status = GdipSetEmpty(region); expect(Ok, status); status = GdipGetClip(graphics, region); @@ -6368,7 +6421,7 @@ static DWORD* GetBitmapPixelBuffer(HDC hdc, HBITMAP hbmp, int width, int height) 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()); + ok(lines == height, "Expected GetDIBits:%p,%d->%d,%ld\n", buffer, height, lines, GetLastError()); return buffer; } @@ -6792,6 +6845,385 @@ static void test_hdc_caching(void) DeleteObject(hbm); } +static void test_gdi_interop_bitmap(void) +{ + GpBitmap *bitmap; + GpGraphics *graphics; + GpMatrix *transform; + GpBrush *brush; + GpStatus stat; + HDC hdc; + HBRUSH hbrush, holdbrush; + ARGB color; + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + stat = GdipCreateMatrix(&transform); + expect(Ok, stat); + + stat = GdipSetMatrixElements(transform, 1.0, 0.0, 0.0, 1.0, 50.0, 50.0); + expect(Ok, stat); + + /* GDI+: Set world transform. Should not matter to GDI. */ + stat = GdipSetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &hdc); + expect(Ok, stat); + + hbrush = CreateSolidBrush(0xff0000); + + holdbrush = SelectObject(hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (5, 5) to (12, 10). */ + Rectangle(hdc, 5, 5, 12, 10); + + holdbrush = SelectObject(hdc, holdbrush); + + /* GDI: Set view port origin. Should not matter to GDI+. */ + SetViewportOrgEx(hdc, 20, 20, NULL); + + GdipReleaseDC(graphics, hdc); + + stat = GdipCreateSolidFill((ARGB)0xff0000ff, (GpSolidFill**)&brush); + expect(Ok, stat); + + /* GDI+: Draw a rectangle at physical coords (85, 85) to (88, 95). */ + stat = GdipFillRectangleI(graphics, brush, 35, 35, 3, 10); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &hdc); + expect(Ok, stat); + + holdbrush = SelectObject(hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (25, 25) to (30, 34). + Updated view port origin should still be in effect. */ + Rectangle(hdc, 5, 5, 10, 14); + + SelectObject(hdc, holdbrush); + + DeleteObject(hbrush); + stat = GdipReleaseDC(graphics, hdc); + expect(Ok, stat); + + stat = GdipDeleteMatrix(transform); + expect(Ok, stat); + + stat = GdipBitmapGetPixel(bitmap, 6, 6, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipBitmapGetPixel(bitmap, 26, 26, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipBitmapGetPixel(bitmap, 86, 86, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + stat = GdipDisposeImage((GpImage*)bitmap); + expect(Ok, stat); +} + +static void test_gdi_interop_hdc(void) +{ + BITMAPINFO bmi; + GpBrush *brush; + GpGraphics *graphics; + GpMatrix *transform; + GpStatus stat; + HBITMAP hbm; + HBRUSH hbrush, holdbrush; + HDC gdi_hdc; + HDC src_hdc; + ULONG *bits; + XFORM xform = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; + + src_hdc = CreateCompatibleDC(0); + ok(src_hdc != NULL, "CreateCompatibleDC failed\n"); + + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biHeight = -100; + bmi.bmiHeader.biWidth = 100; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + hbm = CreateDIBSection(src_hdc, &bmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok(hbm != NULL, "CreateDIBSection failed\n"); + + SelectObject(src_hdc, hbm); + + SetGraphicsMode(src_hdc, GM_ADVANCED); + + xform.eDx = 10.0; + xform.eDy = 10.0; + SetWorldTransform(src_hdc, &xform); + + stat = GdipCreateFromHDC(src_hdc, &graphics); + expect(Ok, stat); + + stat = GdipCreateMatrix(&transform); + expect(Ok, stat); + + stat = GdipSetMatrixElements(transform, 1.0, 0.0, 0.0, 1.0, 40.0, 40.0); + expect(Ok, stat); + + /* GDI+: Set world transform. Should not matter to GDI. */ + stat = GdipSetWorldTransform(graphics, transform); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &gdi_hdc); + expect(Ok, stat); + ok( gdi_hdc == src_hdc, "wrong dc\n" ); + + /* GDI: Set GDI transform back to (0, 0). + Should not matter to GDI+. */ + xform.eDx = 0.0; + xform.eDy = 0.0; + SetWorldTransform(gdi_hdc, &xform); + + hbrush = CreateSolidBrush(0xff00aa); + + holdbrush = SelectObject(gdi_hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (5, 5) to (12, 10). */ + Rectangle(gdi_hdc, 5, 5, 12, 10); + + holdbrush = SelectObject(gdi_hdc, holdbrush); + + /* GDI: Set GDI transform to translate (+20, +20). + Should not matter to GDI+. */ + xform.eDx = 20.0; + xform.eDy = 20.0; + SetWorldTransform(gdi_hdc, &xform); + + GdipReleaseDC(graphics, gdi_hdc); + + /* GDI world transform should still be intact, even when back + in GDI+ mode. */ + stat = GetWorldTransform(src_hdc, &xform); + expect(TRUE, stat); + expect(20.0, xform.eDx); + expect(20.0, xform.eDy); + + stat = GdipCreateSolidFill((ARGB)0xffaa00ff, (GpSolidFill**)&brush); + expect(Ok, stat); + + /* GDI+: Draw a rectangle at physical coords (85, 85) to (88, 95). + The fact that the GDI world transform has been updated should + not influence the GDI+ world transform. GDI+ should still apply + the world transform from the when HDC backed graphics object was + instantiated. */ + stat = GdipFillRectangleI(graphics, brush, 35, 35, 3, 10); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &gdi_hdc); + expect(Ok, stat); + + holdbrush = SelectObject(gdi_hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (25, 25) to (30, 34). + Updated transform should still be in effect. */ + Rectangle(gdi_hdc, 5, 5, 10, 14); + + SelectObject(gdi_hdc, holdbrush); + + stat = GdipReleaseDC(graphics, gdi_hdc); + expect(Ok, stat); + + GdipDeleteGraphics(graphics); + stat = GdipDeleteMatrix(transform); + expect(Ok, stat); + + holdbrush = SelectObject(src_hdc, hbrush); + + /* GDI: Draw a rectangle at physical coords (35, 35) to (40, 38). + Updated transform should still be in effect on src_hdc. */ + Rectangle(gdi_hdc, 15, 15, 20, 18); + + SelectObject(gdi_hdc, holdbrush); + + DeleteObject(hbrush); + + expect(0x00aa00ff, bits[6 * 100 + 6]); + expect(0x00aa00ff, bits[26 * 100 + 26]); + expect(0x00aa00ff, bits[36 * 100 + 36]); + expect(0xffaa00ff, bits[86 * 100 + 86]); + + DeleteDC(src_hdc); + DeleteObject(hbm); +} + +static HDC create_printer_dc(void) +{ + char buffer[260]; + DWORD len; + PRINTER_INFO_2A *pbuf = NULL; + DRIVER_INFO_3A *dbuf = NULL; + HANDLE hprn = 0; + HDC hdc = 0; + HMODULE winspool = LoadLibraryA("winspool.drv"); + BOOL (WINAPI *pOpenPrinterA)(LPSTR, HANDLE *, LPPRINTER_DEFAULTSA); + BOOL (WINAPI *pGetDefaultPrinterA)(LPSTR, LPDWORD); + BOOL (WINAPI *pGetPrinterA)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD); + BOOL (WINAPI *pGetPrinterDriverA)(HANDLE, LPSTR, DWORD, LPBYTE, DWORD, LPDWORD); + BOOL (WINAPI *pClosePrinter)(HANDLE); + + pGetDefaultPrinterA = (void *)GetProcAddress(winspool, "GetDefaultPrinterA"); + pOpenPrinterA = (void *)GetProcAddress(winspool, "OpenPrinterA"); + pGetPrinterA = (void *)GetProcAddress(winspool, "GetPrinterA"); + pGetPrinterDriverA = (void *)GetProcAddress(winspool, "GetPrinterDriverA"); + pClosePrinter = (void *)GetProcAddress(winspool, "ClosePrinter"); + + if (!pGetDefaultPrinterA || !pOpenPrinterA || !pGetPrinterA || !pGetPrinterDriverA || !pClosePrinter) + goto done; + + len = sizeof(buffer); + if (!pGetDefaultPrinterA(buffer, &len)) goto done; + if (!pOpenPrinterA(buffer, &hprn, NULL)) goto done; + + pGetPrinterA(hprn, 2, NULL, 0, &len); + pbuf = HeapAlloc(GetProcessHeap(), 0, len); + if (!pGetPrinterA(hprn, 2, (LPBYTE)pbuf, len, &len)) goto done; + + pGetPrinterDriverA(hprn, NULL, 3, NULL, 0, &len); + dbuf = HeapAlloc(GetProcessHeap(), 0, len); + if (!pGetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, len, &len)) goto done; + + hdc = CreateDCA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, pbuf->pDevMode); + trace("hdc %p for driver '%s' printer '%s' port '%s'\n", hdc, + dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName); +done: + HeapFree(GetProcessHeap(), 0, dbuf); + HeapFree(GetProcessHeap(), 0, pbuf); + if (hprn) pClosePrinter(hprn); + if (winspool) FreeLibrary(winspool); + return hdc; +} + +static BOOL check_rect_pixels(const DWORD *pixel, const RectF *rect, UINT width, DWORD expected, Point *failed) +{ + UINT x, y; + BOOL ret = TRUE; + + for (y = (UINT)rect->Y; y < (UINT)(rect->Y + rect->Height); y++) + { + for (x = (UINT)rect->X; x < (UINT)(rect->X + rect->Width); x++) + { + if (pixel[x + y * width] != expected) + { + ret = FALSE; + goto done; + } + } + } + +done: + if (!ret) + { + failed->X = x; + failed->Y = y; + } + else + { + failed->X = 0; + failed->Y = 0; + } + return ret; +} + +static void test_printer_dc(void) +{ + HDC hdc_printer, hdc; + Status status; + GpGraphics *graphics; + REAL dpi_x, dpi_y, pixel_per_unit_x, pixel_per_unit_y; + HBITMAP bitmap; + UINT width = 16, height = 16; + GpUnit unit; + GpSolidFill *brush; + DWORD *pixel; + BOOL match; + RectF rect; + Point pt; + + hdc_printer = create_printer_dc(); + if (!hdc_printer) + { + skip("could not create a DC for the default printer\n"); + return; + } + + hdc = CreateCompatibleDC(hdc_printer); + bitmap = CreateCompatibleBitmap(hdc, width, height); + SelectObject(hdc, bitmap); + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + GdipGetPageUnit(graphics, &unit); + expect(UnitDisplay, unit); + + GdipGetDpiX(graphics, &dpi_x); + GdipGetDpiY(graphics, &dpi_y); + expectf((REAL)GetDeviceCaps(hdc, LOGPIXELSX), dpi_x); + expectf((REAL)GetDeviceCaps(hdc, LOGPIXELSY), dpi_y); + + /* For graphics created from printer DC, UnitDisplay specifies that a unit is 1/100 inch */ + pixel_per_unit_x = dpi_x / 100.0; + pixel_per_unit_y = dpi_y / 100.0; + + status = GdipCreateSolidFill((ARGB)0xffffffff, &brush); + expect(Ok, status); + + status = GdipFillRectangleI(graphics, (GpBrush *)brush, 1, 1, 1, 1); + expect(Ok, status); + + pixel = GetBitmapPixelBuffer(hdc, bitmap, width, height); + + /* pixels at (0, 0) should all be 0 */ + rect.X = 0; + rect.Y = 0; + rect.Width = pixel_per_unit_x; + rect.Height = pixel_per_unit_y; + match = check_rect_pixels(pixel, &rect, width, 0, &pt); + ok(match, "Expected pixel (%u, %u) to be %08x, got %08lx\n", + pt.X, pt.Y, 0, pixel[pt.X + pt.Y * width]); + + /* pixels at (1, 1) should all be 0x00ffffff */ + rect.X = pixel_per_unit_x; + rect.Y = pixel_per_unit_y; + rect.Width = pixel_per_unit_x; + rect.Height = pixel_per_unit_y; + match = check_rect_pixels(pixel, &rect, width, 0x00ffffff, &pt); + ok(match, "Expected pixel (%u, %u) to be %08x, got %08lx\n", + pt.X, pt.Y, 0x00ffffff, pixel[pt.X + pt.Y * width]); + + GdipFree(pixel); + GdipDeleteBrush((GpBrush *)brush); + GdipDeleteGraphics(graphics); + DeleteObject(bitmap); + DeleteDC(hdc); + DeleteDC(hdc_printer); +} + START_TEST(graphics) { struct GdiplusStartupInput gdiplusStartupInput; @@ -6885,6 +7317,9 @@ START_TEST(graphics) test_GdipGraphicsSetAbort(); test_cliphrgn_transform(); test_hdc_caching(); + test_gdi_interop_bitmap(); + test_gdi_interop_hdc(); + test_printer_dc(); GdiplusShutdown(gdiplusToken); DestroyWindow( hwnd ); diff --git a/modules/rostests/winetests/gdiplus/graphicspath.c b/modules/rostests/winetests/gdiplus/graphicspath.c index 096fbc600ab..07e6dd166ad 100644 --- a/modules/rostests/winetests/gdiplus/graphicspath.c +++ b/modules/rostests/winetests/gdiplus/graphicspath.c @@ -75,7 +75,10 @@ typedef struct int todo; } path_test_t; -static void ok_path(GpPath* path, const path_test_t *expected, INT expected_size, BOOL todo_size) +#define ok_path(a,b,c,d) _ok_path_fudge(a,b,c,d,2.0,__LINE__) +#define ok_path_fudge(a,b,c,d,e) _ok_path_fudge(a,b,c,d,e,__LINE__) +static void _ok_path_fudge(GpPath* path, const path_test_t *expected, INT expected_size, + BOOL todo_size, REAL fudge, int line) { BYTE * types; INT size, idx = 0, eidx = 0, numskip; @@ -88,7 +91,7 @@ static void ok_path(GpPath* path, const path_test_t *expected, INT expected_size } todo_wine_if (todo_size) - ok(size == expected_size, "Path size %d does not match expected size %d\n", + ok_(__FILE__,line)(size == expected_size, "Path size %d does not match expected size %d\n", size, expected_size); points = HeapAlloc(GetProcessHeap(), 0, size * sizeof(GpPointF)); @@ -104,14 +107,14 @@ static void ok_path(GpPath* path, const path_test_t *expected, INT expected_size /* We allow a few pixels fudge in matching X and Y coordinates to account for imprecision in * floating point to integer conversion */ BOOL match = (types[idx] == expected[eidx].type) && - fabs(points[idx].X - expected[eidx].X) <= 2.0 && - fabs(points[idx].Y - expected[eidx].Y) <= 2.0; + fabs(points[idx].X - expected[eidx].X) <= fudge && + fabs(points[idx].Y - expected[eidx].Y) <= fudge; stringify_point_type(expected[eidx].type, ename); stringify_point_type(types[idx], name); todo_wine_if (expected[eidx].todo || numskip) - ok(match, "Expected #%d: %s (%.1f,%.1f) but got %s (%.1f,%.1f)\n", eidx, + ok_(__FILE__,line)(match, "Expected #%d: %s (%.1f,%.1f) but got %s (%.1f,%.1f)\n", eidx, ename, expected[eidx].X, expected[eidx].Y, name, points[idx].X, points[idx].Y); @@ -173,6 +176,115 @@ static void test_getpathdata(void) GdipDeletePath(path); } +static void test_createpath2(void) +{ + GpStatus status; + GpPath* path = NULL; + GpPathData data; + INT i, count, expect_count; + + PointF test_line_points[] = {{1.0,1.0}, {2.0,1.0}, {2.0,2.0}}; + BYTE test_line_types[] = {PathPointTypeStart, PathPointTypeLine, PathPointTypeStart}; + + PointF test_bez_points[] = {{1.0,1.0}, {2.0,1.0}, {3.0,1.0}, {4.0,1.0}, + {5.0,1.0}, {6.0,1.0}, {7.0,1.0}}; + BYTE test_bez_types[] = {PathPointTypeStart, PathPointTypeBezier, + PathPointTypeBezier, PathPointTypeBezier, PathPointTypeBezier, + PathPointTypeBezier, PathPointTypeBezier}; + + status = GdipCreatePath2(test_line_points, test_line_types, 2, FillModeAlternate, &path); + expect(Ok, status); + status = GdipGetPointCount(path, &count); + expect(Ok, status); + expect(2, count); + GdipDeletePath(path); + + status = GdipCreatePath2(test_line_points, test_line_types, 1, FillModeAlternate, &path); + expect(Ok, status); + status = GdipGetPointCount(path, &count); + expect(Ok, status); + expect(1, count); + GdipDeletePath(path); + + path = (void *)0xdeadbeef; + status = GdipCreatePath2(test_line_points, test_line_types, 0, FillModeAlternate, &path); + expect(OutOfMemory, status); + ok(!path, "Expected NULL, got %p\n", path); + if(path && path != (void *)0xdeadbeef) + GdipDeletePath(path); + + path = (void *)0xdeadbeef; + status = GdipCreatePath2(test_line_points, test_line_types, -1, FillModeAlternate, &path); + expect(OutOfMemory, status); + ok(!path, "Expected NULL, got %p\n", path); + if(path && path != (void *)0xdeadbeef) + GdipDeletePath(path); + + path = (void *)0xdeadbeef; + status = GdipCreatePath2(NULL, test_line_types, 2, FillModeAlternate, &path); + expect(InvalidParameter, status); + ok(path == (void *)0xdeadbeef, "Expected %p, got %p\n", (void *)0xdeadbeef, path); + if(path && path != (void *)0xdeadbeef) + GdipDeletePath(path); + + path = (void *)0xdeadbeef; + status = GdipCreatePath2(test_line_points, NULL, 2, FillModeAlternate, &path); + expect(InvalidParameter, status); + ok(path == (void *)0xdeadbeef, "Expected %p, got %p\n", (void *)0xdeadbeef, path); + if(path && path != (void *)0xdeadbeef) + GdipDeletePath(path); + + status = GdipCreatePath2(test_line_points, test_line_types, 2, FillModeAlternate, NULL); + expect(InvalidParameter, status); + + /* Multi-point paths should not end with Start */ + status = GdipCreatePath2(test_line_points, test_line_types, 3, FillModeAlternate, &path); + expect(Ok, status); + status = GdipGetPointCount(path, &count); + expect(Ok, status); + expect(0, count); + GdipDeletePath(path); + + /* Zero-length line points do not get altered */ + test_line_points[1].X = test_line_points[0].X; + test_line_points[1].Y = test_line_points[0].Y; + status = GdipCreatePath2(test_line_points, test_line_types, 2, FillModeAlternate, &path); + expect(Ok, status); + status = GdipGetPointCount(path, &count); + expect(Ok, status); + expect(2, count); + GdipDeletePath(path); + + /* The type of the first point is always converted to PathPointTypeStart */ + test_line_types[0] = PathPointTypeLine; + status = GdipCreatePath2(test_line_points, test_line_types, 1, FillModeAlternate, &path); + expect(Ok, status); + status = GdipGetPointCount(path, &count); + expect(Ok, status); + expect(1, count); + data.Count = count; + data.Types = GdipAlloc(sizeof(BYTE) * count); + data.Points = GdipAlloc(sizeof(PointF) * count); + status = GdipGetPathData(path, &data); + expect(Ok, status); + expect((data.Points[0].X == 1.0) && (data.Points[0].Y == 1.0), TRUE); + expect(data.Types[0], PathPointTypeStart); + GdipFree(data.Points); + GdipFree(data.Types); + GdipDeletePath(path); + + /* Bezier points must come in groups of three */ + for(i = 2; i <= 7; i++) { + expect_count = (i % 3 == 1) ? i : 0; + status = GdipCreatePath2(test_bez_points, test_bez_types, i, FillModeAlternate, &path); + expect(Ok, status); + status = GdipGetPointCount(path, &count); + expect(Ok, status); + expect(expect_count, count); + GdipDeletePath(path); + } +} + static path_test_t line2_path[] = { {0.0, 50.0, PathPointTypeStart, 0, 0}, /*0*/ {5.0, 45.0, PathPointTypeLine, 0, 0}, /*1*/ @@ -198,6 +310,16 @@ static void test_line2(void) } GdipCreatePath(FillModeAlternate, &path); + + status = GdipAddPathLine2(NULL, line2_points, 2); + expect(InvalidParameter, status); + status = GdipAddPathLine2(path, NULL, 2); + expect(InvalidParameter, status); + status = GdipAddPathLine2(path, line2_points, 0); + expect(InvalidParameter, status); + status = GdipAddPathLine2(path, line2_points, -1); + expect(InvalidParameter, status); + status = GdipAddPathLine2(path, line2_points, 3); expect(Ok, status); status = GdipAddPathLine2(path, &(line2_points[3]), 3); @@ -209,6 +331,69 @@ static void test_line2(void) ok_path(path, line2_path, ARRAY_SIZE(line2_path), FALSE); + GdipResetPath(path); + status = GdipAddPathLine2(path, line2_points, 3); + expect(Ok, status); + status = GdipAddPathLine2(path, &(line2_points[2]), 3); + expect(Ok, status); + + ok_path(path, line2_path, 5, FALSE); + + GdipDeletePath(path); +} + +static path_test_t bezier_path[] = { + {10.0, 10.0, PathPointTypeStart, 0, 0}, /*0*/ + {20.0, 10.0, PathPointTypeBezier, 0, 0}, /*1*/ + {20.0, 20.0, PathPointTypeBezier, 0, 0}, /*2*/ + {30.0, 20.0, PathPointTypeBezier, 0, 0}, /*3*/ + {40.0, 20.0, PathPointTypeBezier, 0, 0}, /*4*/ + {40.0, 30.0, PathPointTypeBezier, 0, 0}, /*5*/ + {50.0, 30.0, PathPointTypeBezier, 0, 0}, /*6*/ + {50.0, 10.0, PathPointTypeLine, 0, 0}, /*7*/ + {60.0, 10.0, PathPointTypeBezier, 0, 0}, /*8*/ + {60.0, 20.0, PathPointTypeBezier, 0, 0}, /*9*/ + {70.0, 20.0, PathPointTypeBezier, 0, 0} /*10*/ + }; + +static void test_bezier(void) +{ + GpStatus status; + GpPath* path; + + GdipCreatePath(FillModeAlternate, &path); + + status = GdipAddPathBezier(path, 10.0, 10.0, 20.0, 10.0, 20.0, 20.0, 30.0, 20.0); + expect(Ok, status); + status = GdipAddPathBezier(path, 30.0, 20.0, 40.0, 20.0, 40.0, 30.0, 50.0, 30.0); + expect(Ok, status); + status = GdipAddPathBezier(path, 50.0, 10.0, 60.0, 10.0, 60.0, 20.0, 70.0, 20.0); + expect(Ok, status); + + ok_path(path, bezier_path, ARRAY_SIZE(bezier_path), FALSE); + + GdipDeletePath(path); +} + +static void test_beziers(void) +{ + GpStatus status; + GpPath* path; + PointF bezier_points1[] = {{10.0,10.0}, {20.0,10.0}, {20.0,20.0}, {30.0,20.0}}; + PointF bezier_points2[] = {{30.0,20.0}, {40.0,20.0}, {40.0,30.0}, {50.0,30.0}}; + PointF bezier_points3[] = {{50.0,10.0}, {60.0,10.0}, {60.0,20.0}, {70.0,20.0}}; + + GdipCreatePath(FillModeAlternate, &path); + + status = GdipAddPathBeziers(path, bezier_points1, 4); + expect(Ok, status); + status = GdipAddPathBeziers(path, bezier_points2, 4); + expect(Ok, status); + status = GdipAddPathBeziers(path, bezier_points3, 4); + expect(Ok, status); + + ok_path(path, bezier_path, ARRAY_SIZE(bezier_path), FALSE); + GdipDeletePath(path); } @@ -252,6 +437,13 @@ static path_test_t arc_path[] = { {450.9, 824.1, PathPointTypeBezier, 0, 0}, /*36*/ {540.4, 676.9, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 1} /*37*/ }; +static path_test_t arc_path2[] = { + {1.0, 0.0, PathPointTypeStart, 0, 0}, /*0*/ + {1.0, 0.5, PathPointTypeLine, 0, 0}, /*1*/ + {1.0, 0.776142, PathPointTypeBezier, 0, 0}, /*2*/ + {0.776142, 1.0, PathPointTypeBezier, 0, 0}, /*3*/ + {0.5, 1.0, PathPointTypeBezier, 0, 0} /*4*/ + }; static void test_arc(void) { @@ -280,6 +472,13 @@ static void test_arc(void) ok_path(path, arc_path, ARRAY_SIZE(arc_path), FALSE); + GdipResetPath(path); + GdipAddPathLine(path, 1.0, 0.0, 1.0, 0.5); + status = GdipAddPathArc(path, 0.0, 0.0, 1.0, 1.0, 0.0, 90.0); + expect(Ok, status); + + ok_path_fudge(path, arc_path2, ARRAY_SIZE(arc_path2), FALSE, 0.000005); + GdipDeletePath(path); } @@ -547,7 +746,8 @@ static path_test_t linei_path[] = { {15.00, 15.00, PathPointTypeLine, 0, 0}, /*9*/ {26.00, 28.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*10*/ {35.00, 35.00, PathPointTypeStart, 0, 0}, /*11*/ - {36.00, 38.00, PathPointTypeLine, 0, 0} /*12*/ + {36.00, 38.00, PathPointTypeLine, 0, 0}, /*12*/ + {39.00, 40.00, PathPointTypeLine, 0, 0} /*13*/ }; static void test_linei(void) @@ -564,6 +764,8 @@ static void test_linei(void) GdipClosePathFigure(path); status = GdipAddPathLineI(path, 35.0, 35.0, 36.0, 38.0); expect(Ok, status); + status = GdipAddPathLineI(path, 36, 38, 39, 40); + expect(Ok, status); ok_path(path, linei_path, ARRAY_SIZE(linei_path), FALSE); @@ -1076,6 +1278,13 @@ static path_test_t widenline_dash_path[] = { {45.0, 10.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*7*/ }; +static path_test_t widenline_unit_path[] = { + {5.0, 9.5, PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 9.5, PathPointTypeLine, 0, 0}, /*1*/ + {50.0, 10.5, PathPointTypeLine, 0, 0}, /*2*/ + {5.0, 10.5, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0} /*3*/ + }; + static void test_widen(void) { GpStatus status; @@ -1238,13 +1447,313 @@ static void test_widen(void) status = GdipGetPointCount(path, &count); expect(Ok, status); - todo_wine expect(0, count); + ok(count == 0 || broken(count == 4), "expected 0, got %i\n", count); + + /* pen width = 0 pixels, UnitWorld - result is a path 1 unit wide */ + GdipDeletePen(pen); + status = GdipCreatePen1(0xffffffff, 0.0, UnitWorld, &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); + ok_path_fudge(path, widenline_unit_path, ARRAY_SIZE(widenline_unit_path), FALSE, 0.000005); GdipDeleteMatrix(m); GdipDeletePen(pen); GdipDeletePath(path); } +static path_test_t widenline_capflat_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {50.0, 15.0, PathPointTypeLine, 0, 0}, /*2*/ + {5.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0} /*3*/ + }; + +static path_test_t widenline_capsquare_path[] = { + {0.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {55.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {55.0, 15.0, PathPointTypeLine, 0, 0}, /*2*/ + {0.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0} /*3*/ + }; + +static path_test_t widenline_capround_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {52.761421, 5.0, PathPointTypeBezier, 0, 0}, /*2*/ + {55.0, 7.238576, PathPointTypeBezier, 0, 0}, /*3*/ + {55.0, 10.0, PathPointTypeBezier, 0, 0}, /*4*/ + {55.0, 12.761423, PathPointTypeBezier, 0, 0}, /*5*/ + {52.761421, 15.0, PathPointTypeBezier, 0, 0}, /*6*/ + {50.0, 15.0, PathPointTypeBezier, 0, 0}, /*7*/ + {5.0, 15.0, PathPointTypeLine, 0, 0}, /*8*/ + {2.238576, 15.0, PathPointTypeBezier, 0, 0}, /*9*/ + {0.0, 12.761423, PathPointTypeBezier, 0, 0}, /*10*/ + {0.0, 10.0, PathPointTypeBezier, 0, 0}, /*11*/ + {0.0, 7.238576, PathPointTypeBezier, 0, 0}, /*12*/ + {2.238576, 5.0, PathPointTypeBezier, 0, 0}, /*13*/ + {5.0, 5.0, PathPointTypeBezier|PathPointTypeCloseSubpath, 0, 0}, /*14*/ + }; + +static path_test_t widenline_captriangle_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {55.0, 10.0, PathPointTypeLine, 0, 0}, /*2*/ + {50.0, 15.0, PathPointTypeLine, 0, 0}, /*3*/ + {5.0, 15.0, PathPointTypeLine, 0, 0}, /*4*/ + {0.0, 10.0, PathPointTypeLine, 0, 0}, /*5*/ + {5.0, 5.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0} /*6*/ + }; + +static path_test_t widenline_capsquareanchor_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {50.0, 15.0, PathPointTypeLine, 0, 0}, /*2*/ + {5.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*3*/ + {12.071068, 2.928932, PathPointTypeStart, 0, 0}, /*4*/ + {12.071068, 17.071066, PathPointTypeLine, 0, 0}, /*5*/ + {-2.071068, 17.071066, PathPointTypeLine, 0, 0}, /*6*/ + {-2.071068, 2.928932, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*7*/ + {42.928928, 17.071068, PathPointTypeStart, 0, 0}, /*8*/ + {42.928928, 2.928932, PathPointTypeLine, 0, 0}, /*9*/ + {57.071068, 2.928932, PathPointTypeLine, 0, 0}, /*10*/ + {57.071068, 17.071068, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*11*/ + }; + +static path_test_t widenline_caproundanchor_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {50.0, 15.0, PathPointTypeLine, 0, 0}, /*2*/ + {5.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*3*/ + {5.0, 20.0, PathPointTypeStart, 0, 0}, /*4*/ + {-0.522847, 20.0, PathPointTypeBezier, 0, 0}, /*5*/ + {-5.0, 15.522846, PathPointTypeBezier, 0, 0}, /*6*/ + {-5.0, 10.0, PathPointTypeBezier, 0, 0}, /*7*/ + {-5.0, 4.477152, PathPointTypeBezier, 0, 0}, /*8*/ + {-0.522847, 0.0, PathPointTypeBezier, 0, 0}, /*9*/ + {5.0, 0.0, PathPointTypeBezier, 0, 0}, /*10*/ + {10.522847, 0.0, PathPointTypeBezier, 0, 0}, /*11*/ + {15.0, 4.477152, PathPointTypeBezier, 0, 0}, /*12*/ + {15.0, 10.0, PathPointTypeBezier, 0, 0}, /*13*/ + {15.0, 15.522846, PathPointTypeBezier, 0, 0}, /*14*/ + {10.522847, 20.0, PathPointTypeBezier, 0, 0}, /*15*/ + {5.0, 20.0, PathPointTypeBezier|PathPointTypeCloseSubpath, 0, 0}, /*16*/ + {50.0, 0.0, PathPointTypeStart, 0, 0}, /*17*/ + {55.522846, 0.0, PathPointTypeBezier, 0, 0}, /*18*/ + {60.0, 4.477153, PathPointTypeBezier, 0, 0}, /*19*/ + {60.0, 10.0, PathPointTypeBezier, 0, 0}, /*20*/ + {60.0, 15.522847, PathPointTypeBezier, 0, 0}, /*21*/ + {55.522846, 20.0, PathPointTypeBezier, 0, 0}, /*22*/ + {50.0, 20.0, PathPointTypeBezier, 0, 0}, /*23*/ + {44.477150, 20.0, PathPointTypeBezier, 0, 0}, /*24*/ + {40.0, 15.522847, PathPointTypeBezier, 0, 0}, /*25*/ + {40.0, 10.0, PathPointTypeBezier, 0, 0}, /*26*/ + {40.0, 4.477153, PathPointTypeBezier, 0, 0}, /*27*/ + {44.477150, 0.0, PathPointTypeBezier, 0, 0}, /*28*/ + {50.0, 0.0, PathPointTypeBezier|PathPointTypeCloseSubpath, 0, 0}, /*29*/ + }; + +static path_test_t widenline_capdiamondanchor_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {50.0, 15.0, PathPointTypeLine, 0, 0}, /*2*/ + {5.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*3*/ + {-5.0, 10.0, PathPointTypeStart, 0, 0}, /*4*/ + {5.0, 0.0, PathPointTypeLine, 0, 0}, /*5*/ + {15.0, 10.0, PathPointTypeLine, 0, 0}, /*6*/ + {5.0, 20.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*7*/ + {60.0, 10.0, PathPointTypeStart, 0, 0}, /*8*/ + {50.0, 20.0, PathPointTypeLine, 0, 0}, /*9*/ + {40.0, 10.0, PathPointTypeLine, 0, 0}, /*10*/ + {50.0, 0.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*11*/ + }; + +static path_test_t widenline_caparrowanchor_path[] = { + {15.0, 5.0, PathPointTypeStart, 0, 1}, /*0*/ + {40.0, 5.0, PathPointTypeLine, 0, 1}, /*1*/ + {40.0, 15.0, PathPointTypeLine, 0, 1}, /*2*/ + {15.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 1}, /*3*/ + {5.0, 10.0, PathPointTypeStart, 0, 0}, /*4*/ + {22.320507, 0.0, PathPointTypeLine, 0, 0}, /*5*/ + {22.320507, 20.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*6*/ + {50.0, 10.0, PathPointTypeStart, 0, 0}, /*7*/ + {32.679489, 20.0, PathPointTypeLine, 0, 0}, /*8*/ + {32.679489, 0.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*9*/ + }; + +static path_test_t widenline_capsquareanchor_thin_path[] = { + {6.414213, 8.585786, PathPointTypeStart, 0, 0}, /*0*/ + {6.414213, 11.414213, PathPointTypeLine, 0, 0}, /*1*/ + {3.585786, 11.414213, PathPointTypeLine, 0, 0}, /*2*/ + {3.585786, 8.585786, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*3*/ + {48.585785, 11.414213, PathPointTypeStart, 0, 0}, /*4*/ + {48.585785, 8.585786, PathPointTypeLine, 0, 0}, /*5*/ + {51.414211, 8.585786, PathPointTypeLine, 0, 0}, /*6*/ + {51.414211, 11.414213, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*7*/ + }; + +static path_test_t widenline_capsquareanchor_dashed_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {35.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {35.0, 15.0, PathPointTypeLine, 0, 0}, /*2*/ + {5.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*3*/ + {45.0, 5.0, PathPointTypeStart, 0, 0}, /*4*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*5*/ + {50.0, 15.0, PathPointTypeLine, 0, 0}, /*6*/ + {45.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*7*/ + {12.071068, 2.928932, PathPointTypeStart, 0, 0}, /*8*/ + {12.071068, 17.071066, PathPointTypeLine, 0, 0}, /*9*/ + {-2.071068, 17.071066, PathPointTypeLine, 0, 0}, /*10*/ + {-2.071068, 2.928932, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*11*/ + {42.928928, 17.071068, PathPointTypeStart, 0, 0}, /*12*/ + {42.928928, 2.928932, PathPointTypeLine, 0, 0}, /*13*/ + {57.071068, 2.928932, PathPointTypeLine, 0, 0}, /*14*/ + {57.071068, 17.071068, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*15*/ + }; + +static path_test_t widenline_capsquareanchor_multifigure_path[] = { + {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ + {25.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ + {25.0, 15.0, PathPointTypeLine, 0, 0}, /*2*/ + {5.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*3*/ + {30.0, 5.0, PathPointTypeStart, 0, 0}, /*4*/ + {50.0, 5.0, PathPointTypeLine, 0, 0}, /*5*/ + {50.0, 15.0, PathPointTypeLine, 0, 0}, /*6*/ + {30.0, 15.0, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*7*/ + {12.071068, 2.928932, PathPointTypeStart, 0, 0}, /*8*/ + {12.071068, 17.071066, PathPointTypeLine, 0, 0}, /*9*/ + {-2.071068, 17.071066, PathPointTypeLine, 0, 0}, /*10*/ + {-2.071068, 2.928932, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*11*/ + {17.928930, 17.071068, PathPointTypeStart, 0, 0}, /*12*/ + {17.928930, 2.928932, PathPointTypeLine, 0, 0}, /*13*/ + {32.071068, 2.928932, PathPointTypeLine, 0, 0}, /*14*/ + {32.071068, 17.071068, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*15*/ + {37.071068, 2.928932, PathPointTypeStart, 0, 0}, /*16*/ + {37.071068, 17.071066, PathPointTypeLine, 0, 0}, /*17*/ + {22.928930, 17.071066, PathPointTypeLine, 0, 0}, /*18*/ + {22.928930, 2.928932, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*19*/ + {42.928928, 17.071068, PathPointTypeStart, 0, 0}, /*20*/ + {42.928928, 2.928932, PathPointTypeLine, 0, 0}, /*21*/ + {57.071068, 2.928932, PathPointTypeLine, 0, 0}, /*22*/ + {57.071068, 17.071068, PathPointTypeLine|PathPointTypeCloseSubpath, 0, 0}, /*23*/ + }; + +static void test_widen_cap(void) +{ + struct + { + LineCap type; + REAL line_width; + const path_test_t *expected; + INT expected_size; + BOOL dashed; + BOOL todo_size; + } + caps[] = + { + { LineCapFlat, 10.0, widenline_capflat_path, + ARRAY_SIZE(widenline_capflat_path) }, + { LineCapSquare, 10.0, widenline_capsquare_path, + ARRAY_SIZE(widenline_capsquare_path) }, + { LineCapRound, 10.0, widenline_capround_path, + ARRAY_SIZE(widenline_capround_path) }, + { LineCapTriangle, 10.0, widenline_captriangle_path, + ARRAY_SIZE(widenline_captriangle_path) }, + { LineCapNoAnchor, 10.0, widenline_capflat_path, + ARRAY_SIZE(widenline_capflat_path) }, + { LineCapSquareAnchor, 10.0, widenline_capsquareanchor_path, + ARRAY_SIZE(widenline_capsquareanchor_path) }, + { LineCapRoundAnchor, 10.0, widenline_caproundanchor_path, + ARRAY_SIZE(widenline_caproundanchor_path) }, + { LineCapDiamondAnchor, 10.0, widenline_capdiamondanchor_path, + ARRAY_SIZE(widenline_capdiamondanchor_path) }, + { LineCapArrowAnchor, 10.0, widenline_caparrowanchor_path, + ARRAY_SIZE(widenline_caparrowanchor_path), FALSE, TRUE }, + { LineCapSquareAnchor, 0.0, widenline_capsquareanchor_thin_path, + ARRAY_SIZE(widenline_capsquareanchor_thin_path) }, + { LineCapSquareAnchor, 10.0, widenline_capsquareanchor_dashed_path, + ARRAY_SIZE(widenline_capsquareanchor_dashed_path), TRUE }, + }; + GpStatus status; + GpPath *path; + GpPen *pen; + int i; + + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + + for (i = 0; i < ARRAY_SIZE(caps); i++) + { + status = GdipCreatePen1(0xffffffff, caps[i].line_width, UnitPixel, &pen); + expect(Ok, status); + if (caps[i].dashed) + { + status = GdipSetPenDashStyle(pen, DashStyleDash); + expect(Ok, status); + } + + status = GdipResetPath(path); + expect(Ok, status); + status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 10.0); + expect(Ok, status); + status = GdipSetPenStartCap(pen, caps[i].type); + expect(Ok, status); + status = GdipSetPenEndCap(pen, caps[i].type); + expect(Ok, status); + + status = GdipWidenPath(path, pen, NULL, FlatnessDefault); + expect(Ok, status); + + if (i == 9) + { + INT size; + status = GdipGetPointCount(path, &size); + expect(Ok, status); + ok(size == caps[i].expected_size || broken(size == 12), "unexpected path size %i\n", size); + + if (size == 12) + { + GdipDeletePen(pen); + continue; + } + } + + ok_path_fudge(path, caps[i].expected, caps[i].expected_size, caps[i].todo_size, 0.000005); + + GdipDeletePen(pen); + } + + status = GdipCreatePen1(0xffffffff, 10.0, UnitPixel, &pen); + expect(Ok, status); + status = GdipResetPath(path); + expect(Ok, status); + status = GdipAddPathLine(path, 5.0, 10.0, 25.0, 10.0); + expect(Ok, status); + status = GdipStartPathFigure(path); + expect(Ok, status); + status = GdipAddPathLine(path, 30.0, 10.0, 50.0, 10.0); + expect(Ok, status); + status = GdipSetPenStartCap(pen, LineCapSquareAnchor); + expect(Ok, status); + status = GdipSetPenEndCap(pen, LineCapSquareAnchor); + expect(Ok, status); + status = GdipWidenPath(path, pen, NULL, FlatnessDefault); + expect(Ok, status); + ok_path_fudge(path, widenline_capsquareanchor_multifigure_path, + ARRAY_SIZE(widenline_capsquareanchor_multifigure_path), FALSE, 0.000005); + GdipDeletePen(pen); + + GdipDeletePath(path); +} + static void test_isvisible(void) { GpPath *path; @@ -1370,7 +1879,10 @@ START_TEST(graphicspath) test_constructor_destructor(); test_getpathdata(); + test_createpath2(); test_line2(); + test_bezier(); + test_beziers(); test_arc(); test_worldbounds(); test_pathpath(); @@ -1385,6 +1897,7 @@ START_TEST(graphicspath) test_addpie(); test_flatten(); test_widen(); + test_widen_cap(); test_isvisible(); test_empty_rect(); diff --git a/modules/rostests/winetests/gdiplus/image.c b/modules/rostests/winetests/gdiplus/image.c index c5802f1dc56..83a32357191 100644 --- a/modules/rostests/winetests/gdiplus/image.c +++ b/modules/rostests/winetests/gdiplus/image.c @@ -56,15 +56,21 @@ static GpStatus (WINGDIPAPI *pGdipInitializePalette)(ColorPalette*,PaletteType,I #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)) -static BOOL color_match(ARGB c1, ARGB c2, BYTE max_diff) +static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) { - if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE; + unsigned int diff = x > y ? x - y : y - x; + return diff <= max_diff; +} + +BOOL color_match(ARGB c1, ARGB c2, BYTE max_diff) +{ + if (!compare_uint(c1 & 0xff, c2 & 0xff, max_diff)) return FALSE; c1 >>= 8; c2 >>= 8; - if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE; + if (!compare_uint(c1 & 0xff, c2 & 0xff, max_diff)) return FALSE; c1 >>= 8; c2 >>= 8; - if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE; + if (!compare_uint(c1 & 0xff, c2 & 0xff, max_diff)) return FALSE; c1 >>= 8; c2 >>= 8; - if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE; + if (!compare_uint(c1 & 0xff, c2 & 0xff, max_diff)) return FALSE; return TRUE; } @@ -93,6 +99,36 @@ static void expect_rawformat(REFGUID expected, GpImage *img, int line, BOOL todo expect_guid(expected, &raw, line, todo); } +static BOOL get_encoder_clsid(LPCWSTR mime, GUID *format, CLSID *clsid) +{ + GpStatus status; + UINT n_codecs, info_size, i; + ImageCodecInfo *info; + BOOL ret = FALSE; + + status = GdipGetImageEncodersSize(&n_codecs, &info_size); + expect(Ok, status); + + info = GdipAlloc(info_size); + + status = GdipGetImageEncoders(n_codecs, info_size, info); + expect(Ok, status); + + for (i = 0; i < n_codecs; i++) + { + if (!lstrcmpW(info[i].MimeType, mime)) + { + *format = info[i].FormatID; + *clsid = info[i].Clsid; + ret = TRUE; + break; + } + } + + GdipFree(info); + return ret; +} + static void test_bufferrawformat(void* buff, int size, REFGUID expected, int line, BOOL todo) { LPSTREAM stream; @@ -398,7 +434,6 @@ static void test_LoadingImages(void) GpStatus stat; GpBitmap *bm; GpImage *img; - static const WCHAR nonexistentW[] = {'n','o','n','e','x','i','s','t','e','n','t',0}; stat = GdipCreateBitmapFromFile(0, 0); expect(InvalidParameter, stat); @@ -409,7 +444,7 @@ static void test_LoadingImages(void) ok(bm == (GpBitmap *)0xdeadbeef, "returned %p\n", bm); bm = (GpBitmap *)0xdeadbeef; - stat = GdipCreateBitmapFromFile(nonexistentW, &bm); + stat = GdipCreateBitmapFromFile(L"nonexistent", &bm); todo_wine expect(InvalidParameter, stat); ok(!bm, "returned %p\n", bm); @@ -422,7 +457,7 @@ static void test_LoadingImages(void) ok(img == (GpImage *)0xdeadbeef, "returned %p\n", img); img = (GpImage *)0xdeadbeef; - stat = GdipLoadImageFromFile(nonexistentW, &img); + stat = GdipLoadImageFromFile(L"nonexistent", &img); todo_wine expect(OutOfMemory, stat); ok(!img, "returned %p\n", img); @@ -435,7 +470,7 @@ static void test_LoadingImages(void) ok(img == (GpImage *)0xdeadbeef, "returned %p\n", img); img = (GpImage *)0xdeadbeef; - stat = GdipLoadImageFromFileICM(nonexistentW, &img); + stat = GdipLoadImageFromFileICM(L"nonexistent", &img); todo_wine expect(OutOfMemory, stat); ok(!img, "returned %p\n", img); } @@ -450,7 +485,7 @@ static void test_SavingImages(void) REAL w, h; ImageCodecInfo *codecs; static const CHAR filenameA[] = "a.bmp"; - static const WCHAR filename[] = { 'a','.','b','m','p',0 }; + static const WCHAR filename[] = L"a.bmp"; codecs = NULL; @@ -504,6 +539,188 @@ static void test_SavingImages(void) ok(DeleteFileA(filenameA), "Delete failed.\n"); } +static void test_SavingMultiPageTiff(void) +{ + GpStatus stat; + BOOL result; + GpBitmap *bm1 = NULL, *bm2 = NULL, *check_bm = NULL; + const REAL WIDTH = 10.0, HEIGHT = 20.0; + REAL w, h; + GUID format, tiff_clsid; + EncoderParameters params; + ULONG32 paramValue = EncoderValueFrameDimensionPage; + UINT frame_count; + static const CHAR filename1A[] = "1.tif"; + static const CHAR filename2A[] = "2.tif"; + static const WCHAR filename1[] = L"1.tif"; + static const WCHAR filename2[] = L"2.tif"; + + params.Count = 1; + params.Parameter[0].Guid = EncoderSaveFlag; + params.Parameter[0].Type = EncoderParameterValueTypeLong; + params.Parameter[0].NumberOfValues = 1; + params.Parameter[0].Value = ¶mValue; + + stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm1); + expect(Ok, stat); + stat = GdipCreateBitmapFromScan0(2 * WIDTH, 2 * HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm2); + expect(Ok, stat); + result = get_encoder_clsid(L"image/tiff", &format, &tiff_clsid); + ok(result, "getting TIFF encoding clsid failed"); + + if (!bm1 || !bm2 || !result) + return; + + /* invalid params: NULL */ + stat = GdipSaveAdd(0, ¶ms); + expect(InvalidParameter, stat); + stat = GdipSaveAdd((GpImage*)bm1, 0); + expect(InvalidParameter, stat); + + stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, 0); + expect(InvalidParameter, stat); + stat = GdipSaveAddImage((GpImage*)bm1, 0, ¶ms); + expect(InvalidParameter, stat); + stat = GdipSaveAddImage(0, (GpImage*)bm2, ¶ms); + expect(InvalidParameter, stat); + + /* win32 error: SaveAdd() can only be called after Save() with the MultiFrame param */ + stat = GdipSaveAdd((GpImage*)bm1, ¶ms); + expect(Win32Error, stat); + stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, ¶ms); + expect(Win32Error, stat); + + stat = GdipSaveImageToFile((GpImage*)bm1, filename1, &tiff_clsid, 0); /* param not set! */ + expect(Ok, stat); + if (stat != Ok) goto cleanup; + + stat = GdipSaveAdd((GpImage*)bm1, ¶ms); + expect(Win32Error, stat); + stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, ¶ms); + expect(Win32Error, stat); + + /* win32 error: can't flush before starting the encoding process */ + paramValue = EncoderValueFlush; + stat = GdipSaveAdd((GpImage*)bm1, ¶ms); + expect(Win32Error, stat); + + /* win32 error: can't start encoding process through SaveAdd(), only Save() */ + paramValue = EncoderValueMultiFrame; + stat = GdipSaveAdd((GpImage*)bm1, ¶ms); + expect(Win32Error, stat); + + /* start encoding process: add first frame (bm1) */ + paramValue = EncoderValueMultiFrame; + stat = GdipSaveImageToFile((GpImage*)bm1, filename1, &tiff_clsid, ¶ms); + expect(Ok, stat); + + /* re-start encoding process: add first frame (bm1), should re-create the file */ + stat = GdipSaveImageToFile((GpImage*)bm1, filename1, &tiff_clsid, ¶ms); + expect(Ok, stat); + + /* add second frame (bm2) */ + paramValue = EncoderValueFrameDimensionPage; + stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, ¶ms); + expect(Ok, stat); + if (stat != Ok) goto cleanup; + + /* finish encoding process */ + paramValue = EncoderValueFlush; + stat = GdipSaveAdd((GpImage*)bm1, ¶ms); + expect(Ok, stat); + + /* bm1 should be unchanged, only the saved file on disk has multiple frames */ + stat = GdipImageGetFrameCount((GpImage*)bm1, &FrameDimensionPage, &frame_count); + expect(Ok, stat); + expect(1, frame_count); + + /* win32 error: encoding process already finished */ + paramValue = EncoderValueFrameDimensionPage; + stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, ¶ms); + expect(Win32Error, stat); + + stat = GdipSaveAdd((GpImage*)bm1, ¶ms); + expect(Win32Error, stat); + + GdipDisposeImage((GpImage*)bm1); + bm1 = 0; + GdipDisposeImage((GpImage*)bm2); + bm2 = 0; + + /* re-load and check image stats */ + stat = GdipLoadImageFromFile(filename1, (GpImage**)&check_bm); + expect(Ok, stat); + + stat = GdipImageGetFrameCount((GpImage*)check_bm, &FrameDimensionPage, &frame_count); + expect(Ok, stat); + expect(2, frame_count); + if (stat != Ok || frame_count != 2) goto cleanup; + + stat = GdipGetImageDimension((GpImage*)check_bm, &w, &h); + expect(Ok, stat); + expectf(WIDTH, w); /* frame index 0: bm1 stats */ + expectf(HEIGHT, h); + + stat = GdipImageSelectActiveFrame((GpImage*)check_bm, &FrameDimensionPage, 1); + expect(Ok, stat); + + stat = GdipGetImageDimension((GpImage*)check_bm, &w, &h); + expectf(2 * WIDTH, w); /* frame index 1: bm2 stats */ + expectf(2 * HEIGHT, h); + + /* now proper API use for SaveAdd() to swap the frames in check_bm */ + paramValue = EncoderValueMultiFrame; + stat = GdipSaveImageToFile((GpImage*)check_bm, filename2, &tiff_clsid, ¶ms); + expect(Ok, stat); /* second frame is active: bm2 */ + + stat = GdipImageSelectActiveFrame((GpImage*)check_bm, &FrameDimensionPage, 0); + expect(Ok, stat); + + paramValue = EncoderValueFrameDimensionPage; + stat = GdipSaveAdd((GpImage*)check_bm, ¶ms); + expect(Ok, stat); /* first frame is active: bm1 */ + + paramValue = EncoderValueFlush; + stat = GdipSaveAdd((GpImage*)check_bm, ¶ms); + expect(Ok, stat); /* flushed encoder (finished encoding process) */ + + GdipDisposeImage((GpImage*)check_bm); + check_bm = 0; + + /* re-load and check image stats */ + stat = GdipLoadImageFromFile(filename2, (GpImage**)&check_bm); + expect(Ok, stat); + + stat = GdipImageGetFrameCount((GpImage*)check_bm, &FrameDimensionPage, &frame_count); + expect(Ok, stat); + expect(2, frame_count); + + stat = GdipGetImageDimension((GpImage*)check_bm, &w, &h); + expect(Ok, stat); + expectf(2 * WIDTH, w); /* frame index 0: bm2 stats */ + expectf(2 * HEIGHT, h); + + stat = GdipImageSelectActiveFrame((GpImage*)check_bm, &FrameDimensionPage, 1); + expect(Ok, stat); + + stat = GdipGetImageDimension((GpImage*)check_bm, &w, &h); + expectf(WIDTH, w); /* frame index 1: bm1 stats */ + expectf(HEIGHT, h); + + cleanup: + if (bm1) + GdipDisposeImage((GpImage*)bm1); + if (bm2) + GdipDisposeImage((GpImage*)bm2); + ok(DeleteFileA(filename1A), "Delete 1.tif failed.\n"); + + if (check_bm) + { + GdipDisposeImage((GpImage*)check_bm); + ok(DeleteFileA(filename2A), "Delete 2.tif failed.\n"); + } +} + static void test_encoders(void) { GpStatus stat; @@ -883,7 +1100,7 @@ static void test_LockBits_UserBuf(void) struct BITMAPINFOWITHBITFIELDS { BITMAPINFOHEADER bmiHeader; - DWORD masks[3]; + DWORD masks[255]; }; union BITMAPINFOUNION @@ -899,7 +1116,10 @@ static void test_GdipCreateBitmapFromHBITMAP(void) HPALETTE hpal = NULL; GpStatus stat; BYTE buff[1000]; - LOGPALETTE* LogPal = NULL; + char logpalette_buf[sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 255]; + LOGPALETTE *LogPal = (LOGPALETTE *)logpalette_buf; + char colorpalette_buf[sizeof(ColorPalette) + sizeof(ARGB) * 255]; + ColorPalette *palette = (ColorPalette *)colorpalette_buf; REAL width, height; const REAL WIDTH1 = 5; const REAL HEIGHT1 = 15; @@ -909,6 +1129,7 @@ static void test_GdipCreateBitmapFromHBITMAP(void) union BITMAPINFOUNION bmi; BYTE *bits; PixelFormat format; + int i; stat = GdipCreateBitmapFromHBITMAP(NULL, NULL, NULL); expect(InvalidParameter, stat); @@ -922,6 +1143,9 @@ static void test_GdipCreateBitmapFromHBITMAP(void) expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height)); expectf(WIDTH1, width); expectf(HEIGHT1, height); + stat = GdipGetImagePixelFormat((GpImage*)gpbm, &format); + expect(Ok, stat); + expect(PixelFormat1bppIndexed, format); if (stat == Ok) GdipDisposeImage((GpImage*)gpbm); DeleteObject(hbm); @@ -933,6 +1157,10 @@ static void test_GdipCreateBitmapFromHBITMAP(void) /* raw format */ expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)gpbm, __LINE__, FALSE); + stat = GdipGetImagePixelFormat((GpImage*)gpbm, &format); + expect(Ok, stat); + expect(PixelFormat1bppIndexed, format); + expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height)); expectf(WIDTH2, width); expectf(HEIGHT2, height); @@ -960,6 +1188,9 @@ static void test_GdipCreateBitmapFromHBITMAP(void) expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height)); expectf(WIDTH1, width); expectf(HEIGHT1, height); + stat = GdipGetImagePixelFormat((GpImage*)gpbm, &format); + expect(Ok, stat); + expect(PixelFormat24bppRGB, format); if (stat == Ok) { /* test whether writing to the bitmap affects the original */ @@ -971,21 +1202,77 @@ static void test_GdipCreateBitmapFromHBITMAP(void) GdipDisposeImage((GpImage*)gpbm); } - LogPal = GdipAlloc(sizeof(LOGPALETTE)); - ok(LogPal != NULL, "unable to allocate LOGPALETTE\n"); LogPal->palVersion = 0x300; - LogPal->palNumEntries = 1; + LogPal->palNumEntries = 8; + for (i = 0; i < 8; i++) + { + LogPal->palPalEntry[i].peRed = i; + LogPal->palPalEntry[i].peGreen = i; + LogPal->palPalEntry[i].peBlue = i; + LogPal->palPalEntry[i].peFlags = 0; + } + hpal = CreatePalette(LogPal); ok(hpal != NULL, "CreatePalette failed\n"); - GdipFree(LogPal); stat = GdipCreateBitmapFromHBITMAP(hbm, hpal, &gpbm); expect(Ok, stat); + stat = GdipGetImagePalette((GpImage *)gpbm, palette, sizeof(colorpalette_buf)); + expect(Ok, stat); + expect(0, palette->Count); + GdipDisposeImage((GpImage*)gpbm); + DeleteObject(hbm); - if (stat == Ok) - GdipDisposeImage((GpImage*)gpbm); + for (i = 0; i < 16; i++) + { + RGBQUAD *colors = bmi.bi.bmiColors; + BYTE clr = 255 - i; + colors[i].rgbBlue = clr; + colors[i].rgbGreen = clr; + colors[i].rgbRed = clr; + colors[i].rgbReserved = 0; + } + + bmi.bi.bmiHeader.biBitCount = 8; + bmi.bi.bmiHeader.biClrUsed = 16; + bmi.bi.bmiHeader.biClrImportant = 16; + hbm = CreateDIBSection(hdc, &bmi.bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok(hbm != NULL, "CreateDIBSection failed\n"); + + stat = GdipCreateBitmapFromHBITMAP(hbm, hpal, &gpbm); + expect(Ok, stat); + stat = GdipGetImagePixelFormat((GpImage*)gpbm, &format); + expect(Ok, stat); + expect(PixelFormat8bppIndexed, format); + stat = GdipGetImagePalette((GpImage *)gpbm, palette, sizeof(colorpalette_buf)); + expect(Ok, stat); + expect(256, palette->Count); + for (i = 0; i < 16; i++) + { + BYTE clr = 255 - i; + ARGB argb = 0xff000000 | (clr << 16) | (clr << 8) | clr; + ok(palette->Entries[i] == argb, "got %08lx, expected %08lx\n", palette->Entries[i], argb); + } + GdipDisposeImage((GpImage*)gpbm); DeleteObject(hpal); + + stat = GdipCreateBitmapFromHBITMAP(hbm, 0, &gpbm); + expect(Ok, stat); + stat = GdipGetImagePixelFormat((GpImage*)gpbm, &format); + expect(Ok, stat); + expect(PixelFormat8bppIndexed, format); + stat = GdipGetImagePalette((GpImage *)gpbm, palette, sizeof(colorpalette_buf)); + expect(Ok, stat); + expect(256, palette->Count); + for (i = 0; i < 16; i++) + { + BYTE clr = 255 - i; + ARGB argb = 0xff000000 | (clr << 16) | (clr << 8) | clr; + ok(palette->Entries[i] == argb, "got %08lx, expected %08lx\n", palette->Entries[i], argb); + } + GdipDisposeImage((GpImage*)gpbm); + DeleteObject(hbm); /* 16-bit 555 dib, rgb */ @@ -1016,7 +1303,7 @@ static void test_GdipCreateBitmapFromHBITMAP(void) DeleteObject(hbm); /* 16-bit 555 dib, with bitfields */ - bmi.bi.bmiHeader.biSize = sizeof(bmi); + bmi.bi.bmiHeader.biSize = sizeof(bmi.bi.bmiHeader); bmi.bi.bmiHeader.biCompression = BI_BITFIELDS; bmi.bf.masks[0] = 0x7c00; bmi.bf.masks[1] = 0x3e0; @@ -1243,7 +1530,7 @@ static void test_testcontrol(void) param = 0; stat = GdipTestControl(TestControlGetBuildNumber, ¶m); expect(Ok, stat); - ok(param != 0, "Build number expected, got %u\n", param); + ok(param != 0, "Build number expected, got %lu\n", param); } static void test_fromhicon(void) @@ -1721,7 +2008,7 @@ static void test_createhbitmap(void) if (bm.bmBits) { DWORD val = *(DWORD*)bm.bmBits; - ok(val == 0xff686868, "got %x, expected 0xff686868\n", val); + ok(val == 0xff686868, "got %lx, expected 0xff686868\n", val); } hdc = CreateCompatibleDC(NULL); @@ -1768,9 +2055,9 @@ static void test_createhbitmap(void) if (bm.bmBits) { DWORD val = *(DWORD*)bm.bmBits; - ok(val == 0x682a2a2a, "got %x, expected 0x682a2a2a\n", val); + ok(val == 0x682a2a2a, "got %lx, expected 0x682a2a2a\n", val); val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1); - ok(val == 0x0, "got %x, expected 0x682a2a2a\n", val); + ok(val == 0x0, "got %lx, expected 0x682a2a2a\n", val); } hdc = CreateCompatibleDC(NULL); @@ -1810,20 +2097,20 @@ static void test_createhbitmap(void) if (bm.bmBits) { DWORD val = *(DWORD*)bm.bmBits; - ok(val == 0x68c12ac1 || broken(val == 0x682a2ac1), "got %x, expected 0x68c12ac1\n", val); + ok(val == 0x68c12ac1 || broken(val == 0x682a2ac1), "got %lx, expected 0x68c12ac1\n", val); val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1); - ok(val == 0xff00ff || broken(val == 0xff), "got %x, expected 0xff00ff\n", val); + ok(val == 0xff00ff || broken(val == 0xff), "got %lx, expected 0xff00ff\n", val); } hdc = CreateCompatibleDC(NULL); oldhbitmap = SelectObject(hdc, hbitmap); pixel = GetPixel(hdc, 5, 5); - ok(pixel == 0xc12ac1 || broken(pixel == 0xc12a2a), "got %x, expected 0xc12ac1\n", pixel); + ok(pixel == 0xc12ac1 || broken(pixel == 0xc12a2a), "got %lx, expected 0xc12ac1\n", pixel); pixel = GetPixel(hdc, 1, 0); - ok(pixel == 0xff00ff || broken(pixel == 0xff0000), "got %x, expected 0xff00ff\n", pixel); + ok(pixel == 0xff00ff || broken(pixel == 0xff0000), "got %lx, expected 0xff00ff\n", pixel); pixel = GetPixel(hdc, 2, 0); - ok(pixel == 0xb12ac1 || broken(pixel == 0xb12a2a), "got %x, expected 0xb12ac1\n", pixel); + ok(pixel == 0xb12ac1 || broken(pixel == 0xb12a2a), "got %lx, expected 0xb12ac1\n", pixel); SelectObject(hdc, oldhbitmap); DeleteDC(hdc); @@ -1850,20 +2137,20 @@ static void test_createhbitmap(void) if (bm.bmBits) { DWORD val = *(DWORD*)bm.bmBits; - ok(val == 0x68c12ac1 || broken(val == 0x682a2ac1), "got %x, expected 0x68c12ac1\n", val); + ok(val == 0x68c12ac1 || broken(val == 0x682a2ac1), "got %lx, expected 0x68c12ac1\n", val); val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1); - ok(val == 0xff00ff || broken(val == 0xff), "got %x, expected 0xff00ff\n", val); + ok(val == 0xff00ff || broken(val == 0xff), "got %lx, expected 0xff00ff\n", val); } hdc = CreateCompatibleDC(NULL); oldhbitmap = SelectObject(hdc, hbitmap); pixel = GetPixel(hdc, 5, 5); - ok(pixel == 0xc12ac1 || broken(pixel == 0xc12a2a), "got %x, expected 0xc12ac1\n", pixel); + ok(pixel == 0xc12ac1 || broken(pixel == 0xc12a2a), "got %lx, expected 0xc12ac1\n", pixel); pixel = GetPixel(hdc, 1, 0); - ok(pixel == 0xff00ff || broken(pixel == 0xff0000), "got %x, expected 0xff00ff\n", pixel); + ok(pixel == 0xff00ff || broken(pixel == 0xff0000), "got %lx, expected 0xff00ff\n", pixel); pixel = GetPixel(hdc, 2, 0); - ok(pixel == 0xb12ac1 || broken(pixel == 0xb12a2a), "got %x, expected 0xb12ac1\n", pixel); + ok(pixel == 0xb12ac1 || broken(pixel == 0xb12a2a), "got %lx, expected 0xb12ac1\n", pixel); SelectObject(hdc, oldhbitmap); DeleteDC(hdc); @@ -2084,7 +2371,7 @@ static void check_halftone_palette(ColorPalette *palette) expected |= halftone_values[((i-40)/6)%6] << 8; expected |= halftone_values[((i-40)/36)%6] << 16; } - ok(expected == palette->Entries[i], "Expected %.8x, got %.8x, i=%u/%u\n", + ok(expected == palette->Entries[i], "Expected %.8lx, got %.8lx, i=%u/%u\n", expected, palette->Entries[i], i, palette->Count); } } @@ -2392,7 +2679,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xeeff40cc, color, 3), "expected 0xeeff40cc, got 0x%08x\n", color); + ok(color_match(0xeeff40cc, color, 3), "expected 0xeeff40cc, got 0x%08lx\n", color); /* Toggle NoOp */ stat = GdipSetImageAttributesNoOp(imageattr, ColorAdjustTypeDefault, FALSE); @@ -2404,7 +2691,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xfefe40cc, color, 3), "expected 0xfefe40cc, got 0x%08x\n", color); + ok(color_match(0xfefe40cc, color, 3), "expected 0xfefe40cc, got 0x%08lx\n", color); stat = GdipSetImageAttributesNoOp(imageattr, ColorAdjustTypeDefault, TRUE); expect(Ok, stat); @@ -2415,7 +2702,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08x\n", color); + ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08lx\n", color); stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault); expect(Ok, stat); @@ -2429,7 +2716,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08x\n", color); + ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08lx\n", color); stat = GdipDrawImageRectRectI(graphics, (GpImage *)bitmap1, 0, 0, 1, 1, 0, 0, 1, 1, UnitPixel, imageattr, NULL, NULL); @@ -2437,7 +2724,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff40ccee, color, 1), "Expected ff40ccee, got %.8x\n", color); + ok(color_match(0xff40ccee, color, 1), "Expected ff40ccee, got %.8lx\n", color); /* Disable adjustment, toggle NoOp */ stat = GdipSetImageAttributesColorMatrix(imageattr, ColorAdjustTypeDefault, @@ -2453,7 +2740,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08x\n", color); + ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08lx\n", color); stat = GdipSetImageAttributesNoOp(imageattr, ColorAdjustTypeDefault, TRUE); expect(Ok, stat); @@ -2464,7 +2751,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08x\n", color); + ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08lx\n", color); /* Reset with NoOp on, enable adjustment. */ stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault); @@ -2480,7 +2767,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xfff24ace, color, 3), "expected 0xfff24ace, got 0x%08x\n", color); + ok(color_match(0xfff24ace, color, 3), "expected 0xfff24ace, got 0x%08lx\n", color); /* Now inhibit specific category. */ stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault); @@ -2496,7 +2783,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xfffe41cc, color, 3), "expected 0xfffe41cc, got 0x%08x\n", color); + ok(color_match(0xfffe41cc, color, 3), "expected 0xfffe41cc, got 0x%08lx\n", color); stat = GdipSetImageAttributesNoOp(imageattr, ColorAdjustTypeBitmap, TRUE); expect(Ok, stat); @@ -2507,7 +2794,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08x\n", color); + ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08lx\n", color); stat = GdipSetImageAttributesNoOp(imageattr, ColorAdjustTypeBitmap, FALSE); expect(Ok, stat); @@ -2521,7 +2808,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xfff24ace, color, 3), "expected 0xfff24ace, got 0x%08x\n", color); + ok(color_match(0xfff24ace, color, 3), "expected 0xfff24ace, got 0x%08lx\n", color); stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeBitmap); expect(Ok, stat); @@ -2532,7 +2819,7 @@ static void test_colormatrix(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08x\n", color); + ok(color_match(0xff40ccee, color, 3), "expected 0xff40ccee, got 0x%08lx\n", color); GdipDeleteGraphics(graphics); GdipDisposeImage((GpImage*)bitmap1); @@ -2594,7 +2881,7 @@ static void test_gamma(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff20ffff, color, 1), "Expected ff20ffff, got %.8x\n", color); + ok(color_match(0xff20ffff, color, 1), "Expected ff20ffff, got %.8lx\n", color); stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault); expect(Ok, stat); @@ -2605,7 +2892,7 @@ static void test_gamma(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff80ffff, color, 1), "Expected ff80ffff, got %.8x\n", color); + ok(color_match(0xff80ffff, color, 1), "Expected ff80ffff, got %.8lx\n", color); GdipDeleteGraphics(graphics); GdipDisposeImage((GpImage*)bitmap1); @@ -2896,7 +3183,7 @@ static void test_multiframegif(void) expect(Ok, stat); stat = GdipBitmapGetPixel(bmp, 2, 0, &color); expect(Ok, stat); - ok(color==0 || broken(color==0xff0000ff), "color = %x\n", color); + ok(color==0 || broken(color==0xff0000ff), "color = %lx\n", color); if(color != 0) { win_skip("broken animated gif support\n"); GdipDisposeImage((GpImage*)bmp); @@ -2910,7 +3197,7 @@ static void test_multiframegif(void) for(j=0; j<4; j++) { stat = GdipBitmapGetPixel(bmp, j*2, 0, &color); expect(Ok, stat); - ok(gifanimation2_pixels[i%5][j] == color, "at %d,%d got %x, expected %x\n", i, j, color, gifanimation2_pixels[i%5][j]); + ok(gifanimation2_pixels[i%5][j] == color, "at %d,%d got %lx, expected %lx\n", i, j, color, gifanimation2_pixels[i%5][j]); } } @@ -3093,7 +3380,7 @@ static void test_remaptable(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xffff00ff, color, 1), "Expected ffff00ff, got %.8x\n", color); + ok(color_match(0xffff00ff, color, 1), "Expected ffff00ff, got %.8lx\n", color); stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault); expect(Ok, stat); @@ -3104,7 +3391,7 @@ static void test_remaptable(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0xff00ff00, color, 1), "Expected ff00ff00, got %.8x\n", color); + ok(color_match(0xff00ff00, color, 1), "Expected ff00ff00, got %.8lx\n", color); GdipDeleteGraphics(graphics); GdipDisposeImage((GpImage*)bitmap1); @@ -3163,19 +3450,19 @@ static void test_colorkey(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color); + ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8lx\n", color); stat = GdipBitmapGetPixel(bitmap2, 0, 1, &color); expect(Ok, stat); - ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color); + ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8lx\n", color); stat = GdipBitmapGetPixel(bitmap2, 1, 0, &color); expect(Ok, stat); - ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color); + ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8lx\n", color); stat = GdipBitmapGetPixel(bitmap2, 1, 1, &color); expect(Ok, stat); - ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8x\n", color); + ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8lx\n", color); stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault); expect(Ok, stat); @@ -3186,19 +3473,19 @@ static void test_colorkey(void) stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color); expect(Ok, stat); - ok(color_match(0x20405060, color, 1), "Expected 20405060, got %.8x\n", color); + ok(color_match(0x20405060, color, 1), "Expected 20405060, got %.8lx\n", color); stat = GdipBitmapGetPixel(bitmap2, 0, 1, &color); expect(Ok, stat); - ok(color_match(0x40506070, color, 1), "Expected 40506070, got %.8x\n", color); + ok(color_match(0x40506070, color, 1), "Expected 40506070, got %.8lx\n", color); stat = GdipBitmapGetPixel(bitmap2, 1, 0, &color); expect(Ok, stat); - ok(color_match(0x60708090, color, 1), "Expected 60708090, got %.8x\n", color); + ok(color_match(0x60708090, color, 1), "Expected 60708090, got %.8lx\n", color); stat = GdipBitmapGetPixel(bitmap2, 1, 1, &color); expect(Ok, stat); - ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8x\n", color); + ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8lx\n", color); GdipDeleteGraphics(graphics); @@ -3222,8 +3509,11 @@ static void test_dispose(void) stat = GdipDisposeImage(image); expect(Ok, stat); + if (0) { + /* Can crash with page heap or if the heap region is decommitted. */ stat = GdipDisposeImage(image); expect(ObjectBusy, stat); + } memset(invalid_image, 0, 256); stat = GdipDisposeImage((GpImage*)invalid_image); @@ -3253,11 +3543,11 @@ static GpImage *load_image(const BYTE *image_data, UINT image_size, BOOL valid_d GlobalUnlock(hmem); hr = CreateStreamOnHGlobal(hmem, TRUE, &stream); - ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr); + ok(hr == S_OK, "CreateStreamOnHGlobal error %#lx\n", hr); if (hr != S_OK) return NULL; refcount = obj_refcount(stream); - ok(refcount == 1, "expected stream refcount 1, got %d\n", refcount); + ok(refcount == 1, "expected stream refcount 1, got %ld\n", refcount); status = GdipLoadImageFromStream(stream, &image); todo_wine_if(todo_load) @@ -3277,25 +3567,25 @@ static GpImage *load_image(const BYTE *image_data, UINT image_size, BOOL valid_d refcount = obj_refcount(stream); if (image_type == ImageTypeBitmap) - ok(refcount > 1, "expected stream refcount > 1, got %d\n", refcount); + ok(refcount > 1, "expected stream refcount > 1, got %ld\n", refcount); else - ok(refcount == 1, "expected stream refcount 1, got %d\n", refcount); + ok(refcount == 1, "expected stream refcount 1, got %ld\n", refcount); old_refcount = refcount; status = GdipCloneImage(image, &clone); ok(status == Ok, "GdipCloneImage error %d\n", status); refcount = obj_refcount(stream); - ok(refcount == old_refcount, "expected stream refcount %d, got %d\n", old_refcount, refcount); + ok(refcount == old_refcount, "expected stream refcount %ld, got %ld\n", old_refcount, refcount); status = GdipDisposeImage(clone); ok(status == Ok, "GdipDisposeImage error %d\n", status); refcount = obj_refcount(stream); - ok(refcount == old_refcount, "expected stream refcount %d, got %d\n", old_refcount, refcount); + ok(refcount == old_refcount, "expected stream refcount %ld, got %ld\n", old_refcount, refcount); refcount = IStream_Release(stream); if (image_type == ImageTypeBitmap) ok(refcount >= 1, "expected stream refcount != 0\n"); else - ok(refcount == 0, "expected stream refcount 0, got %d\n", refcount); + ok(refcount == 0, "expected stream refcount 0, got %ld\n", refcount); return image; } @@ -3314,20 +3604,22 @@ static void test_image_properties(void) UINT prop_size2; /* if win7 behaves differently */ UINT prop_id; UINT prop_id2; /* if win7 behaves differently */ + INT palette_size; } td[] = { - { pngimage, sizeof(pngimage), ImageTypeBitmap, 4, ~0, 1, 20, 0x5110, 0x132 }, - { jpgimage, sizeof(jpgimage), ImageTypeBitmap, 2, ~0, 128, 0, 0x5090, 0x5091 }, - { tiffimage, sizeof(tiffimage), ImageTypeBitmap, 16, 0, 4, 0, 0xfe, 0 }, - { bmpimage, sizeof(bmpimage), ImageTypeBitmap, 0, 0, 0, 0, 0, 0 }, - { wmfimage, sizeof(wmfimage), ImageTypeMetafile, 0, 0, 0, 0, 0, 0 } + { pngimage, sizeof(pngimage), ImageTypeBitmap, 4, ~0, 1, 20, 0x5110, 0x132, 12 }, + { jpgimage, sizeof(jpgimage), ImageTypeBitmap, 2, ~0, 128, 0, 0x5090, 0x5091, 12 }, + { tiffimage, sizeof(tiffimage), ImageTypeBitmap, 16, 0, 4, 0, 0xfe, 0, 12 }, + { bmpimage, sizeof(bmpimage), ImageTypeBitmap, 0, 0, 0, 0, 0, 0, 16 }, + { wmfimage, sizeof(wmfimage), ImageTypeMetafile, 0, 0, 0, 0, 0, 0, -GenericError } }; GpStatus status; GpImage *image; UINT prop_count, prop_size, i; PROPID prop_id[16] = { 0 }; ImageType image_type; + INT palette_size; union { PropertyItem data; @@ -3348,6 +3640,21 @@ static void test_image_properties(void) ok(td[i].image_type == image_type, "%u: expected image_type %d, got %d\n", i, td[i].image_type, image_type); + palette_size = -1; + status = GdipGetImagePaletteSize(image, &palette_size); + if (td[i].palette_size >= 0) + { + ok(status == Ok, "%u: GdipGetImagePaletteSize error %d\n", i, status); + ok(td[i].palette_size == palette_size, "%u: expected palette_size %d, got %d\n", + i, td[i].palette_size, palette_size); + } + else + { + ok(status == -td[i].palette_size, "%u: GdipGetImagePaletteSize returned %d\n", i, status); + ok(palette_size == 0, "%u: expected palette_size 0, got %d\n", + i, palette_size); + } + status = GdipGetPropertyCount(image, &prop_count); ok(status == Ok, "%u: GdipGetPropertyCount error %d\n", i, status); todo_wine_if(td[i].image_data == pngimage || td[i].image_data == jpgimage) @@ -3411,7 +3718,7 @@ static void test_image_properties(void) expect(Ok, status); if (prop_count != 0) ok(td[i].prop_id == prop_id[0] || td[i].prop_id2 == prop_id[0], - " %u: expected property id %#x or %#x, got %#x\n", + " %u: expected property id %#x or %#x, got %#lx\n", i, td[i].prop_id, td[i].prop_id2, prop_id[0]); } @@ -3444,7 +3751,7 @@ static void test_image_properties(void) status = GdipGetPropertyItem(image, prop_id[0], prop_size, &item.data); expect(Ok, status); ok(prop_id[0] == item.data.id, - "%u: expected property id %#x, got %#x\n", i, prop_id[0], item.data.id); + "%u: expected property id %#lx, got %#lx\n", i, prop_id[0], item.data.id); } } @@ -3677,14 +3984,14 @@ static void test_tiff_properties(void) looks broken since TypeFloat and TypeDouble now reported as TypeUndefined, and signed types reported as unsigned. */ broken(prop_item->type == documented_type(td[i].type)), - "%u: expected type %u, got %u\n", i, td[i].type, prop_item->type); - ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id); + "%u: expected type %lu, got %u\n", i, td[i].type, prop_item->type); + ok(td[i].id == prop_item->id, "%u: expected id %#lx, got %#lx\n", i, td[i].id, prop_item->id); prop_size -= sizeof(*prop_item); - ok(prop_item->length == prop_size, "%u: expected length %u, got %u\n", i, prop_size, prop_item->length); + ok(prop_item->length == prop_size, "%u: expected length %u, got %lu\n", i, prop_size, prop_item->length); ok(td[i].length == prop_item->length || broken(td[i].id == 0xf00f && td[i].length == prop_item->length+1) /* XP */, - "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length); + "%u: expected length %lu, got %lu\n", i, td[i].length, prop_item->length); ok(td[i].length == prop_size || broken(td[i].id == 0xf00f && td[i].length == prop_size+1) /* XP */, - "%u: expected length %u, got %u\n", i, td[i].length, prop_size); + "%u: expected length %lu, got %u\n", i, td[i].length, prop_size); if (td[i].length == prop_item->length) { int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0; @@ -3693,7 +4000,7 @@ static void test_tiff_properties(void) { UINT j; BYTE *data = prop_item->value; - trace("id %#x:", prop_item->id); + trace("id %#lx:", prop_item->id); for (j = 0; j < prop_item->length; j++) trace(" %02x", data[j]); trace("\n"); @@ -3786,11 +4093,11 @@ static void test_GdipGetAllPropertyItems(void) expect(Ok, status); ok(prop_item->value == prop_item + 1, "expected item->value %p, got %p\n", prop_item + 1, prop_item->value); ok(td[i].type == prop_item->type, - "%u: expected type %u, got %u\n", i, td[i].type, prop_item->type); - ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id); + "%u: expected type %lu, got %u\n", i, td[i].type, prop_item->type); + ok(td[i].id == prop_item->id, "%u: expected id %#lx, got %#lx\n", i, td[i].id, prop_item->id); size -= sizeof(*prop_item); - ok(prop_item->length == size, "%u: expected length %u, got %u\n", i, size, prop_item->length); - ok(td[i].length == prop_item->length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length); + ok(prop_item->length == size, "%u: expected length %u, got %lu\n", i, size, prop_item->length); + ok(td[i].length == prop_item->length, "%u: expected length %lu, got %lu\n", i, td[i].length, prop_item->length); if (td[i].length == prop_item->length) { int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0; @@ -3799,7 +4106,7 @@ static void test_GdipGetAllPropertyItems(void) { UINT j; BYTE *data = prop_item->value; - trace("id %#x:", prop_item->id); + trace("id %#lx:", prop_item->id); for (j = 0; j < prop_item->length; j++) trace(" %02x", data[j]); trace("\n"); @@ -3850,9 +4157,9 @@ static void test_GdipGetAllPropertyItems(void) ok(prop_item[i].value == item_data, "%u: expected value %p, got %p\n", i, item_data, prop_item[i].value); ok(td[i].type == prop_item[i].type, - "%u: expected type %u, got %u\n", i, td[i].type, prop_item[i].type); - ok(td[i].id == prop_item[i].id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item[i].id); - ok(td[i].length == prop_item[i].length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item[i].length); + "%u: expected type %lu, got %u\n", i, td[i].type, prop_item[i].type); + ok(td[i].id == prop_item[i].id, "%u: expected id %#lx, got %#lx\n", i, td[i].id, prop_item[i].id); + ok(td[i].length == prop_item[i].length, "%u: expected length %lu, got %lu\n", i, td[i].length, prop_item[i].length); if (td[i].length == prop_item[i].length) { int match = memcmp(td[i].value, prop_item[i].value, td[i].length) == 0; @@ -3861,7 +4168,7 @@ static void test_GdipGetAllPropertyItems(void) { UINT j; BYTE *data = prop_item[i].value; - trace("id %#x:", prop_item[i].id); + trace("id %#lx:", prop_item[i].id); for (j = 0; j < prop_item[i].length; j++) trace(" %02x", data[j]); trace("\n"); @@ -3916,8 +4223,8 @@ static void test_tiff_palette(void) expect(2, palette.pal.Count); if (palette.pal.Count == 2) { - ok(entries[0] == 0xff000000, "expected 0xff000000, got %#x\n", entries[0]); - ok(entries[1] == 0xffffffff, "expected 0xffffffff, got %#x\n", entries[1]); + ok(entries[0] == 0xff000000, "expected 0xff000000, got %#lx\n", entries[0]); + ok(entries[1] == 0xffffffff, "expected 0xffffffff, got %#lx\n", entries[1]); } GdipDisposeImage(image); @@ -4222,10 +4529,10 @@ static void test_DrawImage_SourceCopy(void) status = GdipDrawImageI(graphics, u2.image, 0, 0); expect(Ok, status); - todo_wine expect(0, dst_pixels[0]); + expect(0, dst_pixels[0]); expect(0xffff0000, dst_pixels[1]); - todo_wine expect(0, dst_pixels[2]); - todo_wine expect(0, dst_pixels[3]); + expect(0, dst_pixels[2]); + expect(0, dst_pixels[3]); status = GdipDeleteGraphics(graphics); expect(Ok, status); @@ -4594,11 +4901,11 @@ static void test_gif_properties(void) expect(Ok, status); ok(prop_item->value == prop_item + 1, "expected item->value %p, got %p\n", prop_item + 1, prop_item->value); ok(td[i].type == prop_item->type, - "%u: expected type %u, got %u\n", i, td[i].type, prop_item->type); - ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id); + "%u: expected type %lu, got %u\n", i, td[i].type, prop_item->type); + ok(td[i].id == prop_item->id, "%u: expected id %#lx, got %#lx\n", i, td[i].id, prop_item->id); size -= sizeof(*prop_item); - ok(prop_item->length == size, "%u: expected length %u, got %u\n", i, size, prop_item->length); - ok(td[i].length == prop_item->length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length); + ok(prop_item->length == size, "%u: expected length %u, got %lu\n", i, size, prop_item->length); + ok(td[i].length == prop_item->length, "%u: expected length %lu, got %lu\n", i, td[i].length, prop_item->length); if (td[i].length == prop_item->length) { int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0; @@ -4607,7 +4914,7 @@ static void test_gif_properties(void) { UINT j; BYTE *data = prop_item->value; - trace("id %#x:", prop_item->id); + trace("id %#lx:", prop_item->id); for (j = 0; j < prop_item->length; j++) trace(" %02x", data[j]); trace("\n"); @@ -4658,9 +4965,9 @@ static void test_gif_properties(void) ok(prop_item[i].value == item_data, "%u: expected value %p, got %p\n", i, item_data, prop_item[i].value); ok(td[i].type == prop_item[i].type, - "%u: expected type %u, got %u\n", i, td[i].type, prop_item[i].type); - ok(td[i].id == prop_item[i].id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item[i].id); - ok(td[i].length == prop_item[i].length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item[i].length); + "%u: expected type %lu, got %u\n", i, td[i].type, prop_item[i].type); + ok(td[i].id == prop_item[i].id, "%u: expected id %#lx, got %#lx\n", i, td[i].id, prop_item[i].id); + ok(td[i].length == prop_item[i].length, "%u: expected length %lu, got %lu\n", i, td[i].length, prop_item[i].length); if (td[i].length == prop_item[i].length) { int match = memcmp(td[i].value, prop_item[i].value, td[i].length) == 0; @@ -4669,7 +4976,7 @@ static void test_gif_properties(void) { UINT j; BYTE *data = prop_item[i].value; - trace("id %#x:", prop_item[i].id); + trace("id %#lx:", prop_item[i].id); for (j = 0; j < prop_item[i].length; j++) trace(" %02x", data[j]); trace("\n"); @@ -4753,12 +5060,103 @@ static void test_ARGB_conversion(void) GdipDisposeImage((GpImage *)bitmap); } +static void test_PARGB_conversion(void) +{ + BYTE pargb[8] = { 0x62,0x77,0x99,0x77, 0x62,0x77,0x99,0 }; + BYTE argb[8] = { 0xd1,0xfe,0xff,0x77, 0x62,0x77,0x99,0 }; + BYTE pargb2[8] = { 0x01,0x01,0x00,0x01, 0xfe,0x7f,0x7f,0xfe }; + BYTE *bits; + GpBitmap *bitmap; + BitmapData data; + GpStatus status; + int match; + + status = GdipCreateBitmapFromScan0(2, 1, 8, PixelFormat32bppPARGB, pargb, &bitmap); + expect(Ok, status); + + status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppARGB, &data); + expect(Ok, status); + ok(data.Width == 2, "expected 2, got %d\n", data.Width); + ok(data.Height == 1, "expected 1, got %d\n", data.Height); + ok(data.Stride == 8, "expected 8, got %d\n", data.Stride); + ok(data.PixelFormat == PixelFormat32bppARGB, "expected PixelFormat32bppARGB, got %d\n", data.PixelFormat); + match = !memcmp(data.Scan0, argb, sizeof(argb)); + ok(match, "bits don't match\n"); + if (!match) + { + bits = data.Scan0; + trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppARGB, + bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]); + } + status = GdipBitmapUnlockBits(bitmap, &data); + expect(Ok, status); + + /* Testing SetPixel 32-bit ARGB to PARGB */ + status = GdipBitmapSetPixel(bitmap, 0, 0, 0x017f80ff); + expect(Ok, status); + status = GdipBitmapSetPixel(bitmap, 1, 0, 0xfe7f80ff); + expect(Ok, status); + status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppPARGB, &data); + expect(Ok, status); + ok(data.Width == 2, "expected 2, got %d\n", data.Width); + ok(data.Height == 1, "expected 1, got %d\n", data.Height); + ok(data.Stride == 8, "expected 8, got %d\n", data.Stride); + ok(data.PixelFormat == PixelFormat32bppPARGB, "expected PixelFormat32bppPARGB, got %d\n", data.PixelFormat); + match = !memcmp(data.Scan0, pargb2, sizeof(pargb2)); + ok(match, "bits don't match\n"); + if (!match) + { + bits = data.Scan0; + trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppPARGB, + bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]); + } + status = GdipBitmapUnlockBits(bitmap, &data); + expect(Ok, status); + + GdipDisposeImage((GpImage *)bitmap); +} + static void test_CloneBitmapArea(void) { + /* 3x3 pixeldata in various formats: red, green, blue, yellow, turquoise, pink, black, gray, white */ + static BYTE bmp_3x3_data_32bpp_argb[] = { + 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0x00,0xff,0xff, + 0xff,0xff,0x00,0xff, 0x00,0xff,0xff,0xff, 0xff,0x00,0xff,0xff, + 0xff,0xff,0xff,0xff, 0x80,0x80,0x80,0xff, 0x00,0x00,0x00,0xff + }; + static BYTE bmp_3x3_data_32bpp_rgb[] = { + 0xff,0x00,0x00,0x00, 0x00,0xff,0x00,0x00, 0x00,0x00,0xff,0x00, + 0xff,0xff,0x00,0x00, 0x00,0xff,0xff,0x00, 0xff,0x00,0xff,0x00, + 0xff,0xff,0xff,0x00, 0x80,0x80,0x80,0x00, 0x00,0x00,0x00,0x00 + }; + static BYTE bmp_3x3_data_24bpp_rgb[] = { + 0xff,0x00,0x00, 0x00,0xff,0x00, 0x00,0x00,0xff, + 0xff,0xff,0x00, 0x00,0xff,0xff, 0xff,0x00,0xff, + 0xff,0xff,0xff, 0x80,0x80,0x80, 0x00,0x00,0x00 + }; + + static const struct test_data { + BYTE *src_pixeldata; + PixelFormat src_format; + PixelFormat dst_format; + } td[] = + { + { bmp_3x3_data_32bpp_argb, PixelFormat32bppARGB, PixelFormat8bppIndexed }, + { bmp_3x3_data_32bpp_argb, PixelFormat32bppARGB, PixelFormat4bppIndexed }, + { bmp_3x3_data_32bpp_argb, PixelFormat32bppARGB, PixelFormat1bppIndexed }, + { bmp_3x3_data_32bpp_rgb, PixelFormat32bppRGB, PixelFormat8bppIndexed }, + { bmp_3x3_data_32bpp_rgb, PixelFormat32bppRGB, PixelFormat4bppIndexed }, + { bmp_3x3_data_32bpp_rgb, PixelFormat32bppRGB, PixelFormat1bppIndexed }, + { bmp_3x3_data_24bpp_rgb, PixelFormat24bppRGB, PixelFormat8bppIndexed }, + { bmp_3x3_data_24bpp_rgb, PixelFormat24bppRGB, PixelFormat4bppIndexed }, + { bmp_3x3_data_24bpp_rgb, PixelFormat24bppRGB, PixelFormat1bppIndexed }, + }; + GpStatus status; GpBitmap *bitmap, *copy; BitmapData data, data2; + INT x, y, i; status = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat24bppRGB, NULL, &bitmap); expect(Ok, status); @@ -4777,56 +5175,55 @@ static void test_CloneBitmapArea(void) GdipDisposeImage((GpImage *)copy); GdipDisposeImage((GpImage *)bitmap); -} -static BOOL get_encoder_clsid(LPCWSTR mime, GUID *format, CLSID *clsid) -{ - GpStatus status; - UINT n_codecs, info_size, i; - ImageCodecInfo *info; - BOOL ret = FALSE; - - status = GdipGetImageEncodersSize(&n_codecs, &info_size); - expect(Ok, status); - - info = GdipAlloc(info_size); - - status = GdipGetImageEncoders(n_codecs, info_size, info); - expect(Ok, status); - - for (i = 0; i < n_codecs; i++) + for(i=0; i> 16 & 0xff) + (color_orig >> 8 & 0xff) + (color_orig & 0xff) + > 0x17d ? 0xffffffff : 0xff000000; + + match = color_match(color_orig, color_copy, 0x00); + ok(match == TRUE, "Colors 0x%08lx and 0x%08lx do not match! (Conversion from %x to %x)\n", + color_orig, color_copy, td[i].src_format, td[i].dst_format); + } + + GdipDisposeImage((GpImage *)copy); + GdipDisposeImage((GpImage *)bitmap); + } } static void test_supported_encoders(void) { - static const WCHAR bmp_mimetype[] = { 'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p',0 }; - static const WCHAR jpeg_mimetype[] = { 'i','m','a','g','e','/','j','p','e','g',0 }; - static const WCHAR gif_mimetype[] = { 'i','m','a','g','e','/','g','i','f',0 }; - static const WCHAR tiff_mimetype[] = { 'i','m','a','g','e','/','t','i','f','f',0 }; - static const WCHAR png_mimetype[] = { 'i','m','a','g','e','/','p','n','g',0 }; static const struct test_data { LPCWSTR mime; const GUID *format; } td[] = { - { bmp_mimetype, &ImageFormatBMP }, - { jpeg_mimetype, &ImageFormatJPEG }, - { gif_mimetype, &ImageFormatGIF }, - { tiff_mimetype, &ImageFormatTIFF }, - { png_mimetype, &ImageFormatPNG } + { L"image/bmp", &ImageFormatBMP }, + { L"image/jpeg", &ImageFormatJPEG }, + { L"image/gif", &ImageFormatGIF }, + { L"image/tiff", &ImageFormatTIFF }, + { L"image/png", &ImageFormatPNG } }; GUID format, clsid; BOOL ret; @@ -4849,10 +5246,10 @@ static void test_supported_encoders(void) hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 16); hr = CreateStreamOnHGlobal(hmem, TRUE, &stream); - ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr); + ok(hr == S_OK, "CreateStreamOnHGlobal error %#lx\n", hr); status = GdipSaveImageToStream((GpImage *)bm, stream, &clsid, NULL); - ok(status == Ok, "GdipSaveImageToStream error %d\n", status); + ok(status == Ok, "%s encoder, GdipSaveImageToStream error %d\n", wine_dbgstr_w(td[i].mime), status); IStream_Release(stream); } @@ -5325,6 +5722,75 @@ static void test_png_color_formats(void) #undef PNG_COLOR_TYPE_GRAY_ALPHA #undef PNG_COLOR_TYPE_RGB_ALPHA +static void test_png_save_palette(void) +{ + GpStatus status; + GpBitmap *bitmap; + HGLOBAL hglob; + BOOL result; + IStream *stream; + GUID enc_format, clsid; + LARGE_INTEGER seek; + ULARGE_INTEGER pos; + UINT i, ptr; + BYTE *data; + + PixelFormat formats[] = { + PixelFormat1bppIndexed, + PixelFormat4bppIndexed, + PixelFormat8bppIndexed, + PixelFormat16bppGrayScale, + PixelFormat16bppRGB555, + PixelFormat16bppRGB565, + PixelFormat16bppARGB1555, + PixelFormat24bppRGB, + PixelFormat32bppRGB, + PixelFormat32bppARGB, + PixelFormat32bppPARGB, + }; + + result = get_encoder_clsid(L"image/png", &enc_format, &clsid); + ok(result, "getting PNG encoding clsid failed"); + + hglob = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT, 1024); + + for (i = 0; i < ARRAY_SIZE(formats); i++) + { + status = GdipCreateBitmapFromScan0(8, 8, 0, formats[i], NULL, &bitmap); + ok(status == Ok, "Unexpected return value %d creating bitmap for PixelFormat %#x\n", status, formats[i]); + + CreateStreamOnHGlobal(hglob, FALSE, &stream); + status = GdipSaveImageToStream((GpImage *)bitmap, stream, &clsid, NULL); + GdipDisposeImage((GpImage*)bitmap); + + todo_wine_if(formats[i] == PixelFormat16bppGrayScale) + ok(formats[i] == PixelFormat16bppGrayScale ? + (status == GenericError || status == Win32Error) : status == Ok, + "Unexpected return value %d saving image for PixelFormat %#x\n", status, formats[i]); + + if (status == Ok) + { + data = GlobalLock(hglob); + seek.QuadPart = 0; + IStream_Seek(stream, seek, STREAM_SEEK_CUR, &pos); + for (ptr = 0; ptr < pos.QuadPart - 4; ptr++) + if (!memcmp(data + ptr, "PLTE", 4)) + break; + memset(data, 0, 1024); + GlobalUnlock(hglob); + + if (IsIndexedPixelFormat(formats[i])) + ok(ptr < pos.QuadPart - 4, "Expected palette not found for PixelFormat %#x\n", formats[i]); + else + ok(ptr >= pos.QuadPart - 4, "Unexpected palette found for PixelFormat %#x\n", formats[i]); + } + + IStream_Release(stream); + } + + GlobalFree(hglob); +} + static void test_GdipLoadImageFromStream(void) { IStream *stream; @@ -5432,7 +5898,7 @@ static void test_GdipInitializePalette(void) palette->Count = 256; status = pGdipInitializePalette(palette, PaletteTypeFixedBW, 0, FALSE, bitmap); expect(Ok, status); -todo_wine + todo_wine expect(0x200, palette->Flags); expect(2, palette->Count); expect(0xff000000, palette->Entries[0]); @@ -5443,7 +5909,7 @@ todo_wine palette->Count = 256; status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone8, 1, FALSE, NULL); expect(Ok, status); -todo_wine + todo_wine expect(0x300, palette->Flags); expect(16, palette->Count); expect(0xff000000, palette->Entries[0]); @@ -5455,7 +5921,7 @@ todo_wine palette->Count = 256; status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone8, 1, FALSE, bitmap); expect(Ok, status); -todo_wine + todo_wine expect(0x300, palette->Flags); expect(16, palette->Count); expect(0xff000000, palette->Entries[0]); @@ -5467,7 +5933,7 @@ todo_wine palette->Count = 256; status = pGdipInitializePalette(palette, PaletteTypeFixedHalftone252, 1, FALSE, bitmap); expect(Ok, status); -todo_wine + todo_wine expect(0x800, palette->Flags); expect(252, palette->Count); expect(0xff000000, palette->Entries[0]); @@ -5497,6 +5963,49 @@ todo_wine GdipFree(palette); GdipDisposeImage((GpImage *)bitmap); + HeapFree(GetProcessHeap(), 0, data); +} + +static void test_graphics_clear(void) +{ + BYTE argb[8] = { 0x11,0x22,0x33,0x80, 0xff,0xff,0xff,0 }; + BYTE cleared[8] = { 0,0,0,0, 0,0,0,0 }; + BYTE *bits; + GpBitmap *bitmap; + GpGraphics *graphics; + BitmapData data; + GpStatus status; + int match; + + status = GdipCreateBitmapFromScan0(2, 1, 8, PixelFormat32bppARGB, argb, &bitmap); + expect(Ok, status); + + status = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, status); + + status = GdipGraphicsClear(graphics, 0x00000000); + expect(Ok, status); + + status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppARGB, &data); + expect(Ok, status); + ok(data.Width == 2, "expected 2, got %d\n", data.Width); + ok(data.Height == 1, "expected 1, got %d\n", data.Height); + ok(data.Stride == 8, "expected 8, got %d\n", data.Stride); + ok(data.PixelFormat == PixelFormat32bppARGB, "expected PixelFormat32bppARGB, got %d\n", data.PixelFormat); + match = !memcmp(data.Scan0, cleared, sizeof(cleared)); + ok(match, "bits don't match\n"); + if (!match) + { + bits = data.Scan0; + trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppARGB, + bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]); + } + status = GdipBitmapUnlockBits(bitmap, &data); + expect(Ok, status); + + status = GdipDeleteGraphics(graphics); + expect(Ok, status); + GdipDisposeImage((GpImage *)bitmap); } #include "pshpack2.h" @@ -5724,9 +6233,11 @@ START_TEST(image) test_tiff_color_formats(); test_GdipInitializePalette(); test_png_color_formats(); + test_png_save_palette(); test_supported_encoders(); test_CloneBitmapArea(); test_ARGB_conversion(); + test_PARGB_conversion(); test_DrawImage_scale(); test_image_format(); test_DrawImage(); @@ -5744,6 +6255,7 @@ START_TEST(image) test_GdipImageGetFrameDimensionsCount(); test_LoadingImages(); test_SavingImages(); + test_SavingMultiPageTiff(); test_encoders(); test_LockBits(); test_LockBits_UserBuf(); @@ -5773,6 +6285,7 @@ START_TEST(image) test_histogram(); test_imageabort(); test_GdipLoadImageFromStream(); + test_graphics_clear(); GdiplusShutdown(gdiplusToken); } diff --git a/modules/rostests/winetests/gdiplus/metafile.c b/modules/rostests/winetests/gdiplus/metafile.c index bd4d5264eda..aa844a62ff9 100644 --- a/modules/rostests/winetests/gdiplus/metafile.c +++ b/modules/rostests/winetests/gdiplus/metafile.c @@ -22,15 +22,22 @@ #include "objbase.h" #include "gdiplus.h" +#include "winspool.h" #include "wine/test.h" -#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#define expect(expected,got) expect_(__LINE__, expected, got) +static inline void expect_(unsigned line, DWORD expected, DWORD got) +{ + ok_(__FILE__, line)(expected == got, "Expected %.8ld, got %.8ld\n", expected, got); +} #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 BOOL save_metafiles; static BOOL load_metafiles; +static const WCHAR description[] = L"winetest"; + typedef struct emfplus_record { DWORD record_type; @@ -57,14 +64,14 @@ static void check_record(int count, const char *desc, const struct emfplus_recor todo_wine_if (expected->todo) ok(expected->record_type == actual->record_type && (expected->flags == actual->flags || broken(expected->broken_flags == actual->flags)), - "%s.%i: Expected record type 0x%x, got 0x%x. Expected flags %#x, got %#x.\n", desc, count, + "%s.%i: Expected record type 0x%lx, got 0x%lx. Expected flags %#lx, got %#lx.\n", desc, count, expected->record_type, actual->record_type, expected->flags, actual->flags); } else { todo_wine_if (expected->todo) ok(expected->record_type == actual->record_type, - "%s.%i: Expected record type 0x%x, got 0x%x.\n", desc, count, + "%s.%i: Expected record type 0x%lx, got 0x%lx.\n", desc, count, expected->record_type, actual->record_type); } } @@ -129,7 +136,7 @@ static int CALLBACK enum_emf_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETAR const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset]; ok(record->Size == record->DataSize + sizeof(EmfPlusRecordHeader), - "%s: EMF+ record datasize %u and size %u mismatch\n", state->desc, record->DataSize, record->Size); + "%s: EMF+ record datasize %lu and size %lu mismatch\n", state->desc, record->DataSize, record->Size); ok(offset + record->DataSize <= comment->cbData, "%s: EMF+ record truncated\n", state->desc); @@ -189,7 +196,7 @@ static int CALLBACK enum_emf_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETAR } else { - ok(0, "%s: Unexpected EMF 0x%x record\n", state->desc, lpEMFR->iType); + ok(0, "%s: Unexpected EMF 0x%lx record\n", state->desc, lpEMFR->iType); } return 1; @@ -287,7 +294,7 @@ static BOOL CALLBACK play_metafile_proc(EmfPlusRecordType record_type, unsigned 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, + "%s.%i: expected record type 0x%lx, got 0x%x\n", state->desc, state->count, state->expected[state->count].record_type, record_type); state->count++; } @@ -378,7 +385,7 @@ static void test_empty(void) MetafileHeader header; 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}; + UINT limit_dpi; hdc = CreateCompatibleDC(0); @@ -408,6 +415,42 @@ static void test_empty(void) if (stat != Ok) return; + stat = GdipGetMetafileDownLevelRasterizationLimit(metafile, NULL); + expect(InvalidParameter, stat); + + stat = GdipGetMetafileDownLevelRasterizationLimit(NULL, &limit_dpi); + expect(InvalidParameter, stat); + + limit_dpi = 0xdeadbeef; + stat = GdipGetMetafileDownLevelRasterizationLimit(metafile, &limit_dpi); + expect(Ok, stat); + ok(limit_dpi == 96, "limit_dpi was %d\n", limit_dpi); + + stat = GdipSetMetafileDownLevelRasterizationLimit(metafile, 255); + expect(Ok, stat); + + limit_dpi = 0xdeadbeef; + stat = GdipGetMetafileDownLevelRasterizationLimit(metafile, &limit_dpi); + expect(Ok, stat); + ok(limit_dpi == 255, "limit_dpi was %d\n", limit_dpi); + + stat = GdipSetMetafileDownLevelRasterizationLimit(metafile, 0); + expect(Ok, stat); + + limit_dpi = 0xdeadbeef; + stat = GdipGetMetafileDownLevelRasterizationLimit(metafile, &limit_dpi); + expect(Ok, stat); + ok(limit_dpi == 96, "limit_dpi was %d\n", limit_dpi); + + stat = GdipSetMetafileDownLevelRasterizationLimit(metafile, 1); + expect(InvalidParameter, stat); + + stat = GdipSetMetafileDownLevelRasterizationLimit(metafile, 9); + expect(InvalidParameter, stat); + + stat = GdipSetMetafileDownLevelRasterizationLimit(metafile, 10); + expect(Ok, stat); + stat = GdipGetHemfFromMetafile(metafile, &hemf); expect(InvalidParameter, stat); @@ -420,6 +463,14 @@ static void test_empty(void) stat = GdipDeleteGraphics(graphics); expect(Ok, stat); + limit_dpi = 0xdeadbeef; + stat = GdipGetMetafileDownLevelRasterizationLimit(metafile, &limit_dpi); + expect(WrongState, stat); + expect(0xdeadbeef, limit_dpi); + + stat = GdipSetMetafileDownLevelRasterizationLimit(metafile, 200); + expect(WrongState, stat); + check_metafile(metafile, empty_records, "empty metafile", dst_points, &frame, UnitPixel); sync_metafile(&metafile, "empty.emf"); @@ -455,7 +506,7 @@ static void test_empty(void) expect(100, header.Height); expect(28, header.EmfPlusHeaderSize); expect(96, header.LogicalDpiX); - expect(96, header.LogicalDpiX); + expect(96, header.LogicalDpiY); expect(EMR_HEADER, U(header).EmfHeader.iType); expect(0, U(header).EmfHeader.rclBounds.left); expect(0, U(header).EmfHeader.rclBounds.top); @@ -494,7 +545,7 @@ static void test_empty(void) expect(100, header.Height); expect(28, header.EmfPlusHeaderSize); expect(96, header.LogicalDpiX); - expect(96, header.LogicalDpiX); + expect(96, header.LogicalDpiY); expect(EMR_HEADER, U(header).EmfHeader.iType); expect(0, U(header).EmfHeader.rclBounds.left); expect(0, U(header).EmfHeader.rclBounds.top); @@ -541,7 +592,7 @@ static void test_empty(void) expect(100, header.Height); expect(28, header.EmfPlusHeaderSize); expect(96, header.LogicalDpiX); - expect(96, header.LogicalDpiX); + expect(96, header.LogicalDpiY); expect(EMR_HEADER, U(header).EmfHeader.iType); expect(0, U(header).EmfHeader.rclBounds.left); expect(0, U(header).EmfHeader.rclBounds.top); @@ -581,7 +632,6 @@ static void test_getdc(void) 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 GpPointF dst_points_half[3] = {{0.0,0.0},{50.0,0.0},{0.0,50.0}}; - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; HBRUSH hbrush, holdbrush; GpBitmap *bitmap; ARGB color; @@ -739,7 +789,6 @@ static void test_emfonly(void) MetafileHeader header; 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}; HBRUSH hbrush, holdbrush; GpBitmap *bitmap; ARGB color; @@ -830,7 +879,7 @@ static void test_emfonly(void) expect(100, header.Height); expect(0, header.EmfPlusHeaderSize); expect(0, header.LogicalDpiX); - expect(0, header.LogicalDpiX); + expect(0, header.LogicalDpiY); expect(EMR_HEADER, U(header).EmfHeader.iType); expect(25, U(header).EmfHeader.rclBounds.left); expect(25, U(header).EmfHeader.rclBounds.top); @@ -926,7 +975,7 @@ static void test_emfonly(void) expect(100, header.Height); expect(0, header.EmfPlusHeaderSize); expect(0, header.LogicalDpiX); - expect(0, header.LogicalDpiX); + expect(0, header.LogicalDpiY); expect(EMR_HEADER, U(header).EmfHeader.iType); expect(25, U(header).EmfHeader.rclBounds.left); expect(25, U(header).EmfHeader.rclBounds.top); @@ -973,7 +1022,7 @@ static void test_emfonly(void) expect(100, header.Height); expect(0, header.EmfPlusHeaderSize); expect(0, header.LogicalDpiX); - expect(0, header.LogicalDpiX); + expect(0, header.LogicalDpiY); expect(EMR_HEADER, U(header).EmfHeader.iType); expect(25, U(header).EmfHeader.rclBounds.left); expect(25, U(header).EmfHeader.rclBounds.top); @@ -1036,7 +1085,6 @@ static void test_fillrect(void) 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 GpPointF dst_points_half[3] = {{0.0,0.0},{50.0,0.0},{0.0,50.0}}; - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; GpBitmap *bitmap; ARGB color; GpBrush *brush; @@ -1149,7 +1197,6 @@ static void test_clear(void) HENHMETAFILE hemf; static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; static const GpPointF dst_points[3] = {{10.0,10.0},{20.0,10.0},{10.0,20.0}}; - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; GpBitmap *bitmap; ARGB color; @@ -1221,7 +1268,6 @@ static void test_nullframerect(void) { GpMetafile *metafile; GpGraphics *graphics; HDC hdc, metafile_dc; - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; GpBrush *brush; HBRUSH hbrush, holdbrush; GpRectF bounds; @@ -1329,6 +1375,64 @@ static void test_nullframerect(void) { stat = GdipDisposeImage((GpImage*)metafile); expect(Ok, stat); + + hdc = CreateCompatibleDC(0); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, NULL, MetafileFrameUnitMillimeter, + description, &metafile); + expect(Ok, stat); + + DeleteDC(hdc); + + 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(0xff0000); + + holdbrush = SelectObject(metafile_dc, hbrush); + + Rectangle(metafile_dc, 25, 25, 75, 75); + + SelectObject(metafile_dc, holdbrush); + + DeleteObject(hbrush); + + stat = GdipReleaseDC(graphics, metafile_dc); + expect(Ok, stat); + + stat = GdipCreateSolidFill((ARGB)0xff0000ff, (GpSolidFill**)&brush); + expect(Ok, stat); + + stat = GdipFillRectangleI(graphics, brush, 20, 40, 10, 70); + expect(Ok, stat); + + stat = GdipDeleteBrush(brush); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + stat = GdipGetImageBounds((GpImage*)metafile, &bounds, &unit); + expect(Ok, stat); + expect(UnitPixel, unit); + expectf_(20.0, bounds.X, 0.05); + expectf_(25.0, bounds.Y, 0.05); + expectf_(55.0, bounds.Width, 1.00); + todo_wine expectf_(55.0, bounds.Width, 0.05); + expectf_(85.0, bounds.Height, 0.05); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); } static const emfplus_record pagetransform_records[] = { @@ -1356,7 +1460,6 @@ static void test_pagetransform(void) HDC hdc; static const GpRectF frame = {0.0, 0.0, 5.0, 5.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}; GpBitmap *bitmap; ARGB color; GpBrush *brush; @@ -1561,7 +1664,6 @@ static void test_worldtransform(void) HDC hdc; static const GpRectF frame = {0.0, 0.0, 5.0, 5.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}; GpBitmap *bitmap; ARGB color; GpBrush *brush; @@ -1818,7 +1920,6 @@ static void test_converttoemfplus(void) GpStatus (WINAPI *pGdipConvertToEmfPlus)( const GpGraphics *graphics, GpMetafile *metafile, BOOL *succ, EmfType emfType, const WCHAR *description, GpMetafile **outmetafile); static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; GpStatus stat; GpMetafile *metafile, *metafile2 = NULL, *emhmeta; GpGraphics *graphics; @@ -1898,7 +1999,6 @@ static void test_frameunit(void) GpGraphics *graphics; HDC hdc; static const GpRectF frame = {0.0, 0.0, 5.0, 5.0}; - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; GpUnit unit; REAL dpix, dpiy; GpRectF bounds; @@ -1994,7 +2094,6 @@ static void test_containers(void) 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; @@ -2190,7 +2289,6 @@ static void test_clipping(void) 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); @@ -2331,7 +2429,6 @@ static void test_gditransform(void) 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; @@ -2458,7 +2555,6 @@ static const emfplus_record draw_image_metafile_records[] = { static void test_drawimage(void) { - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; static const GpPointF dst_points[3] = {{10.0,10.0},{85.0,15.0},{10.0,80.0}}; static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; const ColorMatrix double_red = {{ @@ -2519,6 +2615,9 @@ static void test_drawimage(void) check_emfplus(hemf, draw_image_bitmap_records, "draw image bitmap"); + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); + /* test drawing metafile */ stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); expect(Ok, stat); @@ -2566,6 +2665,8 @@ static const emfplus_record properties_records[] = { { EmfPlusRecordTypeSetCompositingMode, CompositingModeSourceCopy }, { EmfPlusRecordTypeSetCompositingQuality, CompositingQualityHighQuality }, { EmfPlusRecordTypeSetInterpolationMode, InterpolationModeHighQualityBicubic }, + { EmfPlusRecordTypeSetRenderingOrigin }, + { EmfPlusRecordTypeSetRenderingOrigin }, { EmfPlusRecordTypeEndOfFile }, { EMR_EOF }, { 0 } @@ -2573,7 +2674,6 @@ static const emfplus_record properties_records[] = { static void test_properties(void) { - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; GpMetafile *metafile; @@ -2620,6 +2720,15 @@ static void test_properties(void) stat = GdipSetInterpolationMode(graphics, InterpolationModeHighQuality); expect(Ok, stat); + stat = GdipSetRenderingOrigin(graphics, 1, 2); + expect(Ok, stat); + + stat = GdipSetRenderingOrigin(graphics, 1, 2); + expect(Ok, stat); + + stat = GdipSetRenderingOrigin(graphics, 2, 1); + expect(Ok, stat); + stat = GdipDeleteGraphics(graphics); expect(Ok, stat); sync_metafile(&metafile, "properties.emf"); @@ -2651,7 +2760,6 @@ static const emfplus_record draw_path_records[] = { static void test_drawpath(void) { - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; GpMetafile *metafile; @@ -2716,9 +2824,7 @@ static const emfplus_record fill_path_records[] = { static void test_fillpath(void) { - static const WCHAR description[] = {'w','i','n','e','t','e','s','t',0}; static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; - static const WCHAR winetestemfW[] = {'w','i','n','e','t','e','s','t','.','e','m','f',0}; GpMetafile *metafile; GpGraphics *graphics; @@ -2764,7 +2870,7 @@ static void test_fillpath(void) check_emfplus(hemf, fill_path_records, "fill path"); /* write to disk */ - DeleteEnhMetaFile(CopyEnhMetaFileW(hemf, winetestemfW)); + DeleteEnhMetaFile(CopyEnhMetaFileW(hemf, L"winetest.emf")); DeleteEnhMetaFile(hemf); @@ -2772,18 +2878,1002 @@ static void test_fillpath(void) expect(Ok, stat); /* should succeed when given path to an EMF */ - stat = GdipCreateMetafileFromWmfFile(winetestemfW, NULL, &metafile); + stat = GdipCreateMetafileFromWmfFile(L"winetest.emf", NULL, &metafile); expect(Ok, stat); stat = GdipDisposeImage((GpImage*)metafile); expect(Ok, stat); - DeleteFileW(winetestemfW); + DeleteFileW(L"winetest.emf"); - stat = GdipCreateMetafileFromWmfFile(winetestemfW, NULL, &metafile); + stat = GdipCreateMetafileFromWmfFile(L"winetest.emf", NULL, &metafile); expect(GenericError, stat); } +static const emfplus_record restoredc_records[] = { + { EMR_HEADER }, + { EMR_CREATEBRUSHINDIRECT }, + { EMR_SELECTOBJECT }, + + { EMR_SAVEDC }, + { EMR_SETVIEWPORTORGEX }, + { EMR_SAVEDC }, + { EMR_SETVIEWPORTORGEX }, + { EMR_SAVEDC }, + { EMR_SETVIEWPORTORGEX }, + + { EMR_RECTANGLE }, + + { EMR_RESTOREDC }, + { EMR_RECTANGLE }, + + { EMR_RESTOREDC }, + { EMR_RECTANGLE }, + + { EMR_SELECTOBJECT }, + { EMR_DELETEOBJECT }, + { EMR_EOF }, + { 0 } +}; + +static void test_restoredc(void) +{ + static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + + GpBitmap *bitmap; + GpGraphics *graphics; + GpMetafile *metafile; + GpStatus stat; + HDC hdc, metafile_dc; + HBRUSH hbrush, holdbrush; + ARGB color; + + hdc = CreateCompatibleDC(0); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfOnly, &frame, MetafileFrameUnitPixel, + L"winetest", &metafile); + expect(Ok, stat); + + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipGetDC(graphics, &metafile_dc); + expect(Ok, stat); + + hbrush = CreateSolidBrush(0xff0000); + holdbrush = SelectObject(metafile_dc, hbrush); + + SaveDC(metafile_dc); + SetViewportOrgEx(metafile_dc, 20, 20, NULL); + + SaveDC(metafile_dc); + SetViewportOrgEx(metafile_dc, 40, 40, NULL); + + SaveDC(metafile_dc); + SetViewportOrgEx(metafile_dc, 60, 60, NULL); + + Rectangle(metafile_dc, 0, 0, 3, 3); + RestoreDC(metafile_dc, -2); + + Rectangle(metafile_dc, 0, 0, 3, 3); + RestoreDC(metafile_dc, -1); + + Rectangle(metafile_dc, 0, 0, 3, 3); + + SelectObject(metafile_dc, holdbrush); + DeleteObject(hbrush); + + stat = GdipReleaseDC(graphics, metafile_dc); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + check_metafile(metafile, restoredc_records, "restoredc metafile", dst_points, + &frame, UnitPixel); + sync_metafile(&metafile, "restoredc.emf"); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, restoredc_records, "restoredc playback", dst_points, + &frame, UnitPixel); + + stat = GdipBitmapGetPixel(bitmap, 1, 1, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipBitmapGetPixel(bitmap, 21, 21, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + stat = GdipBitmapGetPixel(bitmap, 41, 41, &color); + expect(Ok, stat); + expect(0, color); + + stat = GdipBitmapGetPixel(bitmap, 61, 61, &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 const emfplus_record drawdriverstring_records[] = { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypeFont << 8 }, + { EmfPlusRecordTypeDrawDriverString, 0x8000 }, + { EmfPlusRecordTypeObject, (ObjectTypeFont << 8) | 1 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 2 }, + { EmfPlusRecordTypeDrawDriverString, 0x1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_drawdriverstring(void) +{ + static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + static const PointF solidpos[4] = {{10.0,10.0}, {20.0,10.0}, {30.0,10.0}, {40.0,10.0}}; + static const PointF hatchpos = {10.0,30.0}; + + GpBitmap *bitmap; + GpStatus stat; + GpGraphics *graphics; + GpFont *solidfont, *hatchfont; + GpBrush *solidbrush, *hatchbrush; + HDC hdc; + GpMatrix *matrix; + GpMetafile *metafile; + LOGFONTA logfont = { 0 }; + + hdc = CreateCompatibleDC(0); + + strcpy(logfont.lfFaceName, "Times New Roman"); + logfont.lfHeight = 12; + logfont.lfCharSet = DEFAULT_CHARSET; + + stat = GdipCreateFontFromLogfontA(hdc, &logfont, &solidfont); + if (stat == NotTrueTypeFont || stat == FileNotFound) + { + DeleteDC(hdc); + skip("Times New Roman not installed.\n"); + return; + } + + stat = GdipCloneFont(solidfont, &hatchfont); + expect(Ok, stat); + + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, + L"winetest", &metafile); + expect(Ok, stat); + + DeleteDC(hdc); + hdc = NULL; + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreateSolidFill((ARGB)0xff0000ff, (GpSolidFill**)&solidbrush); + expect(Ok, stat); + + stat = GdipCreateHatchBrush(HatchStyleHorizontal, (ARGB)0xff00ff00, (ARGB)0xffff0000, + (GpHatch**)&hatchbrush); + expect(Ok, stat); + + stat = GdipCreateMatrix(&matrix); + expect(Ok, stat); + + stat = GdipDrawDriverString(graphics, L"Test", 4, solidfont, solidbrush, solidpos, + DriverStringOptionsCmapLookup, matrix); + expect(Ok, stat); + + stat = GdipSetMatrixElements(matrix, 1.5, 0.0, 0.0, 1.5, 0.0, 0.0); + expect(Ok, stat); + + stat = GdipDrawDriverString(graphics, L"Test ", 5, hatchfont, hatchbrush, &hatchpos, + DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, matrix); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + graphics = NULL; + + check_metafile(metafile, drawdriverstring_records, "drawdriverstring metafile", dst_points, + &frame, UnitPixel); + sync_metafile(&metafile, "drawdriverstring.emf"); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, drawdriverstring_records, "drawdriverstring playback", + dst_points, &frame, UnitPixel); + + GdipDeleteMatrix(matrix); + GdipDeleteGraphics(graphics); + GdipDeleteBrush(solidbrush); + GdipDeleteBrush(hatchbrush); + GdipDeleteFont(solidfont); + GdipDeleteFont(hatchfont); + GdipDisposeImage((GpImage*)bitmap); + GdipDisposeImage((GpImage*)metafile); +} + +static const emfplus_record unknownfontdecode_records[] = { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypeFont << 8 }, + { EmfPlusRecordTypeDrawDriverString, 0x8000 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_unknownfontdecode(void) +{ + static const GpPointF dst_points[3] = {{0.0,0.0},{100.0,0.0},{0.0,100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + static const PointF pos = {10.0,30.0}; + static const INT testfont0_resnum = 2; + + BOOL rval; + DWORD written, ressize; + GpBitmap *bitmap; + GpBrush *brush; + GpFont *font; + GpFontCollection *fonts; + GpFontFamily *family; + GpGraphics *graphics; + GpMetafile *metafile; + GpStatus stat; + HANDLE file; + HDC hdc; + HRSRC res; + INT fontscount; + WCHAR path[MAX_PATH]; + void *buf; + + /* Create a custom font from a resource. */ + GetTempPathW(MAX_PATH, path); + lstrcatW(path, L"wine_testfont0.ttf"); + + file = CreateFileW(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", + wine_dbgstr_w(path), GetLastError()); + + res = FindResourceA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(testfont0_resnum), + (LPCSTR)RT_RCDATA); + ok(res != 0, "couldn't find resource\n"); + + buf = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + ressize = SizeofResource(GetModuleHandleA(NULL), res); + + WriteFile(file, buf, ressize, &written, NULL); + expect(ressize, written); + + CloseHandle(file); + + stat = GdipNewPrivateFontCollection(&fonts); + expect(Ok, stat); + + stat = GdipPrivateAddFontFile(fonts, path); + expect(Ok, stat); + + stat = GdipGetFontCollectionFamilyCount(fonts, &fontscount); + expect(Ok, stat); + expect(1, fontscount); + + stat = GdipGetFontCollectionFamilyList(fonts, fontscount, &family, &fontscount); + expect(Ok, stat); + + stat = GdipCreateFont(family, 16.0, FontStyleRegular, UnitPixel, &font); + expect(Ok, stat); + + /* Start metafile recording. */ + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, + L"winetest", &metafile); + expect(Ok, stat); + DeleteDC(hdc); + hdc = NULL; + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreateSolidFill((ARGB)0xff0000ff, (GpSolidFill**)&brush); + expect(Ok, stat); + + /* Write something with the custom font so that it is encoded. */ + stat = GdipDrawDriverString(graphics, L"Test", 4, font, brush, &pos, + DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL); + expect(Ok, stat); + + /* Delete the custom font so that it is not present during playback. */ + GdipDeleteFont(font); + GdipDeletePrivateFontCollection(&fonts); + rval = DeleteFileW(path); + expect(TRUE, rval); + + GdipDeleteGraphics(graphics); + graphics = NULL; + + check_metafile(metafile, unknownfontdecode_records, "unknownfontdecode metafile", dst_points, + &frame, UnitPixel); + sync_metafile(&metafile, "unknownfontdecode.emf"); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, unknownfontdecode_records, "unknownfontdecode playback", + dst_points, &frame, UnitPixel); + + GdipDeleteGraphics(graphics); + GdipDeleteBrush(brush); + GdipDisposeImage((GpImage*)bitmap); + GdipDisposeImage((GpImage*)metafile); +} + +static const emfplus_record fillregion_records[] = { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypeRegion << 8 }, + { EmfPlusRecordTypeFillRegion, 0x8000 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 1 }, + { EmfPlusRecordTypeObject, (ObjectTypeRegion << 8) | 2 }, + { EmfPlusRecordTypeFillRegion, 2 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_fillregion(void) +{ + static const GpPointF dst_points[3] = {{0.0, 0.0}, {100.0, 0.0}, {0.0, 100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + static const GpRectF solidrect = {20.0, 20.0, 20.0, 20.0}; + static const GpRectF hatchrect = {50.0, 50.0, 20.0, 20.0}; + + GpStatus stat; + GpMetafile *metafile; + GpGraphics *graphics; + GpBitmap *bitmap; + GpBrush *solidbrush, *hatchbrush; + GpRegion *solidregion, *hatchregion; + ARGB color; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, + L"winetest", &metafile); + expect(Ok, stat); + DeleteDC(hdc); + hdc = NULL; + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreateRegionRect(&solidrect, &solidregion); + expect(Ok, stat); + + stat = GdipCreateSolidFill(0xffaabbcc, (GpSolidFill**)&solidbrush); + expect(Ok, stat); + + stat = GdipFillRegion(graphics, solidbrush, solidregion); + expect(Ok, stat); + + stat = GdipCreateRegionRect(&hatchrect, &hatchregion); + expect(Ok, stat); + + stat = GdipCreateHatchBrush(HatchStyleHorizontal, 0xffff0000, 0xff0000ff, + (GpHatch**)&hatchbrush); + expect(Ok, stat); + + stat = GdipFillRegion(graphics, hatchbrush, hatchregion); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + graphics = NULL; + expect(Ok, stat); + + check_metafile(metafile, fillregion_records, "regionfill metafile", dst_points, + &frame, UnitPixel); + sync_metafile(&metafile, "regionfill.emf"); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, fillregion_records, "regionfill playback", + dst_points, &frame, UnitPixel); + + stat = GdipBitmapGetPixel(bitmap, 25, 25, &color); + expect(Ok, stat); + expect(0xffaabbcc, color); + + stat = GdipBitmapGetPixel(bitmap, 56, 56, &color); + expect(Ok, stat); + expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 57, 57, &color); + expect(Ok, stat); + expect(0xff0000ff, color); + + GdipDeleteRegion(solidregion); + GdipDeleteRegion(hatchregion); + GdipDeleteBrush(solidbrush); + GdipDeleteBrush(hatchbrush); + GdipDeleteGraphics(graphics); + GdipDisposeImage((GpImage*)bitmap); + GdipDisposeImage((GpImage*)metafile); +} + +static const emfplus_record lineargradient_records[] = { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypeBrush << 8 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 1 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 2 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 3 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_lineargradient(void) +{ + static const GpPointF dst_points[3] = {{0.0, 0.0}, {100.0, 0.0}, {0.0, 100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + static const GpRectF horizrect = {10.0, 10.0, 20.0, 20.0}; + static const GpRectF vertrect = {50.0, 10.0, 20.0, 20.0}; + static const GpRectF blendrect = {10.0, 50.0, 20.0, 20.0}; + static const GpRectF presetrect = {50.0, 50.0, 20.0, 20.0}; + static const REAL blendfac[3] = {0.0, 0.9, 1.0}; + static const REAL blendpos[3] = {0.0, 0.5, 1.0}; + static const ARGB pblendcolor[3] = {0xffff0000, 0xff00ff00, 0xff0000ff}; + static const REAL pblendpos[3] = {0.0, 0.5, 1.0}; + + ARGB color; + GpBitmap *bitmap; + GpBrush *horizbrush, *vertbrush, *blendbrush, *presetbrush; + GpGraphics *graphics; + GpMetafile *metafile; + GpStatus stat; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, + L"winetest", &metafile); + expect(Ok, stat); + DeleteDC(hdc); + hdc = NULL; + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + /* Test various brush types to cover all valid combinations + of optional serialized data. */ + stat = GdipCreateLineBrushFromRect(&horizrect, 0xffff0000, 0xff0000ff, + LinearGradientModeHorizontal, WrapModeTile, (GpLineGradient**)&horizbrush); + expect(Ok, stat); + + stat = GdipCreateLineBrushFromRect(&vertrect, 0xffff0000, 0xff0000ff, + LinearGradientModeVertical, WrapModeTile, (GpLineGradient**)&vertbrush); + expect(Ok, stat); + + stat = GdipCreateLineBrushFromRect(&blendrect, 0xffff0000, 0xff0000ff, + LinearGradientModeHorizontal, WrapModeTile, (GpLineGradient**)&blendbrush); + expect(Ok, stat); + + stat = GdipSetLineBlend((GpLineGradient*)blendbrush, blendfac, blendpos, 3); + expect(Ok, stat); + + stat = GdipCreateLineBrushFromRect(&presetrect, 0xffff0000, 0xff0000ff, + LinearGradientModeVertical, WrapModeTile, (GpLineGradient**)&presetbrush); + expect(Ok, stat); + + stat = GdipSetLinePresetBlend((GpLineGradient*)presetbrush, pblendcolor, pblendpos, 3); + expect(Ok, stat); + + stat = GdipFillRectangles(graphics, vertbrush, &vertrect, 1); + expect(Ok, stat); + + stat = GdipFillRectangles(graphics, horizbrush, &horizrect, 1); + expect(Ok, stat); + + stat = GdipFillRectangles(graphics, blendbrush, &blendrect, 1); + expect(Ok, stat); + + stat = GdipFillRectangles(graphics, presetbrush, &presetrect, 1); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + graphics = NULL; + expect(Ok, stat); + + check_metafile(metafile, lineargradient_records, "lineargradient metafile", dst_points, + &frame, UnitPixel); + sync_metafile(&metafile, "lineargradient.emf"); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, lineargradient_records, "lineargradient playback", + dst_points, &frame, UnitPixel); + + /* Verify horizontal gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 10, 10, &color); + expect(Ok, stat); + expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 18, 10, &color); + expect(Ok, stat); + expect(0xff990066, color); + + /* Verify vertical gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 50, 10, &color); + expect(Ok, stat); + expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 50, 18, &color); + expect(Ok, stat); + expect(0xff990066, color); + + /* Verify custom blend gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 10, 50, &color); + expect(Ok, stat); + expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 18, 50, &color); + expect(Ok, stat); + expect(0xff4700b8, color); + + /* Verify preset color gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); + expect(Ok, stat); + expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 50, 60, &color); + expect(Ok, stat); + expect(0xff00ff00, color); + + GdipDeleteBrush(vertbrush); + GdipDeleteBrush(horizbrush); + GdipDeleteBrush(blendbrush); + GdipDeleteBrush(presetbrush); + GdipDeleteGraphics(graphics); + GdipDisposeImage((GpImage*)bitmap); + GdipDisposeImage((GpImage*)metafile); +} + +static HDC create_printer_dc(void) +{ + char buffer[260]; + DWORD len; + PRINTER_INFO_2A *pbuf = NULL; + DRIVER_INFO_3A *dbuf = NULL; + HANDLE hprn = 0; + HDC hdc = 0; + HMODULE winspool = LoadLibraryA("winspool.drv"); + BOOL (WINAPI *pOpenPrinterA)(LPSTR, HANDLE *, LPPRINTER_DEFAULTSA); + BOOL (WINAPI *pGetDefaultPrinterA)(LPSTR, LPDWORD); + BOOL (WINAPI *pGetPrinterA)(HANDLE, DWORD, LPBYTE, DWORD, LPDWORD); + BOOL (WINAPI *pGetPrinterDriverA)(HANDLE, LPSTR, DWORD, LPBYTE, DWORD, LPDWORD); + BOOL (WINAPI *pClosePrinter)(HANDLE); + + pGetDefaultPrinterA = (void *)GetProcAddress(winspool, "GetDefaultPrinterA"); + pOpenPrinterA = (void *)GetProcAddress(winspool, "OpenPrinterA"); + pGetPrinterA = (void *)GetProcAddress(winspool, "GetPrinterA"); + pGetPrinterDriverA = (void *)GetProcAddress(winspool, "GetPrinterDriverA"); + pClosePrinter = (void *)GetProcAddress(winspool, "ClosePrinter"); + + if (!pGetDefaultPrinterA || !pOpenPrinterA || !pGetPrinterA || !pGetPrinterDriverA || !pClosePrinter) + goto done; + + len = sizeof(buffer); + if (!pGetDefaultPrinterA(buffer, &len)) goto done; + if (!pOpenPrinterA(buffer, &hprn, NULL)) goto done; + + pGetPrinterA(hprn, 2, NULL, 0, &len); + pbuf = HeapAlloc(GetProcessHeap(), 0, len); + if (!pGetPrinterA(hprn, 2, (LPBYTE)pbuf, len, &len)) goto done; + + pGetPrinterDriverA(hprn, NULL, 3, NULL, 0, &len); + dbuf = HeapAlloc(GetProcessHeap(), 0, len); + if (!pGetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, len, &len)) goto done; + + hdc = CreateDCA(dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName, pbuf->pDevMode); + trace("hdc %p for driver '%s' printer '%s' port '%s'\n", hdc, + dbuf->pDriverPath, pbuf->pPrinterName, pbuf->pPortName); +done: + HeapFree(GetProcessHeap(), 0, dbuf); + HeapFree(GetProcessHeap(), 0, pbuf); + if (hprn) pClosePrinter(hprn); + if (winspool) FreeLibrary(winspool); + return hdc; +} + +static void test_printer_dc(void) +{ + HDC hdc; + Status status; + RectF frame = { 0.0, 0.0, 1.0, 1.0 }; + GpMetafile *metafile; + GpGraphics *graphics; + REAL dpix, dpiy; + + hdc = create_printer_dc(); + if (!hdc) + { + skip("could not create a DC for the default printer\n"); + return; + } + + status = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitInch, L"winetest", &metafile); + expect(Ok, status); + + status = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, status); + + GdipGetDpiX(graphics, &dpix); + GdipGetDpiX(graphics, &dpiy); + expectf((REAL)(GetDeviceCaps(hdc, LOGPIXELSX)), dpix); + expectf((REAL)(GetDeviceCaps(hdc, LOGPIXELSY)), dpiy); + + GdipDeleteGraphics(graphics); + GdipDisposeImage((GpImage *)metafile); +} + +static const emfplus_record draw_ellipse_records[] = +{ + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypePen << 8 }, + { EmfPlusRecordTypeDrawEllipse, 0x4000 }, + { EMR_SAVEDC, 0, 1 }, + { EMR_SETICMMODE, 0, 1 }, + { EMR_BITBLT, 0, 1 }, + { EMR_RESTOREDC, 0, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_drawellipse(void) +{ + static const GpRectF frame = { 0.0f, 0.0f, 100.0f, 100.0f }; + + GpMetafile *metafile; + GpGraphics *graphics; + HENHMETAFILE hemf; + GpStatus stat; + GpPen *pen; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); + expect(Ok, stat); + + stat = GdipDrawEllipse(graphics, pen, 1.0f, 1.0f, 16.0f, 32.0f); + expect(Ok, stat); + + stat = GdipDeletePen(pen); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + sync_metafile(&metafile, "draw_ellipse.emf"); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, draw_ellipse_records, "draw ellipse"); + DeleteEnhMetaFile(hemf); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); +} + +static const emfplus_record fill_ellipse_records[] = +{ + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeFillEllipse, 0xc000 }, + { EMR_SAVEDC, 0, 1 }, + { EMR_SETICMMODE, 0, 1 }, + { EMR_BITBLT, 0, 1 }, + { EMR_RESTOREDC, 0, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_fillellipse(void) +{ + static const GpRectF frame = { 0.0f, 0.0f, 100.0f, 100.0f }; + + GpMetafile *metafile; + GpGraphics *graphics; + GpSolidFill *brush; + HENHMETAFILE hemf; + GpStatus stat; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreateSolidFill(0xffaabbcc, &brush); + expect(Ok, stat); + + stat = GdipFillEllipse(graphics, (GpBrush *)brush, 0.0f, 0.0f, 10.0f, 20.0f); + expect(Ok, stat); + + stat = GdipDeleteBrush((GpBrush*)brush); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + sync_metafile(&metafile, "fill_ellipse.emf"); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, fill_ellipse_records, "fill ellipse"); + + DeleteEnhMetaFile(hemf); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); +} + +static const emfplus_record draw_rectangle_records[] = +{ + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypePen << 8 }, + { EmfPlusRecordTypeDrawRects, 0x4000 }, + { EMR_SAVEDC, 0, 1 }, + { EMR_SETICMMODE, 0, 1 }, + { EMR_BITBLT, 0, 1 }, + { EMR_RESTOREDC, 0, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_drawrectangle(void) +{ + static const GpRectF frame = { 0.0f, 0.0f, 100.0f, 100.0f }; + + GpMetafile *metafile; + GpGraphics *graphics; + HENHMETAFILE hemf; + GpStatus stat; + GpPen *pen; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); + expect(Ok, stat); + + stat = GdipDrawRectangle(graphics, pen, 1.0f, 1.0f, 16.0f, 32.0f); + expect(Ok, stat); + + stat = GdipDeletePen(pen); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + sync_metafile(&metafile, "draw_rectangle.emf"); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, draw_rectangle_records, "draw rectangle"); + DeleteEnhMetaFile(hemf); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); +} + +static void test_offsetclip(void) +{ + static const GpRectF frame = { 0.0f, 0.0f, 100.0f, 100.0f }; + static const emfplus_record offset_clip_records[] = + { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeOffsetClip }, + { EmfPlusRecordTypeOffsetClip }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 }, + }; + + GpMetafile *metafile; + GpGraphics *graphics; + HENHMETAFILE hemf; + GpStatus stat; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, stat); + + stat = GdipTranslateClip(graphics, 1.0f, -1.0f); + expect(Ok, stat); + + stat = GdipTranslateClipI(graphics, 2, 3); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + sync_metafile(&metafile, "offset_clip.emf"); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, offset_clip_records, "offset clip"); + DeleteEnhMetaFile(hemf); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); +} + +static void test_resetclip(void) +{ + static const GpRectF frame = { 0.0f, 0.0f, 100.0f, 100.0f }; + static const emfplus_record reset_clip_records[] = + { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeResetClip }, + { EmfPlusRecordTypeResetClip }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 }, + }; + + GpMetafile *metafile; + GpGraphics *graphics; + HENHMETAFILE hemf; + GpStatus stat; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, stat); + + stat = GdipResetClip(graphics); + expect(Ok, stat); + + stat = GdipResetClip(graphics); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + sync_metafile(&metafile, "reset_clip.emf"); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, reset_clip_records, "reset clip"); + DeleteEnhMetaFile(hemf); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); +} + +static void test_setclippath(void) +{ + static const GpRectF frame = { 0.0f, 0.0f, 100.0f, 100.0f }; + static const emfplus_record set_clip_path_records[] = + { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypePath << 8 }, + { EmfPlusRecordTypeSetClipPath, 0x100 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 }, + }; + + GpMetafile *metafile; + GpGraphics *graphics; + HENHMETAFILE hemf; + GpStatus stat; + GpPath *path; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, stat); + stat = GdipAddPathLine(path, 5, 5, 30, 30); + expect(Ok, stat); + stat = GdipAddPathLine(path, 30, 30, 5, 30); + expect(Ok, stat); + + stat = GdipSetClipPath(graphics, path, CombineModeIntersect); + expect(Ok, stat); + + stat = GdipDeletePath(path); + expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + sync_metafile(&metafile, "set_clip_path.emf"); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, set_clip_path_records, "set clip path"); + DeleteEnhMetaFile(hemf); + + stat = GdipDisposeImage((GpImage*)metafile); + expect(Ok, stat); +} + START_TEST(metafile) { struct GdiplusStartupInput gdiplusStartupInput; @@ -2832,6 +3922,18 @@ START_TEST(metafile) test_properties(); test_drawpath(); test_fillpath(); + test_restoredc(); + test_drawdriverstring(); + test_unknownfontdecode(); + test_fillregion(); + test_lineargradient(); + test_printer_dc(); + test_drawellipse(); + test_fillellipse(); + test_drawrectangle(); + test_offsetclip(); + test_resetclip(); + test_setclippath(); GdiplusShutdown(gdiplusToken); } diff --git a/modules/rostests/winetests/gdiplus/pen.c b/modules/rostests/winetests/gdiplus/pen.c index ceab92acffd..cd3e45f9b41 100644 --- a/modules/rostests/winetests/gdiplus/pen.c +++ b/modules/rostests/winetests/gdiplus/pen.c @@ -24,7 +24,11 @@ #include "gdiplus.h" #include "wine/test.h" -#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#define expect(expected,got) expect_(__LINE__, expected, got) +static inline void expect_(unsigned line, DWORD expected, DWORD got) +{ + ok_(__FILE__, line)(expected == got, "Expected %.8ld, got %.8ld\n", expected, got); +} #define expectf(expected, got) ok(fabs(got - expected) < 0.1, "Expected %.2f, got %.2f\n", expected, got) static void test_startup(void) @@ -175,7 +179,7 @@ static void test_dasharray(void) dashes[4] = 14.0; dashes[5] = -100.0; dashes[6] = -100.0; - dashes[7] = dashes[8] = dashes[9] = dashes[10] = dashes[11] = 0.0; + dashes[7] = dashes[8] = dashes[9] = dashes[10] = dashes[11] = 1.0; /* setting the array sets the type to custom */ GdipGetPenDashStyle(pen, &style); @@ -218,10 +222,13 @@ static void test_dasharray(void) /* Some invalid array values. */ status = GdipSetPenDashArray(pen, &dashes[7], 5); - expect(InvalidParameter, status); + expect(Ok, status); dashes[9] = -1.0; status = GdipSetPenDashArray(pen, &dashes[7], 5); expect(InvalidParameter, status); + dashes[9] = 0.0; + status = GdipSetPenDashArray(pen, &dashes[7], 5); + expect(InvalidParameter, status); /* Try to set with count = 0. */ GdipSetPenDashStyle(pen, DashStyleDot); diff --git a/modules/rostests/winetests/gdiplus/region.c b/modules/rostests/winetests/gdiplus/region.c index d69f09db602..7920afd8ef4 100644 --- a/modules/rostests/winetests/gdiplus/region.c +++ b/modules/rostests/winetests/gdiplus/region.c @@ -33,11 +33,15 @@ #define RGNDATA_MAGIC 0xdbc01001 #define RGNDATA_MAGIC2 0xdbc01002 -#define expect(expected, got) ok((got) == (expected), "Expected %.8x, got %.8x\n", (expected), (got)) +#define expect(expected,got) expect_(__LINE__, expected, got) +static inline void expect_(unsigned line, DWORD expected, DWORD got) +{ + ok_(__FILE__, line)(expected == got, "Expected %ld, got %ld\n", expected, got); +} #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) -#define expect_magic(value) ok(broken(*(value) == RGNDATA_MAGIC) || *(value) == RGNDATA_MAGIC2, "Expected a known magic value, got %8x\n", *(value)) +#define expect_magic(value) ok(broken(*(value) == RGNDATA_MAGIC) || *(value) == RGNDATA_MAGIC2, "Expected a known magic value, got %8lx\n", *(value)) #define expect_dword(value, expected) expect((expected), *(value)) #define expect_float(value, expected) expectf((expected), *(FLOAT *)(value)) @@ -59,19 +63,19 @@ static void verify_region(HRGN hrgn, const RECT *rc) ret = GetRegionData(hrgn, 0, NULL); if (IsRectEmpty(rc)) - ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", ret); + ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %lu\n", ret); else - ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret); + ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %lu\n", ret); if (!ret) return; ret = GetRegionData(hrgn, sizeof(rgn), &rgn.data); if (IsRectEmpty(rc)) - ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", ret); + ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %lu\n", ret); else - ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret); + ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %lu\n", ret); - trace("size %u, type %u, count %u, rgn size %u, bound %s\n", + trace("size %lu, type %lu, count %lu, rgn size %lu, bound %s\n", rgn.data.rdh.dwSize, rgn.data.rdh.iType, rgn.data.rdh.nCount, rgn.data.rdh.nRgnSize, wine_dbgstr_rect(&rgn.data.rdh.rcBound)); @@ -83,17 +87,17 @@ static void verify_region(HRGN hrgn, const RECT *rc) wine_dbgstr_rect(rc), wine_dbgstr_rect(rect)); } - ok(rgn.data.rdh.dwSize == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", rgn.data.rdh.dwSize); - ok(rgn.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn.data.rdh.iType); + ok(rgn.data.rdh.dwSize == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %lu\n", rgn.data.rdh.dwSize); + ok(rgn.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %lu\n", rgn.data.rdh.iType); if (IsRectEmpty(rc)) { - ok(rgn.data.rdh.nCount == 0, "expected 0, got %u\n", rgn.data.rdh.nCount); - ok(rgn.data.rdh.nRgnSize == 0, "expected 0, got %u\n", rgn.data.rdh.nRgnSize); + ok(rgn.data.rdh.nCount == 0, "expected 0, got %lu\n", rgn.data.rdh.nCount); + ok(rgn.data.rdh.nRgnSize == 0, "expected 0, got %lu\n", rgn.data.rdh.nRgnSize); } else { - ok(rgn.data.rdh.nCount == 1, "expected 1, got %u\n", rgn.data.rdh.nCount); - ok(rgn.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn.data.rdh.nRgnSize); + ok(rgn.data.rdh.nCount == 1, "expected 1, got %lu\n", rgn.data.rdh.nCount); + ok(rgn.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %lu\n", rgn.data.rdh.nRgnSize); } ok(EqualRect(&rgn.data.rdh.rcBound, rc), "expected %s, got %s\n", wine_dbgstr_rect(rc), wine_dbgstr_rect(&rgn.data.rdh.rcBound)); @@ -142,11 +146,11 @@ static void test_region_data(DWORD *data, UINT size, INT line) for (i = 0; i < size - 1; i++) { if (i == 1) continue; /* data[1] never matches */ - ok_(__FILE__, line)(data[i] == buf[i], "off %u: %#x != %#x\n", i, data[i], buf[i]); + ok_(__FILE__, line)(data[i] == buf[i], "off %u: %#lx != %#lx\n", i, data[i], buf[i]); } /* some Windows versions fail to properly clear the aligned DWORD */ ok_(__FILE__, line)(data[size - 1] == buf[size - 1] || broken(data[size - 1] != buf[size - 1]), - "off %u: %#x != %#x\n", size - 1, data[size - 1], buf[size - 1]); + "off %u: %#lx != %#lx\n", size - 1, data[size - 1], buf[size - 1]); GdipDeleteRegion(region); } @@ -187,7 +191,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(20, needed); expect_dword(buf, 12); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_INFINITE_RECT); @@ -205,7 +209,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(20, needed); expect_dword(buf, 12); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_EMPTY_RECT); @@ -223,7 +227,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(20, needed); expect_dword(buf, 12); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_INFINITE_RECT); @@ -248,7 +252,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(36, needed); expect_dword(buf, 28); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_RECT); @@ -304,7 +308,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(156, needed); expect_dword(buf, 148); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 10); expect_dword(buf + 4, CombineModeExclude); @@ -367,7 +371,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(72, needed); expect_dword(buf, 64); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_PATH); @@ -402,7 +406,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(96, needed); expect_dword(buf, 88); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 2); expect_dword(buf + 4, CombineModeIntersect); @@ -447,7 +451,7 @@ static void test_getregiondata(void) expect(Ok, status); expect(36, needed); expect_dword(buf, 28); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_PATH); @@ -457,7 +461,7 @@ static void test_getregiondata(void) expect_dword(buf + 7, 0); /* flags 0 means that a path is an array of FLOATs */ ok(*(buf + 8) == 0x4000 /* before win7 */ || *(buf + 8) == 0, - "expected 0x4000 or 0, got %08x\n", *(buf + 8)); + "expected 0x4000 or 0, got %08lx\n", *(buf + 8)); expect_dword(buf + 10, 0xeeeeeeee); test_region_data(buf, needed, __LINE__); @@ -489,7 +493,7 @@ static void test_getregiondata(void) expect(Ok, status); expect(56, needed); expect_dword(buf, 48); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3 , 0); expect_dword(buf + 4 , RGNDATA_PATH); @@ -563,7 +567,7 @@ static void test_getregiondata(void) expect(Ok, status); expect(72, needed); expect_dword(buf, 64); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_PATH); @@ -614,7 +618,7 @@ static void test_getregiondata(void) expect(Ok, status); expect(116, needed); expect_dword(buf, 108); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 2); expect_dword(buf + 4, CombineModeUnion); @@ -641,8 +645,8 @@ static void test_getregiondata(void) expect_float(buf + 25, 50.0); expect_float(buf + 26, 70.2); expect_dword(buf + 27, 0x01010100); - ok(*(buf + 28) == 0x00000101 || *(buf + 28) == 0x43050101 /* Win 7 */, - "expected 00000101 or 43050101 got %08x\n", *(buf + 28)); + ok((*(buf + 28) & 0xffff) == 0x0101, + "expected ????0101 got %08lx\n", *(buf + 28)); expect_dword(buf + 29, 0xeeeeeeee); test_region_data(buf, needed, __LINE__); @@ -668,7 +672,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(56, needed); expect_dword(buf, 48); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_PATH); @@ -712,7 +716,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(72, needed); expect_dword(buf, 64); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_PATH); @@ -758,7 +762,7 @@ static void test_getregiondata(void) ok(status == Ok, "status %08x\n", status); expect(136, needed); expect_dword(buf, 128); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_PATH); @@ -791,9 +795,8 @@ static void test_getregiondata(void) expect_float(buf + 30, 789.799561); expect_dword(buf + 31, 0x03030300); expect_dword(buf + 32, 0x03030301); - ok(*(buf + 33) == 0x00030303 /* before win7 */ || - *(buf + 33) == 0x43030303 /* 32-bit win7 */ || *(buf + 33) == 0x4c030303 /* 64-bit win7 */, - "expected 0x00030303 or 0x43030303 or 0x4c030303 got %08x\n", *(buf + 33)); + ok((*(buf + 33) & 0xffffff) == 0x030303, + "expected 0x??030303 got %08lx\n", *(buf + 33)); expect_dword(buf + 34, 0xeeeeeeee); test_region_data(buf, needed, __LINE__); @@ -921,7 +924,7 @@ static void test_combinereplace(void) expect(Ok, status); expect(36, needed); expect_dword(buf, 28); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_RECT); @@ -941,7 +944,7 @@ static void test_combinereplace(void) expect(Ok, status); expect(156, needed); expect_dword(buf, 148); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_PATH); @@ -960,7 +963,7 @@ static void test_combinereplace(void) expect(Ok, status); expect(20, needed); expect_dword(buf, 12); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 0); expect_dword(buf + 4, RGNDATA_INFINITE_RECT); @@ -987,7 +990,7 @@ static void test_combinereplace(void) expect(Ok, status); expect(180, needed); expect_dword(buf, 172); - trace("buf[1] = %08x\n", buf[1]); + trace("buf[1] = %08lx\n", buf[1]); expect_magic(buf + 2); expect_dword(buf + 3, 2); expect_dword(buf + 4, CombineModeUnion); @@ -1446,14 +1449,14 @@ static void test_translate(void) static DWORD get_region_type(GpRegion *region) { DWORD *data; - DWORD size; + UINT size; DWORD result; DWORD status; status = GdipGetRegionDataSize(region, &size); expect(Ok, status); data = GdipAlloc(size); status = GdipGetRegionData(region, (BYTE*)data, size, NULL); - ok(status == Ok || status == InsufficientBuffer, "unexpected status 0x%x\n", status); + ok(status == Ok || status == InsufficientBuffer, "unexpected status 0x%lx\n", status); result = data[4]; GdipFree(data); return result; @@ -1594,7 +1597,7 @@ static void test_scans(void) GpMatrix *matrix; GpRectF rectf; GpStatus status; - ULONG count=80085; + UINT count=80085; INT icount; GpRectF scans[2]; GpRect scansi[2]; diff --git a/modules/rostests/winetests/gdiplus/resource.rc b/modules/rostests/winetests/gdiplus/resource.rc index d7d915ce001..2db8d6359ea 100644 --- a/modules/rostests/winetests/gdiplus/resource.rc +++ b/modules/rostests/winetests/gdiplus/resource.rc @@ -20,3 +20,6 @@ /* @makedep: wine_longname.ttf */ 1 RCDATA wine_longname.ttf + +/* @makedep: wine_testfont0.ttf */ +2 RCDATA wine_testfont0.ttf diff --git a/modules/rostests/winetests/gdiplus/wine_testfont0.sfd b/modules/rostests/winetests/gdiplus/wine_testfont0.sfd new file mode 100644 index 00000000000..c71f717c4a6 --- /dev/null +++ b/modules/rostests/winetests/gdiplus/wine_testfont0.sfd @@ -0,0 +1,69 @@ +SplineFontDB: 3.0 +FontName: winegdiptestfont0 +FullName: Wine GDI+ Test Font 0 +FamilyName: winegdiptestfont +Weight: Regular +Copyright: Copyright (c) 2020, Shawn M. Chapla +UComments: "2020-7-15: Created with FontForge (http://fontforge.org)" +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -100 +UnderlineWidth: 50 +Ascent: 800 +Descent: 200 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 445 409452897 2998051] +StyleMap: 0x0000 +FSType: 0 +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1594833132 +ModificationTime: 1594833348 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 90 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +MarkAttachClasses: 1 +DEI: 91125 +Encoding: ISO8859-1 +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 0 16 4 +BeginPrivate: 0 +EndPrivate +BeginChars: 256 1 + +StartChar: uni0000 +Encoding: 0 0 0 +Width: 2977 +VWidth: 0 +Flags: HWO +LayerCount: 2 +Fore +SplineSet +247 690 m 5 + 748 690 l 5 + 748 72 l 5 + 247 72 l 5 + 247 690 l 5 +EndSplineSet +Validated: 1 +EndChar +EndChars +EndSplineFont diff --git a/modules/rostests/winetests/gdiplus/wine_testfont0.ttf b/modules/rostests/winetests/gdiplus/wine_testfont0.ttf new file mode 100644 index 00000000000..fb899cb342f Binary files /dev/null and b/modules/rostests/winetests/gdiplus/wine_testfont0.ttf differ diff --git a/sdk/include/psdk/gdiplusflat.h b/sdk/include/psdk/gdiplusflat.h index 3613f54aa6e..03ffa5fe438 100644 --- a/sdk/include/psdk/gdiplusflat.h +++ b/sdk/include/psdk/gdiplusflat.h @@ -1103,6 +1103,8 @@ extern "C" GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *, MetafileHeader *); GpStatus WINGDIPAPI + GdipGetMetafileDownLevelRasterizationLimit(GDIPCONST GpMetafile*,UINT*); + GpStatus WINGDIPAPI GdipGetMetafileHeaderFromWmf(HMETAFILE, GDIPCONST WmfPlaceableFileHeader *, MetafileHeader *); /* Notification */ diff --git a/sdk/tools/winesync/gdiplus_tests.cfg b/sdk/tools/winesync/gdiplus_tests.cfg new file mode 100644 index 00000000000..16f72f07545 --- /dev/null +++ b/sdk/tools/winesync/gdiplus_tests.cfg @@ -0,0 +1,5 @@ +directories: + dlls/gdiplus/tests: modules/rostests/winetests/gdiplus +files: null +tags: + wine: 7abca9742a9410447636e0222e36d214449c90dd