diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 2935e6e5ae8be..11a57068da5bf 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -2115,6 +2115,48 @@ TEST(GeometryTest, RectGetPositive) { } } +TEST(GeometryTest, RectScale) { + { + auto r = Rect::MakeLTRB(-100, -100, 100, 100); + auto actual = r.Scale(0); + auto expected = Rect::MakeLTRB(0, 0, 0, 0); + ASSERT_RECT_NEAR(expected, actual); + } + { + auto r = Rect::MakeLTRB(-100, -100, 100, 100); + auto actual = r.Scale(-2); + auto expected = Rect::MakeLTRB(200, 200, -200, -200); + ASSERT_RECT_NEAR(expected, actual); + } + { + auto r = Rect::MakeLTRB(-100, -100, 100, 100); + auto actual = r.Scale(Point{0, 0}); + auto expected = Rect::MakeLTRB(0, 0, 0, 0); + ASSERT_RECT_NEAR(expected, actual); + } + { + auto r = Rect::MakeLTRB(-100, -100, 100, 100); + auto actual = r.Scale(Size{-1, -2}); + auto expected = Rect::MakeLTRB(100, 200, -100, -200); + ASSERT_RECT_NEAR(expected, actual); + } +} + +TEST(GeometryTest, RectProject) { + { + auto r = Rect::MakeLTRB(-100, -100, 100, 100); + auto actual = r.Project(r); + auto expected = Rect::MakeLTRB(0, 0, 1, 1); + ASSERT_RECT_NEAR(expected, actual); + } + { + auto r = Rect::MakeLTRB(-100, -100, 100, 100); + auto actual = r.Project(Rect::MakeLTRB(0, 0, 100, 100)); + auto expected = Rect::MakeLTRB(0.5, 0.5, 1, 1); + ASSERT_RECT_NEAR(expected, actual); + } +} + TEST(GeometryTest, CubicPathComponentPolylineDoesNotIncludePointOne) { CubicPathComponent component({10, 10}, {20, 35}, {35, 20}, {40, 40}); auto polyline = component.CreatePolyline(1.0f); diff --git a/impeller/geometry/rect.h b/impeller/geometry/rect.h index 14c337b43a553..7a2c18b7454fc 100644 --- a/impeller/geometry/rect.h +++ b/impeller/geometry/rect.h @@ -94,10 +94,7 @@ struct TRect { {size.width - r.size.width, size.height - r.size.height}); } - constexpr TRect operator*(Type scale) const { - return TRect({origin.x * scale, origin.y * scale}, - {size.width * scale, size.height * scale}); - } + constexpr TRect operator*(Type scale) const { return Scale(scale); } constexpr TRect operator*(const TRect& r) const { return TRect({origin.x * r.origin.x, origin.y * r.origin.y}, @@ -108,6 +105,20 @@ struct TRect { return origin == r.origin && size == r.size; } + constexpr TRect Scale(Type scale) const { + return TRect({origin.x * scale, origin.y * scale}, + {size.width * scale, size.height * scale}); + } + + constexpr TRect Scale(TPoint scale) const { + return TRect({origin.x * scale.x, origin.y * scale.y}, + {size.width * scale.x, size.height * scale.y}); + } + + constexpr TRect Scale(TSize scale) const { + return Scale(TPoint(scale)); + } + constexpr bool Contains(const TPoint& p) const { return p.x >= GetLeft() && p.x < GetRight() && p.y >= GetTop() && p.y < GetBottom(); @@ -255,7 +266,7 @@ struct TRect { /// @brief Returns a rectangle with expanded edges. Negative expansion /// results in shrinking. - constexpr TRect Expand(T left, T top, T right, T bottom) { + constexpr TRect Expand(T left, T top, T right, T bottom) const { return TRect(origin.x - left, // origin.y - top, // size.width + left + right, // @@ -264,12 +275,22 @@ struct TRect { /// @brief Returns a rectangle with expanded edges in all directions. /// Negative expansion results in shrinking. - constexpr TRect Expand(T amount) { + constexpr TRect Expand(T amount) const { return TRect(origin.x - amount, // origin.y - amount, // size.width + amount * 2, // size.height + amount * 2); } + + /// @brief Returns a new rectangle that represents the projection of the + /// source rectangle onto this rectangle. In other words, the source + /// rectangle is redefined in terms of the corrdinate space of this + /// rectangle. + constexpr TRect Project(TRect source) const { + return source.Shift(-origin).Scale( + TSize(1.0 / static_cast(size.width), + 1.0 / static_cast(size.height))); + } }; using Rect = TRect;