Skip to content

Commit a686424

Browse files
authored
[Impeller] Use StrokePathSourceGeometry to stroke RoundSuperellipse (flutter#169704)
This PR creates a new class, `StrokeRoundSuperellipseGeometry`, which reuses the `StrokePathSourceGeometry` class to stroke rounded superellipses. Fixes flutter#168419. Filling is unchanged. I could have used `FillPathSourceGeometry` for non-uniform filling just like RRect, but I've decided not to after some experimentation, mostly because the `RoundSuperellipseGeometry` class wouldn't be simplified from uniformity as much as we hope for. This might be worthwhile if one day we move the filling code to `Tessellator` (just like `FilledRoundRect`), which reuses much existing code. But that's out of the scope for now. ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent b05da52 commit a686424

File tree

9 files changed

+111
-24
lines changed

9 files changed

+111
-24
lines changed

engine/src/flutter/display_list/geometry/dl_path_builder.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ DlPathBuilder& DlPathBuilder::AddRoundSuperellipse(
115115
BuilderReceiver receiver(*this);
116116
impeller::RoundSuperellipseParam::MakeBoundsRadii(rse.GetBounds(),
117117
rse.GetRadii())
118-
.AddToPath(receiver);
118+
.Dispatch(receiver);
119119
return *this;
120120
}
121121

engine/src/flutter/impeller/display_list/canvas.cc

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -758,29 +758,26 @@ void Canvas::DrawDiffRoundRect(const RoundRect& outer,
758758
}
759759
}
760760

