diff --git a/dlls/gdiplus/gdiplus.spec b/dlls/gdiplus/gdiplus.spec index 900def9c29..2fc4686478 100644 --- a/dlls/gdiplus/gdiplus.spec +++ b/dlls/gdiplus/gdiplus.spec @@ -433,8 +433,8 @@ @ stdcall GdipIsVisibleRectI(ptr long long long long ptr) @ stdcall GdipIsVisibleRegionPoint(ptr long long ptr ptr) @ stdcall GdipIsVisibleRegionPointI(ptr long long ptr ptr) -@ stub GdipIsVisibleRegionRect -@ stub GdipIsVisibleRegionRectI +@ stdcall GdipIsVisibleRegionRect(ptr long long long long ptr ptr) +@ stdcall GdipIsVisibleRegionRectI(ptr long long long long ptr ptr) @ stdcall GdipLoadImageFromFile(wstr ptr) @ stdcall GdipLoadImageFromFileICM(wstr ptr) @ stdcall GdipLoadImageFromStream(ptr ptr) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index dccc8349dc..e36f92130e 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -68,6 +68,11 @@ static inline INT roundr(REAL x) return (INT) floorf(x + 0.5); } +static inline INT ceilr(REAL x) +{ + return (INT) ceilf(x); +} + static inline REAL deg2rad(REAL degrees) { return M_PI * degrees / 180.0; diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c index a6aba971b0..197b68af4a 100644 --- a/dlls/gdiplus/region.c +++ b/dlls/gdiplus/region.c @@ -1127,6 +1127,53 @@ GpStatus WINGDIPAPI GdipIsInfiniteRegion(GpRegion *region, GpGraphics *graphics, return Ok; } +/***************************************************************************** + * GdipIsVisibleRegionRect [GDIPLUS.@] + */ +GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion* region, REAL x, REAL y, REAL w, REAL h, GpGraphics *graphics, BOOL *res) +{ + HRGN hrgn; + GpStatus stat; + RECT rect; + + TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %p, %p)\n", region, x, y, w, h, graphics, res); + + if(!region || !res) + return InvalidParameter; + + if((stat = GdipGetRegionHRgn(region, NULL, &hrgn)) != Ok) + return stat; + + /* infinite */ + if(!hrgn){ + *res = TRUE; + return Ok; + } + + rect.left = ceilr(x); + rect.top = ceilr(y); + rect.right = ceilr(x + w); + rect.bottom = ceilr(y + h); + + *res = RectInRegion(hrgn, &rect); + + DeleteObject(hrgn); + + return Ok; +} + +/***************************************************************************** + * GdipIsVisibleRegionRectI [GDIPLUS.@] + */ +GpStatus WINGDIPAPI GdipIsVisibleRegionRectI(GpRegion* region, INT x, INT y, INT w, INT h, GpGraphics *graphics, BOOL *res) +{ + TRACE("(%p, %d, %d, %d, %d, %p, %p)\n", region, x, y, w, h, graphics, res); + if(!region || !res) + return InvalidParameter; + + return GdipIsVisibleRegionRect(region, (REAL)x, (REAL)y, (REAL)w, (REAL)h, graphics, res); +} + /***************************************************************************** * GdipIsVisibleRegionPoint [GDIPLUS.@] */ diff --git a/dlls/gdiplus/tests/region.c b/dlls/gdiplus/tests/region.c index 902dcdd51c..b3142ba7fa 100644 --- a/dlls/gdiplus/tests/region.c +++ b/dlls/gdiplus/tests/region.c @@ -1407,6 +1407,210 @@ static void test_isvisiblepoint(void) ReleaseDC(0, hdc); } +static void test_isvisiblerect(void) +{ + HDC hdc = GetDC(0); + GpGraphics* graphics; + GpRegion* region; + GpPath* path; + GpRectF rectf; + GpStatus status; + BOOL res; + REAL x, y, w, h; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + status = GdipCreateRegion(®ion); + expect(Ok, status); + + /* null parameters */ + status = GdipIsVisibleRegionRect(NULL, 0, 0, 0, 0, graphics, &res); + expect(InvalidParameter, status); + status = GdipIsVisibleRegionRectI(NULL, 0, 0, 0, 0, graphics, &res); + expect(InvalidParameter, status); + + status = GdipIsVisibleRegionRect(region, 0, 0, 0, 0, NULL, &res); + expect(Ok, status); + status = GdipIsVisibleRegionRectI(region, 0, 0, 0, 0, NULL, &res); + expect(Ok, status); + + status = GdipIsVisibleRegionRect(region, 0, 0, 0, 0, graphics, NULL); + expect(InvalidParameter, status); + status = GdipIsVisibleRegionRectI(region, 0, 0, 0, 0, graphics, NULL); + expect(InvalidParameter, status); + + /* infinite region */ + status = GdipIsInfiniteRegion(region, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Region should be infinite\n"); + + x = 10; w = 10; + y = 10; h = 10; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + + x = -10; w = 5; + y = -10; h = 5; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + + /* rectangular region */ + rectf.X = 10; + rectf.Y = 20; + rectf.Width = 30; + rectf.Height = 40; + + status = GdipCombineRegionRect(region, &rectf, CombineModeIntersect); + expect(Ok, status); + + /* entirely within the region */ + x = 11; w = 10; + y = 12; h = 10; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%d, %d, %d, %d) to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + /* entirely outside of the region */ + x = 0; w = 5; + y = 0; h = 5; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%.2f, %.2f, %.2f, %.2f) not to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%d, %d, %d, %d) not to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + /* corner cases */ + x = 0; w = 10; + y = 0; h = 20; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%.2f, %.2f, %.2f, %.2f) not to be visible\n", x, y, w, h); + + x = 0; w = 10.25; + y = 0; h = 20.25; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + + x = 39; w = 10; + y = 59; h = 10; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + + x = 39.25; w = 10; + y = 59.25; h = 10; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%.2f, %.2f, %.2f, %.2f) not to be visible\n", x, y, w, h); + + /* corners outside, but some intersection */ + x = 0; w = 100; + y = 0; h = 100; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + + x = 0; w = 100; + y = 0; h = 40; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + + x = 0; w = 25; + y = 0; h = 100; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + + /* translate into the center of the rectangle */ + status = GdipTranslateWorldTransform(graphics, 25, 40, MatrixOrderAppend); + expect(Ok, status); + + /* native ignores the world transform, so treat these as if + * no transform exists */ + x = 0; w = 5; + y = 0; h = 5; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%.2f, %.2f, %.2f, %.2f) not to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%d, %d, %d, %d) not to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + x = 11; w = 10; + y = 12; h = 10; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%d, %d, %d, %d) to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + /* translate back to origin */ + status = GdipTranslateWorldTransform(graphics, -25, -40, MatrixOrderAppend); + expect(Ok, status); + + /* region from path */ + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + + status = GdipAddPathEllipse(path, 10, 20, 30, 40); + expect(Ok, status); + + status = GdipCombineRegionPath(region, path, CombineModeReplace); + expect(Ok, status); + + x = 0; w = 12; + y = 0; h = 22; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%.2f, %.2f, %.2f, %.2f) not to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%d, %d, %d, %d) not to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + x = 0; w = 25; + y = 0; h = 40; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%d, %d, %d, %d) to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + x = 38; w = 10; + y = 55; h = 10; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%.2f, %.2f, %.2f, %.2f) not to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == FALSE, "Expected (%d, %d, %d, %d) not to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + x = 0; w = 100; + y = 0; h = 100; + status = GdipIsVisibleRegionRect(region, x, y, w, h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, w, h); + status = GdipIsVisibleRegionRectI(region, (INT)x, (INT)y, (INT)w, (INT)h, graphics, &res); + expect(Ok, status); + ok(res == TRUE, "Expected (%d, %d, %d, %d) to be visible\n", (INT)x, (INT)y, (INT)w, (INT)h); + + GdipDeletePath(path); + + GdipDeleteRegion(region); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + START_TEST(region) { struct GdiplusStartupInput gdiplusStartupInput; @@ -1429,6 +1633,7 @@ START_TEST(region) test_translate(); test_getbounds(); test_isvisiblepoint(); + test_isvisiblerect(); GdiplusShutdown(gdiplusToken); } diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h index 7e4e35ab74..fd8302dc9d 100644 --- a/include/gdiplusflat.h +++ b/include/gdiplusflat.h @@ -567,6 +567,8 @@ GpStatus WINGDIPAPI GdipIsEqualRegion(GpRegion *, GpRegion *, GpGraphics *, BOOL GpStatus WINGDIPAPI GdipIsInfiniteRegion(GpRegion *, GpGraphics *, BOOL *); GpStatus WINGDIPAPI GdipIsVisibleRegionPoint(GpRegion *, REAL, REAL, GpGraphics *, BOOL *); GpStatus WINGDIPAPI GdipIsVisibleRegionPointI(GpRegion *, INT, INT, GpGraphics *, BOOL *); +GpStatus WINGDIPAPI GdipIsVisibleRegionRect(GpRegion *, REAL, REAL, REAL, REAL, GpGraphics *, BOOL *); +GpStatus WINGDIPAPI GdipIsVisibleRegionRectI(GpRegion *, INT, INT, INT, INT, GpGraphics *, BOOL *); GpStatus WINGDIPAPI GdipSetEmpty(GpRegion *); GpStatus WINGDIPAPI GdipSetInfinite(GpRegion *); GpStatus WINGDIPAPI GdipTransformRegion(GpRegion *, GpMatrix *);