From e3d43575511b7080ebea1fc0df82e4fbdcc2a1f4 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 8 Dec 2021 14:08:22 -0800 Subject: [PATCH] Support non-uniform rounding radii. --- impeller/aiks/aiks_unittests.cc | 21 ++++++ impeller/geometry/path_builder.cc | 117 ++++++++++++++++-------------- impeller/geometry/path_builder.h | 41 ++++++----- impeller/geometry/point.h | 6 +- 4 files changed, 110 insertions(+), 75 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 0aacead3f3bd8..bac170f9cdc71 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -224,5 +224,26 @@ TEST_F(AiksTest, ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_F(AiksTest, CanRenderRoundedRectWithNonUniformRadii) { + Canvas canvas; + + Paint paint; + paint.color = Color::Red(); + + PathBuilder::RoundingRadii radii; + radii.top_left = {50, 25}; + radii.top_right = {25, 50}; + radii.bottom_right = {50, 25}; + radii.bottom_left = {25, 50}; + + auto path = PathBuilder{} + .AddRoundedRect(Rect{100, 100, 500, 500}, radii) + .CreatePath(); + + canvas.DrawPath(path, paint); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/geometry/path_builder.cc b/impeller/geometry/path_builder.cc index 94062420dd3d4..2524c4276291b 100644 --- a/impeller/geometry/path_builder.cc +++ b/impeller/geometry/path_builder.cc @@ -163,92 +163,97 @@ PathBuilder& PathBuilder::AddCircle(const Point& c, Scalar r) { } PathBuilder& PathBuilder::AddRoundedRect(Rect rect, Scalar radius) { - return radius == 0.0 ? AddRect(rect) + return radius <= 0.0 ? AddRect(rect) : AddRoundedRect(rect, {radius, radius, radius, radius}); } PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) { - current_ = rect.origin + Point{radii.topLeft, 0.0}; + if (radii.AreAllZero()) { + return AddRect(rect); + } + + current_ = rect.origin + Point{radii.top_left.x, 0.0}; - const Scalar magic_top_right = kArcApproximationMagic * radii.topRight; - const Scalar magic_bottom_right = kArcApproximationMagic * radii.bottomRight; - const Scalar magic_bottom_left = kArcApproximationMagic * radii.bottomLeft; - const Scalar magic_top_left = kArcApproximationMagic * radii.topLeft; + const auto magic_top_right = radii.top_right * kArcApproximationMagic; + const auto magic_bottom_right = radii.bottom_right * kArcApproximationMagic; + const auto magic_bottom_left = radii.bottom_left * kArcApproximationMagic; + const auto magic_top_left = radii.top_left * kArcApproximationMagic; //---------------------------------------------------------------------------- - /// Top line. - /// + // Top line. + // prototype_.AddLinearComponent( - {rect.origin.x + radii.topLeft, rect.origin.y}, - {rect.origin.x + rect.size.width - radii.topRight, rect.origin.y}); + {rect.origin.x + radii.top_left.x, rect.origin.y}, + {rect.origin.x + rect.size.width - radii.top_right.x, rect.origin.y}); //---------------------------------------------------------------------------- - /// Top right arc. - /// + // Top right arc. + // prototype_.AddCubicComponent( - {rect.origin.x + rect.size.width - radii.topRight, rect.origin.y}, - {rect.origin.x + rect.size.width - radii.topRight + magic_top_right, + {rect.origin.x + rect.size.width - radii.top_right.x, rect.origin.y}, + {rect.origin.x + rect.size.width - radii.top_right.x + magic_top_right.x, rect.origin.y}, {rect.origin.x + rect.size.width, - rect.origin.y + radii.topRight - magic_top_right}, - {rect.origin.x + rect.size.width, rect.origin.y + radii.topRight}); + rect.origin.y + radii.top_right.y - magic_top_right.y}, + {rect.origin.x + rect.size.width, rect.origin.y + radii.top_right.y}); //---------------------------------------------------------------------------- - /// Right line. - /// + // Right line. + // prototype_.AddLinearComponent( - {rect.origin.x + rect.size.width, rect.origin.y + radii.topRight}, + {rect.origin.x + rect.size.width, rect.origin.y + radii.top_right.y}, {rect.origin.x + rect.size.width, - rect.origin.y + rect.size.height - radii.bottomRight}); + rect.origin.y + rect.size.height - radii.bottom_right.y}); //---------------------------------------------------------------------------- - /// Bottom right arc. - /// + // Bottom right arc. + // prototype_.AddCubicComponent( {rect.origin.x + rect.size.width, - rect.origin.y + rect.size.height - radii.bottomRight}, + rect.origin.y + rect.size.height - radii.bottom_right.y}, {rect.origin.x + rect.size.width, rect.origin.y + rect.size.height - - radii.bottomRight + - magic_bottom_right}, - {rect.origin.x + rect.size.width - radii.bottomRight + magic_bottom_right, + radii.bottom_right.y + + magic_bottom_right.y}, + {rect.origin.x + rect.size.width - radii.bottom_right.x + + magic_bottom_right.x, rect.origin.y + rect.size.height}, - {rect.origin.x + rect.size.width - radii.bottomRight, + {rect.origin.x + rect.size.width - radii.bottom_right.x, rect.origin.y + rect.size.height}); //---------------------------------------------------------------------------- - /// Bottom line. - /// + // Bottom line. + // prototype_.AddLinearComponent( - {rect.origin.x + rect.size.width - radii.bottomRight, + {rect.origin.x + rect.size.width - radii.bottom_right.x, rect.origin.y + rect.size.height}, - {rect.origin.x + radii.bottomLeft, rect.origin.y + rect.size.height}); + {rect.origin.x + radii.bottom_left.x, rect.origin.y + rect.size.height}); //---------------------------------------------------------------------------- - /// Bottom left arc. - /// + // Bottom left arc. + // prototype_.AddCubicComponent( - {rect.origin.x + radii.bottomLeft, rect.origin.y + rect.size.height}, - {rect.origin.x + radii.bottomLeft - magic_bottom_left, + {rect.origin.x + radii.bottom_left.x, rect.origin.y + rect.size.height}, + {rect.origin.x + radii.bottom_left.x - magic_bottom_left.x, rect.origin.y + rect.size.height}, - {rect.origin.x, - rect.origin.y + rect.size.height - radii.bottomLeft + magic_bottom_left}, - {rect.origin.x, rect.origin.y + rect.size.height - radii.bottomLeft}); + {rect.origin.x, rect.origin.y + rect.size.height - radii.bottom_left.y + + magic_bottom_left.y}, + {rect.origin.x, rect.origin.y + rect.size.height - radii.bottom_left.y}); //---------------------------------------------------------------------------- - /// Left line. - /// + // Left line. + // prototype_.AddLinearComponent( - {rect.origin.x, rect.origin.y + rect.size.height - radii.bottomLeft}, - {rect.origin.x, rect.origin.y + radii.topLeft}); + {rect.origin.x, rect.origin.y + rect.size.height - radii.bottom_left.y}, + {rect.origin.x, rect.origin.y + radii.top_left.y}); //---------------------------------------------------------------------------- - /// Top left arc. - /// + // Top left arc. + // prototype_.AddCubicComponent( - {rect.origin.x, rect.origin.y + radii.topLeft}, - {rect.origin.x, rect.origin.y + radii.topLeft - magic_top_left}, - {rect.origin.x + radii.topLeft - magic_top_left, rect.origin.y}, - {rect.origin.x + radii.topLeft, rect.origin.y}); + {rect.origin.x, rect.origin.y + radii.top_left.y}, + {rect.origin.x, rect.origin.y + radii.top_left.y - magic_top_left.y}, + {rect.origin.x + radii.top_left.x - magic_top_left.x, rect.origin.y}, + {rect.origin.x + radii.top_left.x, rect.origin.y}); return *this; } @@ -260,8 +265,8 @@ PathBuilder& PathBuilder::AddOval(const Rect& container) { const Point m = {kArcApproximationMagic * r.x, kArcApproximationMagic * r.y}; //---------------------------------------------------------------------------- - /// Top right arc. - /// + // Top right arc. + // prototype_.AddCubicComponent({c.x, c.y - r.y}, // p1 {c.x + m.x, c.y - r.y}, // cp1 {c.x + r.x, c.y - m.y}, // cp2 @@ -269,8 +274,8 @@ PathBuilder& PathBuilder::AddOval(const Rect& container) { ); //---------------------------------------------------------------------------- - /// Bottom right arc. - /// + // Bottom right arc. + // prototype_.AddCubicComponent({c.x + r.x, c.y}, // p1 {c.x + r.x, c.y + m.y}, // cp1 {c.x + m.x, c.y + r.y}, // cp2 @@ -278,8 +283,8 @@ PathBuilder& PathBuilder::AddOval(const Rect& container) { ); //---------------------------------------------------------------------------- - /// Bottom left arc. - /// + // Bottom left arc. + // prototype_.AddCubicComponent({c.x, c.y + r.y}, // p1 {c.x - m.x, c.y + r.y}, // cp1 {c.x - r.x, c.y + m.y}, // cp2 @@ -287,8 +292,8 @@ PathBuilder& PathBuilder::AddOval(const Rect& container) { ); //---------------------------------------------------------------------------- - /// Top left arc. - /// + // Top left arc. + // prototype_.AddCubicComponent({c.x - r.x, c.y}, // p1 {c.x - r.x, c.y - m.y}, // cp1 {c.x - m.x, c.y - r.y}, // cp2 diff --git a/impeller/geometry/path_builder.h b/impeller/geometry/path_builder.h index 84057fa79d33c..13ebf6ab13068 100644 --- a/impeller/geometry/path_builder.h +++ b/impeller/geometry/path_builder.h @@ -48,8 +48,6 @@ class PathBuilder { PathBuilder& AddRect(Rect rect); - PathBuilder& AddRoundedRect(Rect rect, Scalar radius); - PathBuilder& AddCircle(const Point& center, Scalar radius); PathBuilder& AddOval(const Rect& rect); @@ -57,25 +55,34 @@ class PathBuilder { PathBuilder& AddLine(const Point& p1, const Point& p2); struct RoundingRadii { - Scalar topLeft = 0.0; - Scalar bottomLeft = 0.0; - Scalar topRight = 0.0; - Scalar bottomRight = 0.0; - - RoundingRadii() {} - - RoundingRadii(Scalar pTopLeft, - Scalar pBottomLeft, - Scalar pTopRight, - Scalar pBottomRight) - : topLeft(pTopLeft), - bottomLeft(pBottomLeft), - topRight(pTopRight), - bottomRight(pBottomRight) {} + Point top_left; + Point bottom_left; + Point top_right; + Point bottom_right; + + RoundingRadii() = default; + + RoundingRadii(Scalar p_top_left, + Scalar p_bottom_left, + Scalar p_top_right, + Scalar p_bottom_right) + : top_left(p_top_left, p_top_left), + bottom_left(p_bottom_left, p_bottom_left), + top_right(p_top_right, p_top_right), + bottom_right(p_bottom_right, p_bottom_right) {} + + bool AreAllZero() const { + return top_left.IsZero() && // + bottom_left.IsZero() && // + top_right.IsZero() && // + bottom_right.IsZero(); + } }; PathBuilder& AddRoundedRect(Rect rect, RoundingRadii radii); + PathBuilder& AddRoundedRect(Rect rect, Scalar radius); + private: Point subpath_start_; Point current_; diff --git a/impeller/geometry/point.h b/impeller/geometry/point.h index e84338796d5e2..0d497a70f934c 100644 --- a/impeller/geometry/point.h +++ b/impeller/geometry/point.h @@ -57,7 +57,7 @@ struct TPoint { return {x - s.width, y - s.height}; } - constexpr TPoint operator*(Type scale) const { + constexpr TPoint operator*(Scalar scale) const { return {x * scale, y * scale}; } @@ -69,7 +69,7 @@ struct TPoint { return {x * s.width, y * s.height}; } - constexpr TPoint operator/(Type d) const { return {x / d, y / d}; } + constexpr TPoint operator/(Scalar d) const { return {x / d, y / d}; } constexpr TPoint operator/(const TPoint& p) const { return {x / p.x, y / p.y}; @@ -108,6 +108,8 @@ struct TPoint { } return {x / length, y / length}; } + + constexpr bool IsZero() const { return x == 0 && y == 0; } }; using Point = TPoint;