diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 36f280bd78ea5..9cdd9dc593393 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -43199,6 +43199,8 @@ ORIGIN: ../../../flutter/impeller/geometry/rect.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/geometry/rect.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/geometry/round_rect.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/geometry/round_rect.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/geometry/round_superellipse.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/geometry/round_superellipse.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/geometry/saturated_math.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/geometry/scalar.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/geometry/separated_vector.cc + ../../../flutter/LICENSE @@ -46134,6 +46136,8 @@ FILE: ../../../flutter/impeller/geometry/rect.cc FILE: ../../../flutter/impeller/geometry/rect.h FILE: ../../../flutter/impeller/geometry/round_rect.cc FILE: ../../../flutter/impeller/geometry/round_rect.h +FILE: ../../../flutter/impeller/geometry/round_superellipse.cc +FILE: ../../../flutter/impeller/geometry/round_superellipse.h FILE: ../../../flutter/impeller/geometry/saturated_math.h FILE: ../../../flutter/impeller/geometry/scalar.h FILE: ../../../flutter/impeller/geometry/separated_vector.cc diff --git a/display_list/benchmarking/dl_complexity_gl.cc b/display_list/benchmarking/dl_complexity_gl.cc index 438a31af7d092..62999c4510c05 100644 --- a/display_list/benchmarking/dl_complexity_gl.cc +++ b/display_list/benchmarking/dl_complexity_gl.cc @@ -335,6 +335,11 @@ void DisplayListGLComplexityCalculator::GLHelper::drawDiffRoundRect( AccumulateComplexity(complexity); } +void DisplayListGLComplexityCalculator::GLHelper::drawRoundSuperellipse( + const DlRoundSuperellipse& rse) { + // TODO(dkwingsmt): implement +} + void DisplayListGLComplexityCalculator::GLHelper::drawPath(const DlPath& path) { if (IsComplex()) { return; diff --git a/display_list/benchmarking/dl_complexity_gl.h b/display_list/benchmarking/dl_complexity_gl.h index d9e7891de5007..798429e718be3 100644 --- a/display_list/benchmarking/dl_complexity_gl.h +++ b/display_list/benchmarking/dl_complexity_gl.h @@ -51,6 +51,7 @@ class DisplayListGLComplexityCalculator void drawRoundRect(const DlRoundRect& rrect) override; void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override; + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override; void drawPath(const DlPath& path) override; void drawArc(const DlRect& oval_bounds, DlScalar start_degrees, diff --git a/display_list/benchmarking/dl_complexity_metal.cc b/display_list/benchmarking/dl_complexity_metal.cc index eaa1bb99ea5b4..d71af43069dde 100644 --- a/display_list/benchmarking/dl_complexity_metal.cc +++ b/display_list/benchmarking/dl_complexity_metal.cc @@ -329,6 +329,11 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawDiffRoundRect( AccumulateComplexity(complexity); } +void DisplayListMetalComplexityCalculator::MetalHelper::drawRoundSuperellipse( + const DlRoundSuperellipse& rse) { + // TODO(dkwingsmt): implement +} + void DisplayListMetalComplexityCalculator::MetalHelper::drawPath( const DlPath& path) { if (IsComplex()) { diff --git a/display_list/benchmarking/dl_complexity_metal.h b/display_list/benchmarking/dl_complexity_metal.h index 4ecf3957832f3..8ad423a3494d5 100644 --- a/display_list/benchmarking/dl_complexity_metal.h +++ b/display_list/benchmarking/dl_complexity_metal.h @@ -51,6 +51,7 @@ class DisplayListMetalComplexityCalculator void drawRoundRect(const DlRoundRect& rrect) override; void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override; + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override; void drawPath(const DlPath& path) override; void drawArc(const DlRect& oval_bounds, DlScalar start_degrees, diff --git a/display_list/display_list.cc b/display_list/display_list.cc index fc823dee83209..7c0e638053406 100644 --- a/display_list/display_list.cc +++ b/display_list/display_list.cc @@ -317,6 +317,7 @@ DisplayListOpCategory DisplayList::GetOpCategory(DisplayListOpType type) { case DisplayListOpType::kDrawCircle: case DisplayListOpType::kDrawRoundRect: case DisplayListOpType::kDrawDiffRoundRect: + case DisplayListOpType::kDrawRoundSuperellipse: case DisplayListOpType::kDrawArc: case DisplayListOpType::kDrawPath: case DisplayListOpType::kDrawPoints: diff --git a/display_list/display_list.h b/display_list/display_list.h index 0c13a437df60e..a5d40eeb0bbe2 100644 --- a/display_list/display_list.h +++ b/display_list/display_list.h @@ -113,6 +113,7 @@ namespace flutter { V(DrawCircle) \ V(DrawRoundRect) \ V(DrawDiffRoundRect) \ + V(DrawRoundSuperellipse) \ V(DrawArc) \ V(DrawPath) \ \ diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index 682e8823c5607..956667bf3b020 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -1225,6 +1225,27 @@ void DisplayListBuilder::DrawDiffRoundRect(const DlRoundRect& outer, SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawDRRectFlags); drawDiffRoundRect(outer, inner); } +void DisplayListBuilder::DrawRoundSuperellipse(const DlRoundSuperellipse& rse, + const DlPaint& paint) { + SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawRSuperellipseFlags); + drawRoundSuperellipse(rse); +} +void DisplayListBuilder::drawRoundSuperellipse(const DlRoundSuperellipse& rse) { + if (rse.IsRect()) { + drawRect(rse.GetBounds()); + } else if (rse.IsCircle()) { + drawOval(rse.GetBounds()); + } else { + DisplayListAttributeFlags flags = kDrawRSuperellipseFlags; + OpResult result = PaintResult(current_, flags); + if (result != OpResult::kNoEffect && + AccumulateOpBounds(ToSkRect(rse.GetBounds()), flags)) { + Push(0, rse); + CheckLayerOpacityCompatibility(); + UpdateLayerResult(result); + } + } +} void DisplayListBuilder::drawPath(const DlPath& path) { DisplayListAttributeFlags flags = kDrawPathFlags; OpResult result = PaintResult(current_, flags); diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index 92dc9b83246c0..b87f78936709a 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -172,6 +172,9 @@ class DisplayListBuilder final : public virtual DlCanvas, const DlRoundRect& inner, const DlPaint& paint) override; // |DlCanvas| + void DrawRoundSuperellipse(const DlRoundSuperellipse& rse, + const DlPaint& paint) override; + // |DlCanvas| void DrawPath(const DlPath& path, const DlPaint& paint) override; // |DlCanvas| void DrawArc(const DlRect& bounds, @@ -438,6 +441,8 @@ class DisplayListBuilder final : public virtual DlCanvas, void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override; // |DlOpReceiver| + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override; + // |DlOpReceiver| void drawPath(const DlPath& path) override; // |DlOpReceiver| void drawArc(const DlRect& bounds, diff --git a/display_list/dl_canvas.h b/display_list/dl_canvas.h index c2ae784ff5f59..438d7b5573a78 100644 --- a/display_list/dl_canvas.h +++ b/display_list/dl_canvas.h @@ -141,6 +141,8 @@ class DlCanvas { virtual void DrawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner, const DlPaint& paint) = 0; + virtual void DrawRoundSuperellipse(const DlRoundSuperellipse& rse, + const DlPaint& paint) = 0; virtual void DrawPath(const DlPath& path, const DlPaint& paint) = 0; virtual void DrawArc(const DlRect& bounds, DlScalar start, diff --git a/display_list/dl_op_flags.h b/display_list/dl_op_flags.h index f5d4cfb5c0064..4cdf089af9486 100644 --- a/display_list/dl_op_flags.h +++ b/display_list/dl_op_flags.h @@ -323,6 +323,10 @@ class DisplayListOpFlags : DisplayListFlags { kBasePaintFlags | // kBaseStrokeOrFillFlags // }; + static constexpr DisplayListAttributeFlags kDrawRSuperellipseFlags{ + kBasePaintFlags | // + kBaseStrokeOrFillFlags // + }; static constexpr DisplayListAttributeFlags kDrawPathFlags{ kBasePaintFlags | // kBaseStrokeOrFillFlags | // diff --git a/display_list/dl_op_receiver.h b/display_list/dl_op_receiver.h index 081c44b5444f8..5e000b947428f 100644 --- a/display_list/dl_op_receiver.h +++ b/display_list/dl_op_receiver.h @@ -318,6 +318,7 @@ class DlOpReceiver { virtual void drawRoundRect(const DlRoundRect& rrect) = 0; virtual void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) = 0; + virtual void drawRoundSuperellipse(const DlRoundSuperellipse& rse) = 0; virtual void drawPath(const DlPath& path) = 0; virtual void drawArc(const DlRect& oval_bounds, DlScalar start_degrees, diff --git a/display_list/dl_op_records.h b/display_list/dl_op_records.h index 1df10f933f3c0..983bcbb2245d0 100644 --- a/display_list/dl_op_records.h +++ b/display_list/dl_op_records.h @@ -579,6 +579,7 @@ struct DrawColorOp final : DrawOpBase { // SkOval is same as DlRect // DlRoundRect is 48 more bytes, using 52 bytes which rounds up to 56 bytes // total (4 bytes unused) +// TODO(dkwingsmt): Evaluate DlRoundSuperellipse here #define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name) \ struct Draw##op_name##Op final : DrawOpBase { \ static constexpr auto kType = DisplayListOpType::kDraw##op_name; \ @@ -595,6 +596,7 @@ struct DrawColorOp final : DrawOpBase { DEFINE_DRAW_1ARG_OP(Rect, DlRect, rect) DEFINE_DRAW_1ARG_OP(Oval, DlRect, oval) DEFINE_DRAW_1ARG_OP(RoundRect, DlRoundRect, rrect) +DEFINE_DRAW_1ARG_OP(RoundSuperellipse, DlRoundSuperellipse, rse) #undef DEFINE_DRAW_1ARG_OP // 4 byte header + 16 byte payload uses 20 bytes but is rounded diff --git a/display_list/geometry/dl_geometry_types.h b/display_list/geometry/dl_geometry_types.h index 6ee6c38385c36..c819669647ae4 100644 --- a/display_list/geometry/dl_geometry_types.h +++ b/display_list/geometry/dl_geometry_types.h @@ -8,6 +8,7 @@ #include "flutter/impeller/geometry/matrix.h" #include "flutter/impeller/geometry/rect.h" #include "flutter/impeller/geometry/round_rect.h" +#include "flutter/impeller/geometry/round_superellipse.h" #include "flutter/impeller/geometry/scalar.h" #include "flutter/third_party/skia/include/core/SkM44.h" @@ -30,6 +31,7 @@ using DlISize = impeller::ISize32; using DlRect = impeller::Rect; using DlIRect = impeller::IRect32; using DlRoundRect = impeller::RoundRect; +using DlRoundSuperellipse = impeller::RoundSuperellipse; using DlMatrix = impeller::Matrix; using DlQuad = impeller::Quad; diff --git a/display_list/skia/dl_sk_canvas.cc b/display_list/skia/dl_sk_canvas.cc index 6d66c466745e6..c737048fa6ce9 100644 --- a/display_list/skia/dl_sk_canvas.cc +++ b/display_list/skia/dl_sk_canvas.cc @@ -235,6 +235,15 @@ void DlSkCanvasAdapter::DrawDiffRoundRect(const DlRoundRect& outer, delegate_->drawDRRect(ToSkRRect(outer), ToSkRRect(inner), ToSk(paint)); } +void DlSkCanvasAdapter::DrawRoundSuperellipse(const DlRoundSuperellipse& rse, + const DlPaint& paint) { + // Skia doesn't support round superellipse, thus fallback to round rectangle. + // TODO(dkwingsmt): Figure out the corner radius mapping. + delegate_->drawRRect(ToSkRRect(DlRoundRect::MakeRectRadius( + rse.GetBounds(), rse.GetCornerRadius())), + ToSk(paint)); +} + void DlSkCanvasAdapter::DrawPath(const DlPath& path, const DlPaint& paint) { path.WillRenderSkPath(); delegate_->drawPath(path.GetSkPath(), ToSk(paint)); diff --git a/display_list/skia/dl_sk_canvas.h b/display_list/skia/dl_sk_canvas.h index 3a42c3a61f2e5..1a07433e1b523 100644 --- a/display_list/skia/dl_sk_canvas.h +++ b/display_list/skia/dl_sk_canvas.h @@ -104,6 +104,8 @@ class DlSkCanvasAdapter final : public virtual DlCanvas { void DrawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner, const DlPaint& paint) override; + void DrawRoundSuperellipse(const DlRoundSuperellipse& rse, + const DlPaint& paint) override; void DrawPath(const DlPath& path, const DlPaint& paint) override; void DrawArc(const DlRect& bounds, DlScalar start, diff --git a/display_list/skia/dl_sk_dispatcher.cc b/display_list/skia/dl_sk_dispatcher.cc index 0f9ffda98879a..f9fd580cce93c 100644 --- a/display_list/skia/dl_sk_dispatcher.cc +++ b/display_list/skia/dl_sk_dispatcher.cc @@ -192,6 +192,14 @@ void DlSkCanvasDispatcher::drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) { canvas_->drawDRRect(ToSkRRect(outer), ToSkRRect(inner), paint()); } +void DlSkCanvasDispatcher::drawRoundSuperellipse( + const DlRoundSuperellipse& rse) { + // Skia doesn't support round superellipse, thus fallback to round rectangle. + // TODO(dkwingsmt): Figure out the corner radius mapping. + canvas_->drawRRect(ToSkRRect(DlRoundRect::MakeRectRadius( + rse.GetBounds(), rse.GetCornerRadius())), + paint()); +} void DlSkCanvasDispatcher::drawPath(const DlPath& path) { path.WillRenderSkPath(); canvas_->drawPath(path.GetSkPath(), paint()); diff --git a/display_list/skia/dl_sk_dispatcher.h b/display_list/skia/dl_sk_dispatcher.h index 659506b6bff21..3f4d0f3f36dca 100644 --- a/display_list/skia/dl_sk_dispatcher.h +++ b/display_list/skia/dl_sk_dispatcher.h @@ -71,6 +71,7 @@ class DlSkCanvasDispatcher : public virtual DlOpReceiver, void drawRoundRect(const DlRoundRect& rrect) override; void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override; + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override; void drawPath(const DlPath& path) override; void drawArc(const DlRect& bounds, DlScalar start, diff --git a/display_list/utils/dl_receiver_utils.h b/display_list/utils/dl_receiver_utils.h index 40a7df5de4652..f37c243eea96f 100644 --- a/display_list/utils/dl_receiver_utils.h +++ b/display_list/utils/dl_receiver_utils.h @@ -98,6 +98,7 @@ class IgnoreDrawDispatchHelper : public virtual DlOpReceiver { void drawRoundRect(const DlRoundRect& rrect) override {} void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override {} + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override {} void drawPath(const DlPath& path) override {} void drawArc(const DlRect& oval_bounds, DlScalar start_degrees, diff --git a/impeller/display_list/canvas.cc b/impeller/display_list/canvas.cc index e5ebe4a409210..cfbbbf68563aa 100644 --- a/impeller/display_list/canvas.cc +++ b/impeller/display_list/canvas.cc @@ -533,6 +533,30 @@ void Canvas::DrawRoundRect(const RoundRect& round_rect, const Paint& paint) { DrawPath(path, paint); } +void Canvas::DrawRoundSuperellipse(const RoundSuperellipse& rse, + const Paint& paint) { + auto& rect = rse.GetBounds(); + Scalar corner_radius = rse.GetCornerRadius(); + + if (paint.style == Paint::Style::kStroke) { + // TODO(dkwingsmt): Add path + // DrawPath(PathBuilder{}.AddRect(rect).TakePath(), paint); + return; + } + + // TODO(dkwingsmt): Add blurred rrect approximation + // if (AttemptDrawBlurredRRect(rect, {}, paint)) { + // return; + // } + + Entity entity; + entity.SetTransform(GetCurrentTransform()); + entity.SetBlendMode(paint.blend_mode); + + RoundSuperellipseGeometry geom(rect, corner_radius); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); +} + void Canvas::DrawCircle(const Point& center, Scalar radius, const Paint& paint) { diff --git a/impeller/display_list/canvas.h b/impeller/display_list/canvas.h index d92c6d79a86e3..b7a9e3a9e4aed 100644 --- a/impeller/display_list/canvas.h +++ b/impeller/display_list/canvas.h @@ -198,6 +198,8 @@ class Canvas { void DrawRoundRect(const RoundRect& rect, const Paint& paint); + void DrawRoundSuperellipse(const RoundSuperellipse& rse, const Paint& paint); + void DrawCircle(const Point& center, Scalar radius, const Paint& paint); void DrawPoints(const Point points[], diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 3fb650d36a29d..57295240fb529 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -601,6 +601,13 @@ void DlDispatcherBase::drawDiffRoundRect(const DlRoundRect& outer, GetCanvas().DrawPath(builder.TakePath(FillType::kOdd), paint_); } +// |flutter::DlOpReceiver| +void DlDispatcherBase::drawRoundSuperellipse(const DlRoundSuperellipse& rse) { + AUTO_DEPTH_WATCHER(1u); + + GetCanvas().DrawRoundSuperellipse(rse, paint_); +} + // |flutter::DlOpReceiver| void DlDispatcherBase::drawPath(const DlPath& path) { AUTO_DEPTH_WATCHER(1u); diff --git a/impeller/display_list/dl_dispatcher.h b/impeller/display_list/dl_dispatcher.h index ba43f1c15c9d8..9fea3af892448 100644 --- a/impeller/display_list/dl_dispatcher.h +++ b/impeller/display_list/dl_dispatcher.h @@ -25,6 +25,7 @@ using DlPoint = flutter::DlPoint; using DlRect = flutter::DlRect; using DlIRect = flutter::DlIRect; using DlRoundRect = flutter::DlRoundRect; +using DlRoundSuperellipse = flutter::DlRoundSuperellipse; using DlPath = flutter::DlPath; class DlDispatcherBase : public flutter::DlOpReceiver { @@ -168,6 +169,9 @@ class DlDispatcherBase : public flutter::DlOpReceiver { void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override; + // |flutter::DlOpReceiver| + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override; + // |flutter::DlOpReceiver| void drawPath(const DlPath& path) override; diff --git a/impeller/entity/geometry/geometry.cc b/impeller/entity/geometry/geometry.cc index 0f3185fce940e..b259f1820bea8 100644 --- a/impeller/entity/geometry/geometry.cc +++ b/impeller/entity/geometry/geometry.cc @@ -15,6 +15,7 @@ #include "impeller/entity/geometry/line_geometry.h" #include "impeller/entity/geometry/rect_geometry.h" #include "impeller/entity/geometry/round_rect_geometry.h" +#include "impeller/entity/geometry/round_superellipse_geometry.h" #include "impeller/entity/geometry/stroke_path_geometry.h" #include "impeller/geometry/rect.h" @@ -110,6 +111,12 @@ std::unique_ptr Geometry::MakeRoundRect(const Rect& rect, return std::make_unique(rect, radii); } +std::unique_ptr Geometry::MakeRoundSuperellipse( + const Rect& rect, + Scalar corner_radius) { + return std::make_unique(rect, corner_radius); +} + bool Geometry::CoversArea(const Matrix& transform, const Rect& rect) const { return false; } diff --git a/impeller/entity/geometry/geometry.h b/impeller/entity/geometry/geometry.h index d5c504d79e844..257c44d3aeb1d 100644 --- a/impeller/entity/geometry/geometry.h +++ b/impeller/entity/geometry/geometry.h @@ -83,6 +83,9 @@ class Geometry { static std::unique_ptr MakeRoundRect(const Rect& rect, const Size& radii); + static std::unique_ptr MakeRoundSuperellipse(const Rect& rect, + Scalar corner_radius); + virtual GeometryResult GetPositionBuffer(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const = 0; diff --git a/impeller/geometry/BUILD.gn b/impeller/geometry/BUILD.gn index 5c1d71f4e0005..935f26657776e 100644 --- a/impeller/geometry/BUILD.gn +++ b/impeller/geometry/BUILD.gn @@ -31,6 +31,8 @@ impeller_component("geometry") { "rect.h", "round_rect.cc", "round_rect.h", + "round_superellipse.cc", + "round_superellipse.h", "saturated_math.h", "scalar.h", "separated_vector.cc", diff --git a/impeller/geometry/round_superellipse.cc b/impeller/geometry/round_superellipse.cc new file mode 100644 index 0000000000000..10e48c73fa874 --- /dev/null +++ b/impeller/geometry/round_superellipse.cc @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/impeller/geometry/round_superellipse.h" + +#include + +namespace impeller { + +RoundSuperellipse RoundSuperellipse::MakeRectRadius(const Rect& rect, + Scalar corner_radius) { + if (rect.IsEmpty() || !rect.IsFinite() || // + !std::isfinite(corner_radius)) { + // preserve the empty bounds as they might be strokable + return RoundSuperellipse(rect, 0); + } + + return RoundSuperellipse(rect, corner_radius); +} + +} // namespace impeller diff --git a/impeller/geometry/round_superellipse.h b/impeller/geometry/round_superellipse.h new file mode 100644 index 0000000000000..93f6fa7de8015 --- /dev/null +++ b/impeller/geometry/round_superellipse.h @@ -0,0 +1,78 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ +#define FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ + +#include "flutter/impeller/geometry/point.h" +#include "flutter/impeller/geometry/rect.h" +#include "flutter/impeller/geometry/size.h" + +namespace impeller { + +struct RoundSuperellipse { + RoundSuperellipse() = default; + + static RoundSuperellipse MakeRectRadius(const Rect& rect, + Scalar corner_radius); + + constexpr const Rect& GetBounds() const { return bounds_; } + constexpr float GetCornerRadius() const { return corner_radius_; } + + [[nodiscard]] constexpr bool IsFinite() const { + return bounds_.IsFinite() && std::isfinite(corner_radius_); + } + + [[nodiscard]] constexpr bool IsEmpty() const { return bounds_.IsEmpty(); } + + [[nodiscard]] constexpr bool IsRect() const { + return !bounds_.IsEmpty() && ScalarNearlyEqual(corner_radius_, 0); + } + + [[nodiscard]] constexpr bool IsCircle() const { + return !bounds_.IsEmpty() && + ScalarNearlyEqual(corner_radius_, bounds_.GetWidth() * 0.5f) && + ScalarNearlyEqual(corner_radius_, bounds_.GetHeight() * 0.5f); + } + + /// @brief Returns a new round rectangle translated by the given offset. + [[nodiscard]] constexpr RoundSuperellipse Shift(Scalar dx, Scalar dy) const { + // Just in case, use the factory rather than the internal constructor + // as shifting the rectangle may increase/decrease its bit precision + // so we should re-validate the radii to the newly located rectangle. + return MakeRectRadius(bounds_.Shift(dx, dy), corner_radius_); + } + + [[nodiscard]] constexpr bool operator==(const RoundSuperellipse& rr) const { + return bounds_ == rr.bounds_ && corner_radius_ == rr.corner_radius_; + } + + [[nodiscard]] constexpr bool operator!=(const RoundSuperellipse& r) const { + return !(*this == r); + } + + private: + constexpr RoundSuperellipse(const Rect& bounds, float corner_radius) + : bounds_(bounds), corner_radius_(corner_radius) {} + + const Rect bounds_; + const float corner_radius_ = 0; +}; + +} // namespace impeller + +namespace std { + +inline std::ostream& operator<<(std::ostream& out, + const impeller::RoundSuperellipse& rr) { + out << "(" // + << "rect: " << rr.GetBounds() << ", " // + << "corner_radius: " << rr.GetCornerRadius() // + << ")"; + return out; +} + +} // namespace std + +#endif // FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ diff --git a/shell/common/dl_op_spy.cc b/shell/common/dl_op_spy.cc index f9671ccab4a73..bd34001d0b2f4 100644 --- a/shell/common/dl_op_spy.cc +++ b/shell/common/dl_op_spy.cc @@ -65,6 +65,9 @@ void DlOpSpy::drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) { did_draw_ |= will_draw_; } +void DlOpSpy::drawRoundSuperellipse(const DlRoundSuperellipse& rse) { + did_draw_ |= will_draw_; +} void DlOpSpy::drawPath(const DlPath& path) { did_draw_ |= will_draw_; } diff --git a/shell/common/dl_op_spy.h b/shell/common/dl_op_spy.h index 27fe39554f3b5..d598cfe22514e 100644 --- a/shell/common/dl_op_spy.h +++ b/shell/common/dl_op_spy.h @@ -57,6 +57,7 @@ class DlOpSpy final : public virtual DlOpReceiver, void drawRoundRect(const DlRoundRect& rrect) override; void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override; + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override; void drawPath(const DlPath& path) override; void drawArc(const DlRect& oval_bounds, DlScalar start_degrees, diff --git a/testing/display_list_testing.cc b/testing/display_list_testing.cc index b3c6fe65ba34e..5d21ee83ce594 100644 --- a/testing/display_list_testing.cc +++ b/testing/display_list_testing.cc @@ -847,6 +847,9 @@ void DisplayListStreamDispatcher::drawDiffRoundRect(const DlRoundRect& outer, startl() << "drawDRRect(outer: " << outer << ", " << std::endl; startl() << " inner: " << inner << ");" << std::endl; } +void DisplayListStreamDispatcher::drawRoundSuperellipse(const DlRoundSuperellipse& rse) { + startl() << "drawRSuperellipse(" << rse << ");" << std::endl; +} void DisplayListStreamDispatcher::drawPath(const DlPath& path) { startl() << "drawPath(" << path << ");" << std::endl; } diff --git a/testing/display_list_testing.h b/testing/display_list_testing.h index 17cf01d0239ea..10381029f51aa 100644 --- a/testing/display_list_testing.h +++ b/testing/display_list_testing.h @@ -151,6 +151,7 @@ class DisplayListStreamDispatcher final : public DlOpReceiver { void drawRoundRect(const DlRoundRect& rrect) override; void drawDiffRoundRect(const DlRoundRect& outer, const DlRoundRect& inner) override; + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override; void drawPath(const DlPath& path) override; void drawArc(const DlRect& oval_bounds, DlScalar start_degrees, @@ -442,6 +443,9 @@ class DisplayListGeneralReceiver : public DlOpReceiver { const DlRoundRect& inner) override { RecordByType(DisplayListOpType::kDrawDiffRoundRect); } + void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override { + RecordByType(DisplayListOpType::kDrawRoundSuperellipse); + } void drawPath(const DlPath& path) override { RecordByType(DisplayListOpType::kDrawPath); }