Mark BackdropFilter as inheriting opacity, enabling fading of BDFs (flutter/engine#34435)

This commit is contained in:
Jim Graham 2022-07-06 18:56:04 -07:00 committed by GitHub
parent a44f32cdab
commit a433158616
9 changed files with 88 additions and 29 deletions

View File

@ -47,28 +47,28 @@ void BackdropFilterLayer::Preroll(PrerollContext* context,
PrerollChildren(context, matrix, &child_paint_bounds);
child_paint_bounds.join(context->cull_rect);
set_paint_bounds(child_paint_bounds);
context->subtree_can_inherit_opacity = true;
}
void BackdropFilterLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "BackdropFilterLayer::Paint");
FML_DCHECK(needs_painting(context));
AutoCachePaint save_paint(context);
save_paint.setBlendMode(blend_mode_);
if (context.leaf_nodes_builder) {
DlPaint paint;
paint.setBlendMode(blend_mode_);
context.leaf_nodes_builder->saveLayer(&paint_bounds(), &paint,
filter_.get());
context.leaf_nodes_builder->saveLayer(&paint_bounds(),
save_paint.dl_paint(), filter_.get());
PaintChildren(context);
context.leaf_nodes_builder->restore();
} else {
SkPaint paint;
paint.setBlendMode(ToSk(blend_mode_));
auto sk_filter = filter_ ? filter_->skia_object() : nullptr;
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
context,
SkCanvas::SaveLayerRec{&paint_bounds(), &paint, sk_filter.get(), 0},
SkCanvas::SaveLayerRec{&paint_bounds(), save_paint.sk_paint(),
sk_filter.get(), 0},
// BackdropFilter should only happen on the leaf nodes canvas.
// See https:://flutter.dev/go/backdrop-filter-with-overlay-canvas
AutoSaveLayer::SaveMode::kLeafNodesCanvas);

View File

@ -277,6 +277,52 @@ TEST_F(BackdropFilterLayerTest, Readback) {
EXPECT_FALSE(preroll_context()->surface_needs_readback);
}
TEST_F(BackdropFilterLayerTest, OpacityInheritance) {
auto backdrop_filter = DlBlurImageFilter(5, 5, DlTileMode::kClamp);
const SkPath mock_path = SkPath().addRect(SkRect::MakeLTRB(0, 0, 10, 10));
const SkPaint mock_paint = SkPaint(SkColors::kRed);
const SkRect clip_rect = SkRect::MakeLTRB(0, 0, 100, 100);
auto clip = std::make_shared<ClipRectLayer>(clip_rect, Clip::hardEdge);
auto parent = std::make_shared<OpacityLayer>(128, SkPoint::Make(0, 0));
auto layer = std::make_shared<BackdropFilterLayer>(backdrop_filter.shared(),
DlBlendMode::kSrcOver);
auto child = std::make_shared<MockLayer>(mock_path, mock_paint);
layer->Add(child);
parent->Add(layer);
clip->Add(parent);
clip->Preroll(preroll_context(), SkMatrix::I());
clip->Paint(display_list_paint_context());
DisplayListBuilder expected_builder(clip_rect);
/* ClipRectLayer::Paint */ {
expected_builder.save();
{
expected_builder.clipRect(clip_rect, SkClipOp::kIntersect, false);
/* OpacityLayer::Paint */ {
// NOP - it hands opacity down to BackdropFilterLayer
/* BackdropFilterLayer::Paint */ {
DlPaint save_paint;
save_paint.setAlpha(128);
expected_builder.saveLayer(&clip_rect, &save_paint, &backdrop_filter);
{
/* MockLayer::Paint */ {
DlPaint child_paint;
child_paint.setColor(DlColor::kRed());
expected_builder.drawPath(mock_path, child_paint);
}
}
expected_builder.restore();
}
}
}
expected_builder.restore();
}
EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
}
using BackdropLayerDiffTest = DiffContextTest;
TEST_F(BackdropLayerDiffTest, BackdropLayer) {

View File

@ -89,13 +89,13 @@ class ClipShapeLayer : public CacheableContainerLayer {
AutoCachePaint cache_paint(context);
if (context.raster_cache) {
if (layer_raster_cache_item_->Draw(context, cache_paint.paint())) {
if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) {
return;
}
}
Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create(
context, paint_bounds(), cache_paint.paint());
context, paint_bounds(), cache_paint.sk_paint());
PaintChildren(context);
}

View File

@ -51,7 +51,7 @@ void ColorFilterLayer::Paint(PaintContext& context) const {
if (layer_raster_cache_item_->IsCacheChildren()) {
cache_paint.setColorFilter(filter_);
}
if (layer_raster_cache_item_->Draw(context, cache_paint.paint())) {
if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) {
return;
}
}
@ -59,7 +59,7 @@ void ColorFilterLayer::Paint(PaintContext& context) const {
cache_paint.setColorFilter(filter_);
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
context, paint_bounds(), cache_paint.paint());
context, paint_bounds(), cache_paint.sk_paint());
PaintChildren(context);
}

View File

