Skip to content

Commit

Permalink
[Engine] Add RoundSuperellipse to drawing OP (#160883)
Browse files Browse the repository at this point in the history
This PR adds support for clipping round superellipse to the engine.

For what a rounded superellipse is, see [this design
doc](https://docs.google.com/document/d/1CJXULKJGQt22FOFsrlm2TKVjKBtif1yU4U50cMfL6Kc/edit?tab=t.0).
Video demos can be found at flutter/engine#56726
and flutter/flutter#161409.

Only impeller can actually render it. On Skia and Web, this shape falls
back to `RRect`.

Part of flutter/flutter#139321 and
flutter/flutter#13914, also related to
flutter/flutter#91523.

## 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
  • Loading branch information
dkwingsmt authored Feb 21, 2025
1 parent 7d23780 commit 5b7a3c8
Show file tree
Hide file tree
Showing 77 changed files with 3,001 additions and 660 deletions.
1 change: 1 addition & 0 deletions engine/src/flutter/ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
../../../flutter/flow/layers/clip_path_layer_unittests.cc
../../../flutter/flow/layers/clip_rect_layer_unittests.cc
../../../flutter/flow/layers/clip_rrect_layer_unittests.cc
../../../flutter/flow/layers/clip_rsuperellipse_layer_unittests.cc
../../../flutter/flow/layers/color_filter_layer_unittests.cc
../../../flutter/flow/layers/container_layer_unittests.cc
../../../flutter/flow/layers/display_list_layer_unittests.cc
Expand Down
8 changes: 8 additions & 0 deletions engine/src/flutter/ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -41379,6 +41379,8 @@ ORIGIN: ../../../flutter/flow/layers/clip_rect_layer.cc + ../../../flutter/LICEN
ORIGIN: ../../../flutter/flow/layers/clip_rect_layer.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/layers/clip_rrect_layer.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/layers/clip_rrect_layer.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/layers/clip_rsuperellipse_layer.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/layers/clip_rsuperellipse_layer.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/layers/clip_shape_layer.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/layers/color_filter_layer.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/flow/layers/color_filter_layer.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -42490,6 +42492,8 @@ ORIGIN: ../../../flutter/lib/ui/painting/picture_recorder.cc + ../../../flutter/
ORIGIN: ../../../flutter/lib/ui/painting/picture_recorder.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/painting/rrect.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/painting/rrect.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/painting/rsuperellipse.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/painting/rsuperellipse.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/painting/shader.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/painting/shader.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/ui/painting/single_frame_codec.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -44342,6 +44346,8 @@ FILE: ../../../flutter/flow/layers/clip_rect_layer.cc
FILE: ../../../flutter/flow/layers/clip_rect_layer.h
FILE: ../../../flutter/flow/layers/clip_rrect_layer.cc
FILE: ../../../flutter/flow/layers/clip_rrect_layer.h
FILE: ../../../flutter/flow/layers/clip_rsuperellipse_layer.cc
FILE: ../../../flutter/flow/layers/clip_rsuperellipse_layer.h
FILE: ../../../flutter/flow/layers/clip_shape_layer.h
FILE: ../../../flutter/flow/layers/color_filter_layer.cc
FILE: ../../../flutter/flow/layers/color_filter_layer.h
Expand Down Expand Up @@ -45457,6 +45463,8 @@ FILE: ../../../flutter/lib/ui/painting/picture_recorder.cc
FILE: ../../../flutter/lib/ui/painting/picture_recorder.h
FILE: ../../../flutter/lib/ui/painting/rrect.cc
FILE: ../../../flutter/lib/ui/painting/rrect.h
FILE: ../../../flutter/lib/ui/painting/rsuperellipse.cc
FILE: ../../../flutter/lib/ui/painting/rsuperellipse.h
FILE: ../../../flutter/lib/ui/painting/shader.cc
FILE: ../../../flutter/lib/ui/painting/shader.h
FILE: ../../../flutter/lib/ui/painting/single_frame_codec.cc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,12 @@ void DisplayListGLComplexityCalculator::GLHelper::drawDiffRoundRect(
AccumulateComplexity(complexity);
}

void DisplayListGLComplexityCalculator::GLHelper::drawRoundSuperellipse(
const DlRoundSuperellipse& rse) {
// Drawing RSEs on Skia falls back to RRect.
drawRoundRect(rse.ToApproximateRoundRect());
}

void DisplayListGLComplexityCalculator::GLHelper::drawPath(const DlPath& path) {
if (IsComplex()) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,12 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawDiffRoundRect(
AccumulateComplexity(complexity);
}

void DisplayListMetalComplexityCalculator::MetalHelper::drawRoundSuperellipse(
const DlRoundSuperellipse& rse) {
// Drawing RSEs on Skia falls back to RRect.
drawRoundRect(rse.ToApproximateRoundRect());
}

void DisplayListMetalComplexityCalculator::MetalHelper::drawPath(
const DlPath& path) {
if (IsComplex()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions engine/src/flutter/display_list/display_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,12 @@ DisplayListOpCategory DisplayList::GetOpCategory(DisplayListOpType type) {
case DisplayListOpType::kClipIntersectRect:
case DisplayListOpType::kClipIntersectOval:
case DisplayListOpType::kClipIntersectRoundRect:
case DisplayListOpType::kClipIntersectRoundSuperellipse:
case DisplayListOpType::kClipIntersectPath:
case DisplayListOpType::kClipDifferenceRect:
case DisplayListOpType::kClipDifferenceOval:
case DisplayListOpType::kClipDifferenceRoundRect:
case DisplayListOpType::kClipDifferenceRoundSuperellipse:
case DisplayListOpType::kClipDifferencePath:
return DisplayListOpCategory::kClip;

Expand All @@ -316,6 +318,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:
Expand Down
167 changes: 85 additions & 82 deletions engine/src/flutter/display_list/display_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,88 +52,91 @@

namespace flutter {

#define FOR_EACH_DISPLAY_LIST_OP(V) \
V(SetAntiAlias) \
V(SetInvertColors) \
\
V(SetStrokeCap) \
V(SetStrokeJoin) \
\
V(SetStyle) \
V(SetStrokeWidth) \
V(SetStrokeMiter) \
\
V(SetColor) \
V(SetBlendMode) \
\
V(ClearColorFilter) \
V(SetPodColorFilter) \
\
V(ClearColorSource) \
V(SetPodColorSource) \
V(SetImageColorSource) \
V(SetRuntimeEffectColorSource) \
\
V(ClearImageFilter) \
V(SetPodImageFilter) \
V(SetSharedImageFilter) \
\
V(ClearMaskFilter) \
V(SetPodMaskFilter) \
\
V(Save) \
V(SaveLayer) \
V(SaveLayerBackdrop) \
V(Restore) \
\
V(Translate) \
V(Scale) \
V(Rotate) \
V(Skew) \
V(Transform2DAffine) \
V(TransformFullPerspective) \
V(TransformReset) \
\
V(ClipIntersectRect) \
V(ClipIntersectOval) \
V(ClipIntersectRoundRect) \
V(ClipIntersectPath) \
V(ClipDifferenceRect) \
V(ClipDifferenceOval) \
V(ClipDifferenceRoundRect) \
V(ClipDifferencePath) \
\
V(DrawPaint) \
V(DrawColor) \
\
V(DrawLine) \
V(DrawDashedLine) \
V(DrawRect) \
V(DrawOval) \
V(DrawCircle) \
V(DrawRoundRect) \
V(DrawDiffRoundRect) \
V(DrawArc) \
V(DrawPath) \
\
V(DrawPoints) \
V(DrawLines) \
V(DrawPolygon) \
V(DrawVertices) \
\
V(DrawImage) \
V(DrawImageWithAttr) \
V(DrawImageRect) \
V(DrawImageNine) \
V(DrawImageNineWithAttr) \
V(DrawAtlas) \
V(DrawAtlasCulled) \
\
V(DrawDisplayList) \
V(DrawTextBlob) \
V(DrawTextFrame) \
\
V(DrawShadow) \
#define FOR_EACH_DISPLAY_LIST_OP(V) \
V(SetAntiAlias) \
V(SetInvertColors) \
\
V(SetStrokeCap) \
V(SetStrokeJoin) \
\
V(SetStyle) \
V(SetStrokeWidth) \
V(SetStrokeMiter) \
\
V(SetColor) \
V(SetBlendMode) \
\
V(ClearColorFilter) \
V(SetPodColorFilter) \
\
V(ClearColorSource) \
V(SetPodColorSource) \
V(SetImageColorSource) \
V(SetRuntimeEffectColorSource) \
\
V(ClearImageFilter) \
V(SetPodImageFilter) \
V(SetSharedImageFilter) \
\
V(ClearMaskFilter) \
V(SetPodMaskFilter) \
\
V(Save) \
V(SaveLayer) \
V(SaveLayerBackdrop) \
V(Restore) \
\
V(Translate) \
V(Scale) \
V(Rotate) \
V(Skew) \
V(Transform2DAffine) \
V(TransformFullPerspective) \
V(TransformReset) \
\
V(ClipIntersectRect) \
V(ClipIntersectOval) \
V(ClipIntersectRoundRect) \
V(ClipIntersectRoundSuperellipse) \
V(ClipIntersectPath) \
V(ClipDifferenceRect) \
V(ClipDifferenceOval) \
V(ClipDifferenceRoundRect) \
V(ClipDifferenceRoundSuperellipse) \
V(ClipDifferencePath) \
\
V(DrawPaint) \
V(DrawColor) \
\
V(DrawLine) \
V(DrawDashedLine) \
V(DrawRect) \
V(DrawOval) \
V(DrawCircle) \
V(DrawRoundRect) \
V(DrawDiffRoundRect) \
V(DrawRoundSuperellipse) \
V(DrawArc) \
V(DrawPath) \
\
V(DrawPoints) \
V(DrawLines) \
V(DrawPolygon) \
V(DrawVertices) \
\
V(DrawImage) \
V(DrawImageWithAttr) \
V(DrawImageRect) \
V(DrawImageNine) \
V(DrawImageNineWithAttr) \
V(DrawAtlas) \
V(DrawAtlasCulled) \
\
V(DrawDisplayList) \
V(DrawTextBlob) \
V(DrawTextFrame) \
\
V(DrawShadow) \
V(DrawShadowTransparentOccluder)

#define DL_OP_TO_ENUM_VALUE(name) k##name,
Expand Down
9 changes: 8 additions & 1 deletion engine/src/flutter/display_list/display_list_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4512,7 +4512,7 @@ TEST_F(DisplayListTest, DrawDisplayListForwardsBackdropFlag) {
#define CLIP_EXPECTOR(name) ClipExpector name(__FILE__, __LINE__)

struct ClipExpectation {
std::variant<DlRect, DlRoundRect, DlPath> shape;
std::variant<DlRect, DlRoundRect, DlRoundSuperellipse, DlPath> shape;
bool is_oval;
DlClipOp clip_op;
bool is_aa;
Expand All @@ -4524,6 +4524,8 @@ struct ClipExpectation {
case 1:
return "DlRoundRect";
case 2:
return "DlRoundSuperellipse";
case 3:
return "DlPath";
default:
return "Unknown";
Expand Down Expand Up @@ -4632,6 +4634,11 @@ class ClipExpector : public virtual DlOpReceiver,
bool is_aa) override {
check(rrect, clip_op, is_aa);
}
void clipRoundSuperellipse(const DlRoundSuperellipse& rse,
DlClipOp clip_op,
bool is_aa) override {
check(rse, clip_op, is_aa);
}
void clipPath(const DlPath& path, DlClipOp clip_op, bool is_aa) override {
check(path, clip_op, is_aa);
}
Expand Down
57 changes: 57 additions & 0 deletions engine/src/flutter/display_list/dl_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,42 @@ void DisplayListBuilder::ClipRoundRect(const DlRoundRect& rrect,
break;
}
}
void DisplayListBuilder::ClipRoundSuperellipse(const DlRoundSuperellipse& rse,
DlClipOp clip_op,
bool is_aa) {
if (rse.IsRect()) {
ClipRect(rse.GetBounds(), clip_op, is_aa);
return;
}
if (rse.IsOval()) {
ClipOval(rse.GetBounds(), clip_op, is_aa);
return;
}
if (current_info().is_nop) {
return;
}
if (current_info().has_valid_clip && clip_op == DlClipOp::kIntersect &&
layer_local_state().rsuperellipse_covers_cull(rse)) {
return;
}
global_state().clipRSuperellipse(rse, clip_op, is_aa);
layer_local_state().clipRSuperellipse(rse, clip_op, is_aa);
if (global_state().is_cull_rect_empty() ||
layer_local_state().is_cull_rect_empty()) {
current_info().is_nop = true;
return;
}
current_info().has_valid_clip = true;
checkForDeferredSave();
switch (clip_op) {
case DlClipOp::kIntersect:
Push<ClipIntersectRoundSuperellipseOp>(0, rse, is_aa);
break;
case DlClipOp::kDifference:
Push<ClipDifferenceRoundSuperellipseOp>(0, rse, is_aa);
break;
}
}
void DisplayListBuilder::ClipPath(const DlPath& path,
DlClipOp clip_op,
bool is_aa) {
Expand Down Expand Up @@ -1214,6 +1250,27 @@ void DisplayListBuilder::DrawDiffRoundRect(const DlRoundRect& outer,
SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawDRRectFlags);
drawDiffRoundRect(outer, inner);
}
void DisplayListBuilder::drawRoundSuperellipse(const DlRoundSuperellipse& rse) {
if (rse.IsRect()) {
drawRect(rse.GetBounds());
} else if (rse.IsOval()) {
drawOval(rse.GetBounds());
} else {
DisplayListAttributeFlags flags = kDrawRSuperellipseFlags;
OpResult result = PaintResult(current_, flags);
if (result != OpResult::kNoEffect &&
AccumulateOpBounds(rse.GetBounds(), flags)) {
Push<DrawRoundSuperellipseOp>(0, rse);
CheckLayerOpacityCompatibility();
UpdateLayerResult(result);
}
}
}
void DisplayListBuilder::DrawRoundSuperellipse(const DlRoundSuperellipse& rse,
const DlPaint& paint) {
SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawRSuperellipseFlags);
drawRoundSuperellipse(rse);
}
void DisplayListBuilder::drawPath(const DlPath& path) {
DisplayListAttributeFlags flags = kDrawPathFlags;
OpResult result = PaintResult(current_, flags);
Expand Down
Loading

0 comments on commit 5b7a3c8

Please sign in to comment.