Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f4d020b

Browse files
committed
[Impeller] Use direct tessellation geometry for simple clip shapes
1 parent a1777a3 commit f4d020b

File tree

4 files changed

+118
-17
lines changed

4 files changed

+118
-17
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,74 @@ TEST_P(AiksTest, CanRenderClips) {
318318
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
319319
}
320320

321+
TEST_P(AiksTest, CanRenderSimpleClips) {
322+
Canvas canvas;
323+
canvas.Scale(GetContentScale());
324+
Paint paint;
325+
326+
paint.color = Color::White();
327+
canvas.DrawPaint(paint);
328+
329+
auto draw = [&canvas](const Paint& paint, Scalar x, Scalar y) {
330+
canvas.Save();
331+
canvas.Translate({x, y});
332+
{
333+
canvas.Save();
334+
canvas.ClipRect(Rect::MakeLTRB(50, 50, 150, 150));
335+
canvas.DrawPaint(paint);
336+
canvas.Restore();
337+
}
338+
{
339+
canvas.Save();
340+
canvas.ClipOval(Rect::MakeLTRB(200, 50, 300, 150));
341+
canvas.DrawPaint(paint);
342+
canvas.Restore();
343+
}
344+
{
345+
canvas.Save();
346+
canvas.ClipRRect(Rect::MakeLTRB(50, 200, 150, 300), {20, 20});
347+
canvas.DrawPaint(paint);
348+
canvas.Restore();
349+
}
350+
canvas.Restore();
351+
};
352+
353+
paint.color = Color::Blue();
354+
draw(paint, 0, 0);
355+
356+
std::vector<Color> gradient_colors = {
357+
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
358+
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
359+
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
360+
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
361+
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
362+
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
363+
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
364+
std::vector<Scalar> stops = {
365+
0.0,
366+
(1.0 / 6.0) * 1,
367+
(1.0 / 6.0) * 2,
368+
(1.0 / 6.0) * 3,
369+
(1.0 / 6.0) * 4,
370+
(1.0 / 6.0) * 5,
371+
1.0,
372+
};
373+
auto texture = CreateTextureForFixture("airplane.jpg",
374+
/*enable_mipmapping=*/true);
375+
376+
paint.color_source = ColorSource::MakeRadialGradient(
377+
{500, 600}, 75, std::move(gradient_colors), std::move(stops),
378+
Entity::TileMode::kMirror, {});
379+
draw(paint, 0, 300);
380+
381+
paint.color_source = ColorSource::MakeImage(
382+
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
383+
Matrix::MakeTranslation({0, 0}));
384+
draw(paint, 300, 0);
385+
386+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
387+
}
388+
321389
TEST_P(AiksTest, CanRenderNestedClips) {
322390
Canvas canvas;
323391
Paint paint;

impeller/aiks/canvas.cc

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -448,23 +448,34 @@ void Canvas::ClipRect(const Rect& rect, Entity::ClipOperation clip_op) {
448448
}
449449
}
450450

451+
void Canvas::ClipOval(const Rect& bounds, Entity::ClipOperation clip_op) {
452+
auto geometry = Geometry::MakeOval(bounds);
453+
auto& cull_rect = transform_stack_.back().cull_rect;
454+
if (clip_op == Entity::ClipOperation::kIntersect && //
455+
cull_rect.has_value() && //
456+
geometry->CoversArea(transform_stack_.back().transform, *cull_rect) //
457+
) {
458+
return; // This clip will do nothing, so skip it.
459+
}
460+
461+
ClipGeometry(geometry, clip_op);
462+
switch (clip_op) {
463+
case Entity::ClipOperation::kIntersect:
464+
IntersectCulling(bounds);
465+
break;
466+
case Entity::ClipOperation::kDifference:
467+
break;
468+
}
469+
}
470+
451471
void Canvas::ClipRRect(const Rect& rect,
452472
const Size& corner_radii,
453473
Entity::ClipOperation clip_op) {
454-
auto path = PathBuilder{}
455-
.SetConvexity(Convexity::kConvex)
456-
.AddRoundedRect(rect, corner_radii)
457-
.SetBounds(rect)
458-
.TakePath();
459-
460474
auto size = rect.GetSize();
461475
// Does the rounded rect have a flat part on the top/bottom or left/right?
462476
bool flat_on_TB = corner_radii.width * 2 < size.width;
463477
bool flat_on_LR = corner_radii.height * 2 < size.height;
464-
std::optional<Rect> inner_rect = (flat_on_LR && flat_on_TB)
465-
? rect.Expand(-corner_radii)
466-
: std::make_optional<Rect>();
467-
auto geometry = Geometry::MakeFillPath(std::move(path), inner_rect);
478+
auto geometry = Geometry::MakeRoundRect(rect, corner_radii);
468479
auto& cull_rect = transform_stack_.back().cull_rect;
469480
if (clip_op == Entity::ClipOperation::kIntersect && //
470481
cull_rect.has_value() && //

impeller/aiks/canvas.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ class Canvas {
136136
const Rect& rect,
137137
Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect);
138138

139+
void ClipOval(
140+
const Rect& bounds,
141+
Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect);
142+
139143
void ClipRRect(
140144
const Rect& rect,
141145
const Size& corner_radii,

impeller/display_list/dl_dispatcher.cc

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -725,22 +725,40 @@ void DlDispatcher::clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) {
725725
}
726726

727727
// |flutter::DlOpReceiver|
728-
void DlDispatcher::clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) {
728+
void DlDispatcher::clipRRect(const SkRRect& rrect, ClipOp sk_op, bool is_aa) {
729+
auto clip_op = ToClipOperation(sk_op);
729730
if (rrect.isRect()) {
730-
canvas_.ClipRect(skia_conversions::ToRect(rrect.rect()),
731-
ToClipOperation(clip_op));
731+
canvas_.ClipRect(skia_conversions::ToRect(rrect.rect()), clip_op);
732+
} else if (rrect.isOval()) {
733+
canvas_.ClipOval(skia_conversions::ToRect(rrect.rect()), clip_op);
732734
} else if (rrect.isSimple()) {
733735
canvas_.ClipRRect(skia_conversions::ToRect(rrect.rect()),
734736
skia_conversions::ToSize(rrect.getSimpleRadii()),
735-
ToClipOperation(clip_op));
737+
clip_op);
736738
} else {
737-
canvas_.ClipPath(skia_conversions::ToPath(rrect), ToClipOperation(clip_op));
739+
canvas_.ClipPath(skia_conversions::ToPath(rrect), clip_op);
738740
}
739741
}
740742

741743
// |flutter::DlOpReceiver|
742-
void DlDispatcher::clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) {
743-
canvas_.ClipPath(skia_conversions::ToPath(path), ToClipOperation(clip_op));
744+
void DlDispatcher::clipPath(const SkPath& path, ClipOp sk_op, bool is_aa) {
745+
auto clip_op = ToClipOperation(sk_op);
746+
747+
SkRect rect;
748+
if (path.isRect(&rect)) {
749+
canvas_.ClipRect(skia_conversions::ToRect(rect), clip_op);
750+
} else if (path.isOval(&rect)) {
751+
canvas_.ClipOval(skia_conversions::ToRect(rect), clip_op);
752+
} else {
753+
SkRRect rrect;
754+
if (path.isRRect(&rrect) && rrect.isSimple()) {
755+
canvas_.ClipRRect(skia_conversions::ToRect(rrect.rect()),
756+
skia_conversions::ToSize(rrect.getSimpleRadii()),
757+
clip_op);
758+
} else {
759+
canvas_.ClipPath(skia_conversions::ToPath(path), clip_op);
760+
}
761+
}
744762
}
745763

746764
// |flutter::DlOpReceiver|

0 commit comments

Comments
 (0)