@ -114,7 +114,8 @@ void DisplayListLayer::Paint(PaintContext& context) const {
if (context.raster_cache && display_list_raster_cache_item_) {
AutoCachePaint cache_paint(context);
if (display_list_raster_cache_item_->Draw(context, cache_paint.paint())) {
if (display_list_raster_cache_item_->Draw(context,
cache_paint.sk_paint())) {
TRACE_EVENT_INSTANT0("flutter", "raster cache hit");
return;
}
@ -151,9 +152,9 @@ void DisplayListLayer::Paint(PaintContext& context) const {
if (context.leaf_nodes_builder) {
AutoCachePaint save_paint(context);
int restore_count = context.leaf_nodes_builder->getSaveCount();
if (save_paint.paint() != nullptr) {
DlPaint paint = DlPaint().setAlpha(save_paint.paint()->getAlpha());
context.leaf_nodes_builder->saveLayer(&paint_bounds(), &paint);
if (save_paint.dl_paint() != nullptr) {
context.leaf_nodes_builder->saveLayer(&paint_bounds(),
save_paint.dl_paint());
}
context.leaf_nodes_builder->drawDisplayList(display_list_.skia_object());
context.leaf_nodes_builder->restoreToCount(restore_count);

View File

@ -87,7 +87,7 @@ void ImageFilterLayer::Paint(PaintContext& context) const {
if (layer_raster_cache_item_->IsCacheChildren()) {
cache_paint.setImageFilter(transformed_filter_);
}
if (layer_raster_cache_item_->Draw(context, cache_paint.paint())) {
if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) {
return;
}
@ -98,7 +98,7 @@ void ImageFilterLayer::Paint(PaintContext& context) const {
// so we use the bounds of the child container which do not include any
// modifications that the filter might apply.
Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create(
context, child_paint_bounds(), cache_paint.paint());
context, child_paint_bounds(), cache_paint.sk_paint());
PaintChildren(context);
}

View File

@ -209,34 +209,46 @@ class Layer {
explicit AutoCachePaint(PaintContext& context) : context_(context) {
needs_paint_ = context.inherited_opacity < SK_Scalar1;
if (needs_paint_) {
paint_.setAlphaf(context.inherited_opacity);
sk_paint_.setAlphaf(context.inherited_opacity);
dl_paint_.setAlpha(SkScalarRoundToInt(context.inherited_opacity * 255));
context.inherited_opacity = SK_Scalar1;
}
}
~AutoCachePaint() { context_.inherited_opacity = paint_.getAlphaf(); }
~AutoCachePaint() { context_.inherited_opacity = sk_paint_.getAlphaf(); }
void setImageFilter(sk_sp<SkImageFilter> filter) {
paint_.setImageFilter(filter);
sk_paint_.setImageFilter(filter);
dl_paint_.setImageFilter(DlImageFilter::From(filter));
update_needs_paint();
}
void setColorFilter(sk_sp<SkColorFilter> filter) {
paint_.setColorFilter(filter);
sk_paint_.setColorFilter(filter);
dl_paint_.setColorFilter(DlColorFilter::From(filter));
update_needs_paint();
}
const SkPaint* paint() { return needs_paint_ ? &paint_ : nullptr; }
void setBlendMode(DlBlendMode mode) {
sk_paint_.setBlendMode(ToSk(mode));
dl_paint_.setBlendMode(mode);
update_needs_paint();
}
const SkPaint* sk_paint() { return needs_paint_ ? &sk_paint_ : nullptr; }
const DlPaint* dl_paint() { return needs_paint_ ? &dl_paint_ : nullptr; }
private:
PaintContext& context_;
SkPaint paint_;
SkPaint sk_paint_;
DlPaint dl_paint_;
bool needs_paint_;
void update_needs_paint() {
needs_paint_ = paint_.getImageFilter() != nullptr ||
paint_.getColorFilter() != nullptr ||
paint_.getAlphaf() < SK_Scalar1;
needs_paint_ = sk_paint_.getImageFilter() != nullptr ||
sk_paint_.getColorFilter() != nullptr ||
!sk_paint_.isSrcOver() ||
sk_paint_.getAlphaf() < SK_Scalar1;
}
};

View File

@ -50,13 +50,13 @@ void ShaderMaskLayer::Paint(PaintContext& context) const {
AutoCachePaint cache_paint(context);
if (context.raster_cache) {
if (layer_raster_cache_item_->Draw(context, cache_paint.paint())) {
if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) {
return;
}
}
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
context, paint_bounds(), cache_paint.paint());
context, paint_bounds(), cache_paint.sk_paint());
PaintChildren(context);
SkPaint paint;

View File

@ -61,7 +61,7 @@ void TextureLayer::Paint(PaintContext& context) const {
}
AutoCachePaint cache_paint(context);
texture->Paint(*context.leaf_nodes_canvas, paint_bounds(), freeze_,
context.gr_context, ToSk(sampling_), cache_paint.paint());
context.gr_context, ToSk(sampling_), cache_paint.sk_paint());
}
} // namespace flutter