mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Mark BackdropFilter as inheriting opacity, enabling fading of BDFs (flutter/engine#34435)
This commit is contained in:
parent
a44f32cdab
commit
a433158616
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user