Signed-off-by: Jeff Smith whydoubt@gmail.com --- dlls/gdiplus/tests/brush.c | 93 ++++++++++++++++++++++++++++++++++++++ include/gdiplusflat.h | 1 + 2 files changed, 94 insertions(+)
diff --git a/dlls/gdiplus/tests/brush.c b/dlls/gdiplus/tests/brush.c index fca1c17057..8e0d7e9ca0 100644 --- a/dlls/gdiplus/tests/brush.c +++ b/dlls/gdiplus/tests/brush.c @@ -1778,6 +1778,98 @@ static void test_hatchBrushStyles(void) 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] % 8) + 8) % 8; + const INT exp_y = ((tests[i][1] % 8) + 8) % 8; + + 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; + } + } + todo_wine + { + 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; @@ -1831,6 +1923,7 @@ START_TEST(brush) test_pathgradientblend(); test_getHatchStyle(); test_hatchBrushStyles(); + test_renderingOrigin();
GdiplusShutdown(gdiplusToken); DestroyWindow(hwnd); diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h index b7da5427d4..1526ce0338 100644 --- a/include/gdiplusflat.h +++ b/include/gdiplusflat.h @@ -258,6 +258,7 @@ GpStatus WINGDIPAPI GdipGetNearestColor(GpGraphics*,ARGB*); GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics*,REAL*); GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics*,GpUnit*); GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics*,PixelOffsetMode*); +GpStatus WINGDIPAPI GdipGetRenderingOrigin(GpGraphics*,INT*,INT*); GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics*,SmoothingMode*); GpStatus WINGDIPAPI GdipGetTextContrast(GpGraphics*,UINT*); GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics*,TextRenderingHint*);
Signed-off-by: Jeff Smith whydoubt@gmail.com --- dlls/gdiplus/graphics.c | 31 ++++++++++++++----------------- dlls/gdiplus/tests/brush.c | 3 --- 2 files changed, 14 insertions(+), 20 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 1ed29d1094..6619be9b58 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -127,7 +127,7 @@ static void init_hatch_palette(ARGB *hatch_palette, ARGB fore_color, ARGB back_c hatch_palette[3] = fore_color; }
-static HBITMAP create_hatch_bitmap(const GpHatch *hatch) +static HBITMAP create_hatch_bitmap(const GpHatch *hatch, INT origin_x, INT origin_y) { HBITMAP hbmp; BITMAPINFOHEADER bmih; @@ -159,7 +159,9 @@ static HBITMAP create_hatch_bitmap(const GpHatch *hatch) * degree of shading needed. */ for (y = 0; y < 8; y++) { - unsigned int row = 0x101 * hatch_data[y]; + const int hy = (((y + origin_y) % 8) + 8) % 8; + const int hx = ((origin_x % 8) + 8) % 8; + unsigned int row = (0x10101 * hatch_data[hy]) >> hx;
for (x = 0; x < 8; x++, row >>= 1) { @@ -184,7 +186,7 @@ static HBITMAP create_hatch_bitmap(const GpHatch *hatch) return hbmp; }
-static GpStatus create_gdi_logbrush(const GpBrush *brush, LOGBRUSH *lb) +static GpStatus create_gdi_logbrush(const GpBrush *brush, LOGBRUSH *lb, INT origin_x, INT origin_y) { switch (brush->bt) { @@ -202,7 +204,7 @@ static GpStatus create_gdi_logbrush(const GpBrush *brush, LOGBRUSH *lb) const GpHatch *hatch = (const GpHatch *)brush; HBITMAP hbmp;
- hbmp = create_hatch_bitmap(hatch); + hbmp = create_hatch_bitmap(hatch, origin_x, origin_y); if (!hbmp) return OutOfMemory;
lb->lbStyle = BS_PATTERN; @@ -231,12 +233,12 @@ static GpStatus free_gdi_logbrush(LOGBRUSH *lb) return Ok; }
-static HBRUSH create_gdi_brush(const GpBrush *brush) +static HBRUSH create_gdi_brush(const GpBrush *brush, INT origin_x, INT origin_y) { LOGBRUSH lb; HBRUSH gdibrush;
- if (create_gdi_logbrush(brush, &lb) != Ok) return 0; + if (create_gdi_logbrush(brush, &lb, origin_x, origin_y) != Ok) return 0;
gdibrush = CreateBrushIndirect(&lb); free_gdi_logbrush(&lb); @@ -293,14 +295,14 @@ static INT prepare_dc(GpGraphics *graphics, GpPen *pen) } TRACE("\n and the pen style is %x\n", pen->style);
- create_gdi_logbrush(pen->brush, &lb); + create_gdi_logbrush(pen->brush, &lb, graphics->origin_x, graphics->origin_y); gdipen = ExtCreatePen(pen->style, gdip_round(width), &lb, numdashes, dash_array); free_gdi_logbrush(&lb); } else { - create_gdi_logbrush(pen->brush, &lb); + create_gdi_logbrush(pen->brush, &lb, graphics->origin_x, graphics->origin_y); gdipen = ExtCreatePen(pen->style, gdip_round(width), &lb, 0, NULL); free_gdi_logbrush(&lb); } @@ -1134,7 +1136,7 @@ static GpStatus brush_fill_path(GpGraphics *graphics, GpBrush *brush) { HBRUSH gdibrush, old_brush;
- gdibrush = create_gdi_brush(brush); + gdibrush = create_gdi_brush(brush, graphics->origin_x, graphics->origin_y); if (!gdibrush) { status = OutOfMemory; @@ -1196,9 +1198,9 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush, /* See create_hatch_bitmap for an explanation of how index is derived. */ for (y = 0; y < fill_area->Height; y++, argb_pixels += cdwStride) { - /* FIXME: Account for the rendering origin */ - const int hy = 7 - ((y + fill_area->Y) % 8); - const unsigned int row = 0x101 * hatch_data[hy]; + const int hy = (7 - ((y + fill_area->Y - graphics->origin_y) % 8)) % 8; + const int hx = ((graphics->origin_x % 8) + 8) % 8; + const unsigned int row = (0x10101 * hatch_data[hy]) >> hx;
for (x = 0; x < fill_area->Width; x++) { @@ -6193,13 +6195,8 @@ GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y) { - static int calls; - TRACE("(%p,%i,%i)\n", graphics, x, y);
- if (!(calls++)) - FIXME("value is unused in rendering\n"); - if (!graphics) return InvalidParameter;
diff --git a/dlls/gdiplus/tests/brush.c b/dlls/gdiplus/tests/brush.c index 8e0d7e9ca0..5d5280c7f9 100644 --- a/dlls/gdiplus/tests/brush.c +++ b/dlls/gdiplus/tests/brush.c @@ -1852,13 +1852,10 @@ static void test_renderingOrigin(void) match_image = FALSE; } } - todo_wine - { 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);
Signed-off-by: Esme Povirk vincent@codeweavers.com
+ const INT exp_x = ((tests[i][0] % 8) + 8) % 8; + const INT exp_y = ((tests[i][1] % 8) + 8) % 8;
Not sure if it matters too much, but this could be more simply written as & 7.
Signed-off-by: Jeff Smith whydoubt@gmail.com --- v2: - Use (x&7) for signed modulo 8 (that wraps instead of mirrors at zero)
dlls/gdiplus/tests/brush.c | 93 ++++++++++++++++++++++++++++++++++++++ include/gdiplusflat.h | 1 + 2 files changed, 94 insertions(+)
diff --git a/dlls/gdiplus/tests/brush.c b/dlls/gdiplus/tests/brush.c index fca1c17057..0a423b34d0 100644 --- a/dlls/gdiplus/tests/brush.c +++ b/dlls/gdiplus/tests/brush.c @@ -1778,6 +1778,98 @@ static void test_hatchBrushStyles(void) 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; + } + } + todo_wine + { + 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; @@ -1831,6 +1923,7 @@ START_TEST(brush) test_pathgradientblend(); test_getHatchStyle(); test_hatchBrushStyles(); + test_renderingOrigin();
GdiplusShutdown(gdiplusToken); DestroyWindow(hwnd); diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h index b7da5427d4..1526ce0338 100644 --- a/include/gdiplusflat.h +++ b/include/gdiplusflat.h @@ -258,6 +258,7 @@ GpStatus WINGDIPAPI GdipGetNearestColor(GpGraphics*,ARGB*); GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics*,REAL*); GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics*,GpUnit*); GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics*,PixelOffsetMode*); +GpStatus WINGDIPAPI GdipGetRenderingOrigin(GpGraphics*,INT*,INT*); GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics*,SmoothingMode*); GpStatus WINGDIPAPI GdipGetTextContrast(GpGraphics*,UINT*); GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics*,TextRenderingHint*);
Signed-off-by: Jeff Smith whydoubt@gmail.com --- dlls/gdiplus/graphics.c | 33 +++++++++++++++------------------ dlls/gdiplus/tests/brush.c | 3 --- 2 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 1ed29d1094..4b141e19b6 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -127,7 +127,7 @@ static void init_hatch_palette(ARGB *hatch_palette, ARGB fore_color, ARGB back_c hatch_palette[3] = fore_color; }
-static HBITMAP create_hatch_bitmap(const GpHatch *hatch) +static HBITMAP create_hatch_bitmap(const GpHatch *hatch, INT origin_x, INT origin_y) { HBITMAP hbmp; BITMAPINFOHEADER bmih; @@ -159,7 +159,9 @@ static HBITMAP create_hatch_bitmap(const GpHatch *hatch) * degree of shading needed. */ for (y = 0; y < 8; y++) { - unsigned int row = 0x101 * hatch_data[y]; + const int hy = (y + origin_y) & 7; + const int hx = origin_x & 7; + unsigned int row = (0x10101 * hatch_data[hy]) >> hx;
for (x = 0; x < 8; x++, row >>= 1) { @@ -184,7 +186,7 @@ static HBITMAP create_hatch_bitmap(const GpHatch *hatch) return hbmp; }
-static GpStatus create_gdi_logbrush(const GpBrush *brush, LOGBRUSH *lb) +static GpStatus create_gdi_logbrush(const GpBrush *brush, LOGBRUSH *lb, INT origin_x, INT origin_y) { switch (brush->bt) { @@ -202,7 +204,7 @@ static GpStatus create_gdi_logbrush(const GpBrush *brush, LOGBRUSH *lb) const GpHatch *hatch = (const GpHatch *)brush; HBITMAP hbmp;
- hbmp = create_hatch_bitmap(hatch); + hbmp = create_hatch_bitmap(hatch, origin_x, origin_y); if (!hbmp) return OutOfMemory;
lb->lbStyle = BS_PATTERN; @@ -231,12 +233,12 @@ static GpStatus free_gdi_logbrush(LOGBRUSH *lb) return Ok; }
-static HBRUSH create_gdi_brush(const GpBrush *brush) +static HBRUSH create_gdi_brush(const GpBrush *brush, INT origin_x, INT origin_y) { LOGBRUSH lb; HBRUSH gdibrush;
- if (create_gdi_logbrush(brush, &lb) != Ok) return 0; + if (create_gdi_logbrush(brush, &lb, origin_x, origin_y) != Ok) return 0;
gdibrush = CreateBrushIndirect(&lb); free_gdi_logbrush(&lb); @@ -293,14 +295,14 @@ static INT prepare_dc(GpGraphics *graphics, GpPen *pen) } TRACE("\n and the pen style is %x\n", pen->style);
- create_gdi_logbrush(pen->brush, &lb); + create_gdi_logbrush(pen->brush, &lb, graphics->origin_x, graphics->origin_y); gdipen = ExtCreatePen(pen->style, gdip_round(width), &lb, numdashes, dash_array); free_gdi_logbrush(&lb); } else { - create_gdi_logbrush(pen->brush, &lb); + create_gdi_logbrush(pen->brush, &lb, graphics->origin_x, graphics->origin_y); gdipen = ExtCreatePen(pen->style, gdip_round(width), &lb, 0, NULL); free_gdi_logbrush(&lb); } @@ -1134,7 +1136,7 @@ static GpStatus brush_fill_path(GpGraphics *graphics, GpBrush *brush) { HBRUSH gdibrush, old_brush;
- gdibrush = create_gdi_brush(brush); + gdibrush = create_gdi_brush(brush, graphics->origin_x, graphics->origin_y); if (!gdibrush) { status = OutOfMemory; @@ -1196,13 +1198,13 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush, /* See create_hatch_bitmap for an explanation of how index is derived. */ for (y = 0; y < fill_area->Height; y++, argb_pixels += cdwStride) { - /* FIXME: Account for the rendering origin */ - const int hy = 7 - ((y + fill_area->Y) % 8); - const unsigned int row = 0x101 * hatch_data[hy]; + const int hy = ~(y + fill_area->Y - graphics->origin_y) & 7; + const int hx = graphics->origin_x & 7; + const unsigned int row = (0x10101 * hatch_data[hy]) >> hx;
for (x = 0; x < fill_area->Width; x++) { - const unsigned int srow = row >> (7 - ((x + fill_area->X) % 8)); + const unsigned int srow = row >> (~(x + fill_area->X) & 7); int index; if (hatch_data[8]) index = (srow & 1) ? 2 : (srow & 0x82) ? 1 : 0; @@ -6193,13 +6195,8 @@ GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y) { - static int calls; - TRACE("(%p,%i,%i)\n", graphics, x, y);
- if (!(calls++)) - FIXME("value is unused in rendering\n"); - if (!graphics) return InvalidParameter;
diff --git a/dlls/gdiplus/tests/brush.c b/dlls/gdiplus/tests/brush.c index 0a423b34d0..78939e6899 100644 --- a/dlls/gdiplus/tests/brush.c +++ b/dlls/gdiplus/tests/brush.c @@ -1852,13 +1852,10 @@ static void test_renderingOrigin(void) match_image = FALSE; } } - todo_wine - { 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);