761-
void Canvas::DrawRoundSuperellipse(const RoundSuperellipse& rse,
761+
void Canvas::DrawRoundSuperellipse(const RoundSuperellipse& round_superellipse,
762762
const Paint& paint) {
763-
auto& rect = rse.GetBounds();
764-
auto& radii = rse.GetRadii();
763+
auto& rect = round_superellipse.GetBounds();
764+
auto& radii = round_superellipse.GetRadii();
765765
if (radii.AreAllCornersSame() &&
766766
AttemptDrawBlurredRSuperellipse(rect, radii.top_left, paint)) {
767767
return;
768768
}
769769

770-
if (paint.style == Paint::Style::kFill) {
771-
Entity entity;
772-
entity.SetTransform(GetCurrentTransform());
773-
entity.SetBlendMode(paint.blend_mode);
770+
Entity entity;
771+
entity.SetTransform(GetCurrentTransform());
772+
entity.SetBlendMode(paint.blend_mode);
774773

774+
if (paint.style == Paint::Style::kFill) {
775775
RoundSuperellipseGeometry geom(rect, radii);
776776
AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
777-
return;
777+
} else {
778+
StrokeRoundSuperellipseGeometry geom(round_superellipse, paint.stroke);
779+
AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
778780
}
779-
780-
auto path = flutter::DlPathBuilder{} //
781-
.AddRoundSuperellipse(rse)
782-
.TakePath();
783-
DrawPath(flutter::DlPath(path), paint);
784781
}
785782

786783
void Canvas::DrawCircle(const Point& center,

engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "impeller/entity/geometry/fill_path_geometry.h"
99
#include "impeller/entity/geometry/geometry.h"
1010
#include "impeller/entity/geometry/stroke_path_geometry.h"
11+
#include "impeller/geometry/round_rect.h"
1112

1213
namespace impeller {
1314

engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,4 +462,14 @@ bool RoundSuperellipseGeometry::IsAxisAlignedRect() const {
462462
return false;
463463
}
464464

465+
StrokeRoundSuperellipseGeometry::StrokeRoundSuperellipseGeometry(
466+
const RoundSuperellipse& round_superellipse,
467+
const StrokeParameters& parameters)
468+
: StrokePathSourceGeometry(parameters),
469+
round_superellipse_source_(round_superellipse) {}
470+
471+
const PathSource& StrokeRoundSuperellipseGeometry::GetSource() const {
472+
return round_superellipse_source_;
473+
}
474+
465475
} // namespace impeller

engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.h

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,27 @@
66
#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_ROUND_SUPERELLIPSE_GEOMETRY_H_
77

88
#include "impeller/entity/geometry/geometry.h"
9+
#include "impeller/entity/geometry/stroke_path_geometry.h"
10+
#include "impeller/geometry/round_superellipse.h"
911
#include "impeller/geometry/rounding_radii.h"
1012

1113
namespace impeller {
12-
13-
/// Geometry class that can generate vertices for a rounded superellipse.
14+
/// @brief A Geometry class that generates fillable vertices (with or without
15+
/// texture coordinates) directly from a round superellipse object
16+
/// regardless of radii uniformity.
1417
///
1518
/// A rounded superellipse is a shape similar to a typical rounded rectangle
16-
/// (`RoundRect`), but with smoother transitions between the straight sides and
17-
/// the rounded corners. It resembles the `RoundedRectangle` shape in SwiftUI
18-
/// with the `.continuous` corner style. Technically, it is created by replacing
19-
/// the four corners of a superellipse (also known as a Lamé curve) with
20-
/// circular arcs.
19+
/// (`RoundSuperellipse`), but with smoother transitions between the straight
20+
/// sides and the rounded corners. It resembles the `RoundedRectangle` shape in
21+
/// SwiftUI with the `.continuous` corner style. Technically, it is created by
22+
/// replacing the four corners of a superellipse (also known as a Lamé curve)
23+
/// with circular arcs.
2124
///
2225
/// The `bounds` defines the position and size of the shape. The `corner_radius`
2326
/// corresponds to SwiftUI's `cornerRadius` parameter, which is close to, but
2427
/// not exactly equals to, the radius of the corner circles.
28+
///
29+
/// @see |StrokeRoundSuperellipseGeometry|
2530
class RoundSuperellipseGeometry final : public Geometry {
2631
public:
2732
RoundSuperellipseGeometry(const Rect& bounds, const RoundingRadii& radii);
@@ -53,6 +58,27 @@ class RoundSuperellipseGeometry final : public Geometry {
5358
delete;
5459
};
5560

61+
/// @brief A Geometry class that produces fillable vertices representing
62+
/// the stroked outline of any |RoundSuperellipse| object regardless of
63+
/// radii uniformity.
64+
///
65+
/// This class uses the |StrokePathSourceGeometry| base class to do the work
66+
/// by providing a |RoundSuperellipsePathSoure| iterator.
67+
///
68+
/// @see |RoundSuperellipseGeometry|
69+
class StrokeRoundSuperellipseGeometry final : public StrokePathSourceGeometry {
70+
public:
71+
StrokeRoundSuperellipseGeometry(const RoundSuperellipse& round_superellipse,
72+
const StrokeParameters& parameters);
73+
74+
protected:
75+
// |StrokePathSourceGeometry|
76+
const PathSource& GetSource() const override;
77+
78+
private:
79+
const RoundSuperellipsePathSource round_superellipse_source_;
80+
};
81+
5682
} // namespace impeller
5783

5884
#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_ROUND_SUPERELLIPSE_GEOMETRY_H_

engine/src/flutter/impeller/geometry/round_superellipse.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,29 @@ RoundRect RoundSuperellipse::ToApproximateRoundRect() const {
3838
return RoundRect::MakeRectRadii(GetBounds(), GetRadii());
3939
}
4040

41+
RoundSuperellipsePathSource::RoundSuperellipsePathSource(
42+
const RoundSuperellipse& round_superellipse)
43+
: round_superellipse_(round_superellipse) {}
44+
45+
RoundSuperellipsePathSource::~RoundSuperellipsePathSource() = default;
46+
47+
FillType RoundSuperellipsePathSource::GetFillType() const {
48+
return FillType::kNonZero;
49+
}
50+
51+
Rect RoundSuperellipsePathSource::GetBounds() const {
52+
return round_superellipse_.GetBounds();
53+
}
54+
55+
bool RoundSuperellipsePathSource::IsConvex() const {
56+
return true;
57+
}
58+
59+
void RoundSuperellipsePathSource::Dispatch(PathReceiver& receiver) const {
60+
auto param = RoundSuperellipseParam::MakeBoundsRadii(
61+
round_superellipse_.GetBounds(), round_superellipse_.GetRadii());
62+
param.Dispatch(receiver);
63+
receiver.PathEnd();
64+
}
65+
4166
} // namespace impeller

engine/src/flutter/impeller/geometry/round_superellipse.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_
66
#define FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_
77

8+
#include "flutter/impeller/geometry/path_source.h"
89
#include "flutter/impeller/geometry/point.h"
910
#include "flutter/impeller/geometry/rect.h"
1011
#include "flutter/impeller/geometry/rounding_radii.h"
@@ -142,6 +143,33 @@ struct RoundSuperellipse {
142143
RoundingRadii radii_;
143144
};
144145

146+
class RoundSuperellipsePathSource : public PathSource {
147+
public:
148+
explicit RoundSuperellipsePathSource(
149+
const RoundSuperellipse& round_superellipse);
150+
151+
~RoundSuperellipsePathSource();
152+
153+
const RoundSuperellipse& GetRoundSuperellipse() const {
154+
return round_superellipse_;
155+
}
156+
157+
// |PathSource|
158+
FillType GetFillType() const override;
159+
160+
// |PathSource|
161+
Rect GetBounds() const override;
162+
163+
// |PathSource|
164+
bool IsConvex() const override;
165+
166+
// |PathSource|
167+
void Dispatch(PathReceiver& receiver) const override;
168+
169+
private:
170+
const RoundSuperellipse round_superellipse_;
171+
};
172+
145173
} // namespace impeller
146174

147175
namespace std {

engine/src/flutter/impeller/geometry/round_superellipse_param.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ RoundSuperellipseParam RoundSuperellipseParam::MakeBoundsRadii(
519519
};
520520
}
521521

522-
void RoundSuperellipseParam::AddToPath(PathReceiver& path_receiver) const {
522+
void RoundSuperellipseParam::Dispatch(PathReceiver& path_receiver) const {
523523
RoundSuperellipseBuilder builder(path_receiver);
524524

525525
Point start = top_right.offset +

engine/src/flutter/impeller/geometry/round_superellipse_param.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ struct RoundSuperellipseParam {
110110
// with the bounds, which is recommended for callers.
111111
bool Contains(const Point& point) const;
112112

113-
// Add a path of this rounded superellipse to the provided path builder.
114-
void AddToPath(PathReceiver& path) const;
113+
// Dispatch the path operations of this rounded superellipse to the receiver.
114+
void Dispatch(PathReceiver& receiver) const;
115115

116116
// A factor used to calculate the "gap", defined as the distance from the
117117
// midpoint of the curved corners to the nearest sides of the bounding box.

0 commit comments

Comments
 (0)