未验证 提交 2d9c5e4a 编写于 作者: J Jim Graham 提交者: GitHub

Add a blendMode to BackdropFilter layers to enable developers to control...

Add a blendMode to BackdropFilter layers to enable developers to control blending on save layers (#19631)
上级 c4810cf5
......@@ -6,8 +6,9 @@
namespace flutter {
BackdropFilterLayer::BackdropFilterLayer(sk_sp<SkImageFilter> filter)
: filter_(std::move(filter)) {}
BackdropFilterLayer::BackdropFilterLayer(sk_sp<SkImageFilter> filter,
SkBlendMode blend_mode)
: filter_(std::move(filter)), blend_mode_(blend_mode) {}
#ifdef FLUTTER_ENABLE_DIFF_CONTEXT
......@@ -57,9 +58,11 @@ void BackdropFilterLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "BackdropFilterLayer::Paint");
FML_DCHECK(needs_painting(context));
SkPaint paint;
paint.setBlendMode(blend_mode_);
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
context,
SkCanvas::SaveLayerRec{&paint_bounds(), nullptr, filter_.get(), 0});
SkCanvas::SaveLayerRec{&paint_bounds(), &paint, filter_.get(), 0});
PaintChildren(context);
}
......
......@@ -12,7 +12,7 @@ namespace flutter {
class BackdropFilterLayer : public ContainerLayer {
public:
BackdropFilterLayer(sk_sp<SkImageFilter> filter);
BackdropFilterLayer(sk_sp<SkImageFilter> filter, SkBlendMode blend_mode);
#ifdef FLUTTER_ENABLE_DIFF_CONTEXT
......@@ -26,6 +26,7 @@ class BackdropFilterLayer : public ContainerLayer {
private:
sk_sp<SkImageFilter> filter_;
SkBlendMode blend_mode_;
FML_DISALLOW_COPY_AND_ASSIGN(BackdropFilterLayer);
};
......
......@@ -22,7 +22,8 @@ using BackdropFilterLayerTest = LayerTest;
#ifndef NDEBUG
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies) {
auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>());
auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>(),
SkBlendMode::kSrcOver);
auto parent = std::make_shared<ClipRectLayer>(kEmptyRect, Clip::hardEdge);
parent->Add(layer);
......@@ -39,7 +40,8 @@ TEST_F(BackdropFilterLayerTest, PaintBeforePrerollDies) {
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
const SkPath child_path = SkPath().addRect(child_bounds);
auto mock_layer = std::make_shared<MockLayer>(child_path);
auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>());
auto layer = std::make_shared<BackdropFilterLayer>(sk_sp<SkImageFilter>(),
SkBlendMode::kSrcOver);
layer->Add(mock_layer);
EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
......@@ -54,7 +56,8 @@ TEST_F(BackdropFilterLayerTest, EmptyFilter) {
const SkPath child_path = SkPath().addRect(child_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<BackdropFilterLayer>(nullptr);
auto layer =
std::make_shared<BackdropFilterLayer>(nullptr, SkBlendMode::kSrcOver);
layer->Add(mock_layer);
auto parent = std::make_shared<ClipRectLayer>(child_bounds, Clip::hardEdge);
parent->Add(layer);
......@@ -82,7 +85,8 @@ TEST_F(BackdropFilterLayerTest, SimpleFilter) {
const SkPaint child_paint = SkPaint(SkColors::kYellow);
auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer = std::make_shared<BackdropFilterLayer>(layer_filter);
auto layer = std::make_shared<BackdropFilterLayer>(layer_filter,
SkBlendMode::kSrcOver);
layer->Add(mock_layer);
auto parent = std::make_shared<ClipRectLayer>(child_bounds, Clip::hardEdge);
parent->Add(layer);
......@@ -103,6 +107,38 @@ TEST_F(BackdropFilterLayerTest, SimpleFilter) {
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(BackdropFilterLayerTest, NonSrcOverBlend) {
const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
const SkPath child_path = SkPath().addRect(child_bounds);
const SkPaint child_paint = SkPaint(SkColors::kYellow);
auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
auto layer =
std::make_shared<BackdropFilterLayer>(layer_filter, SkBlendMode::kSrc);
layer->Add(mock_layer);
auto parent = std::make_shared<ClipRectLayer>(child_bounds, Clip::hardEdge);
parent->Add(layer);
parent->Preroll(preroll_context(), initial_transform);
EXPECT_EQ(layer->paint_bounds(), child_bounds);
EXPECT_TRUE(layer->needs_painting(paint_context()));
EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
SkPaint filter_paint = SkPaint();
filter_paint.setBlendMode(SkBlendMode::kSrc);
layer->Paint(paint_context());
EXPECT_EQ(
mock_canvas().draw_calls(),
std::vector({MockCanvas::DrawCall{
0, MockCanvas::SaveLayerData{child_bounds, filter_paint,
layer_filter, 1}},
MockCanvas::DrawCall{
1, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
}
TEST_F(BackdropFilterLayerTest, MultipleChildren) {
const SkMatrix initial_transform = SkMatrix::Translate(0.5f, 1.0f);
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
......@@ -116,7 +152,8 @@ TEST_F(BackdropFilterLayerTest, MultipleChildren) {
auto layer_filter = SkImageFilters::Paint(SkPaint(SkColors::kMagenta));
auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
auto layer = std::make_shared<BackdropFilterLayer>(layer_filter);
auto layer = std::make_shared<BackdropFilterLayer>(layer_filter,
SkBlendMode::kSrcOver);
layer->Add(mock_layer1);
layer->Add(mock_layer2);
auto parent =
......@@ -160,8 +197,10 @@ TEST_F(BackdropFilterLayerTest, Nested) {
auto layer_filter2 = SkImageFilters::Paint(SkPaint(SkColors::kDkGray));
auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1);
auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2);
auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter1);
auto layer2 = std::make_shared<BackdropFilterLayer>(layer_filter2);
auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter1,
SkBlendMode::kSrcOver);
auto layer2 = std::make_shared<BackdropFilterLayer>(layer_filter2,
SkBlendMode::kSrcOver);
layer2->Add(mock_layer2);
layer1->Add(mock_layer1);
layer1->Add(layer2);
......@@ -204,13 +243,15 @@ TEST_F(BackdropFilterLayerTest, Readback) {
auto initial_transform = SkMatrix();
// BDF with filter always reads from surface
auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter);
auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter,
SkBlendMode::kSrcOver);
preroll_context()->surface_needs_readback = false;
layer1->Preroll(preroll_context(), initial_transform);
EXPECT_TRUE(preroll_context()->surface_needs_readback);
// BDF with no filter does not read from surface itself
auto layer2 = std::make_shared<BackdropFilterLayer>(no_filter);
auto layer2 =
std::make_shared<BackdropFilterLayer>(no_filter, SkBlendMode::kSrcOver);
preroll_context()->surface_needs_readback = false;
layer2->Preroll(preroll_context(), initial_transform);
EXPECT_FALSE(preroll_context()->surface_needs_readback);
......@@ -244,7 +285,8 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) {
}
MockLayerTree l1(SkISize::Make(100, 100));
l1.root()->Add(std::make_shared<BackdropFilterLayer>(filter));
l1.root()->Add(
std::make_shared<BackdropFilterLayer>(filter, SkBlendMode::kSrcOver));
// no clip, effect over entire surface
auto damage = DiffLayerTree(l1, MockLayerTree(SkISize::Make(100, 100)));
......@@ -254,7 +296,8 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) {
auto clip = std::make_shared<ClipRectLayer>(SkRect::MakeLTRB(20, 20, 60, 60),
Clip::hardEdge);
clip->Add(std::make_shared<BackdropFilterLayer>(filter));
clip->Add(
std::make_shared<BackdropFilterLayer>(filter, SkBlendMode::kSrcOver));
l2.root()->Add(clip);
damage = DiffLayerTree(l2, MockLayerTree(SkISize::Make(100, 100)));
......
......@@ -495,8 +495,9 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
/// Pushes a backdrop filter operation onto the operation stack.
///
/// The given filter is applied to the current contents of the scene prior to
/// rasterizing the given objects.
/// The given filter is applied to the current contents of the scene as far back as
/// the most recent save layer and rendered back to the scene using the indicated
/// [blendMode] prior to rasterizing the child layers.
///
/// {@macro dart.ui.sceneBuilder.oldLayer}
///
......@@ -505,17 +506,18 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
/// See [pop] for details about the operation stack.
BackdropFilterEngineLayer? pushBackdropFilter(
ImageFilter filter, {
BlendMode blendMode = BlendMode.srcOver,
BackdropFilterEngineLayer? oldLayer,
}) {
assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushBackdropFilter'));
final EngineLayer engineLayer = EngineLayer._();
_pushBackdropFilter(engineLayer, filter._toNativeImageFilter(), oldLayer?._nativeLayer);
_pushBackdropFilter(engineLayer, filter._toNativeImageFilter(), blendMode.index, oldLayer?._nativeLayer);
final BackdropFilterEngineLayer layer = BackdropFilterEngineLayer._(engineLayer);
assert(_debugPushLayer(layer));
return layer;
}
void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter, EngineLayer? oldLayer)
void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter, int blendMode, EngineLayer? oldLayer)
native 'SceneBuilder_pushBackdropFilter';
/// Pushes a shader mask operation onto the operation stack.
......
......@@ -211,8 +211,10 @@ void SceneBuilder::pushImageFilter(Dart_Handle layer_handle,
void SceneBuilder::pushBackdropFilter(Dart_Handle layer_handle,
ImageFilter* filter,
int blendMode,
fml::RefPtr<EngineLayer> oldLayer) {
auto layer = std::make_shared<flutter::BackdropFilterLayer>(filter->filter());
auto layer = std::make_shared<flutter::BackdropFilterLayer>(
filter->filter(), static_cast<SkBlendMode>(blendMode));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
......
......@@ -72,6 +72,7 @@ class SceneBuilder : public RefCountedDartWrappable<SceneBuilder> {
fml::RefPtr<EngineLayer> oldLayer);
void pushBackdropFilter(Dart_Handle layer_handle,
ImageFilter* filter,
int blendMode,
fml::RefPtr<EngineLayer> oldLayer);
void pushShaderMask(Dart_Handle layer_handle,
Shader* shader,
......
......@@ -269,11 +269,11 @@ class CkCanvas {
skCanvas.saveLayer(paint?.skiaObject, null, null, null);
}
void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter) {
void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter, [ CkPaint? paint ]) {
final _CkManagedSkImageFilterConvertible convertible =
filter as _CkManagedSkImageFilterConvertible;
return skCanvas.saveLayer(
null,
paint?.skiaObject,
toSkRect(bounds),
convertible._imageFilter.skiaObject,
0,
......@@ -505,9 +505,9 @@ class RecordingCkCanvas extends CkCanvas {
}
@override
void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter) {
super.saveLayerWithFilter(bounds, filter);
_addCommand(CkSaveLayerWithFilterCommand(bounds, filter));
void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter, [ CkPaint? paint ]) {
super.saveLayerWithFilter(bounds, filter, paint);
_addCommand(CkSaveLayerWithFilterCommand(bounds, filter, paint));
}
@override
......@@ -1121,17 +1121,18 @@ class CkSaveLayerWithoutBoundsCommand extends CkPaintCommand {
}
class CkSaveLayerWithFilterCommand extends CkPaintCommand {
CkSaveLayerWithFilterCommand(this.bounds, this.filter);
CkSaveLayerWithFilterCommand(this.bounds, this.filter, this.paint);
final ui.Rect bounds;
final ui.ImageFilter filter;
final CkPaint? paint;
@override
void apply(SkCanvas canvas) {
final _CkManagedSkImageFilterConvertible convertible =
filter as _CkManagedSkImageFilterConvertible;
return canvas.saveLayer(
null,
paint?.skiaObject,
toSkRect(bounds),
convertible._imageFilter.skiaObject,
0,
......
......@@ -152,8 +152,9 @@ class RootLayer extends ContainerLayer {
class BackdropFilterEngineLayer extends ContainerLayer implements ui.BackdropFilterEngineLayer {
final ui.ImageFilter _filter;
final ui.BlendMode _blendMode;
BackdropFilterEngineLayer(this._filter);
BackdropFilterEngineLayer(this._filter, this._blendMode);
@override
void preroll(PrerollContext preRollContext, Matrix4 matrix) {
......@@ -163,7 +164,8 @@ class BackdropFilterEngineLayer extends ContainerLayer implements ui.BackdropFil
@override
void paint(PaintContext context) {
context.internalNodesCanvas.saveLayerWithFilter(paintBounds, _filter);
CkPaint paint = CkPaint()..blendMode = _blendMode;
context.internalNodesCanvas.saveLayerWithFilter(paintBounds, _filter, paint);
paintChildren(context);
context.internalNodesCanvas.restore();
}
......
......@@ -101,9 +101,13 @@ class LayerSceneBuilder implements ui.SceneBuilder {
@override
BackdropFilterEngineLayer? pushBackdropFilter(
ui.ImageFilter filter, {
ui.BlendMode blendMode = ui.BlendMode.srcOver,
ui.EngineLayer? oldLayer,
}) {
return pushLayer<BackdropFilterEngineLayer>(BackdropFilterEngineLayer(filter));
return pushLayer<BackdropFilterEngineLayer>(BackdropFilterEngineLayer(
filter,
blendMode,
));
}
@override
......
......@@ -31,9 +31,9 @@ class CkNWayCanvas {
}
/// Calls [saveLayerWithFilter] on all canvases.
void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter) {
void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter, [ CkPaint? paint ]) {
for (int i = 0; i < _canvases.length; i++) {
_canvases[i]!.saveLayerWithFilter(bounds, filter);
_canvases[i]!.saveLayerWithFilter(bounds, filter, paint);
}
}
......
......@@ -210,12 +210,16 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
/// Pushes a backdrop filter operation onto the operation stack.
///
/// The given filter is applied to the current contents of the scene prior to
/// rasterizing the given objects.
/// rasterizing the child layers.
///
/// The [blendMode] argument is required for [ui.SceneBuilder] compatibility, but is
/// ignored by the DOM renderer.
///
/// See [pop] for details about the operation stack.
@override
ui.BackdropFilterEngineLayer pushBackdropFilter(
ui.ImageFilter filter, {
ui.BlendMode blendMode = ui.BlendMode.srcOver,
ui.BackdropFilterEngineLayer? oldLayer,
}) {
return _pushSurface<PersistedBackdropFilter>(PersistedBackdropFilter(
......
......@@ -79,6 +79,7 @@ abstract class SceneBuilder {
});
BackdropFilterEngineLayer? pushBackdropFilter(
ImageFilter filter, {
BlendMode blendMode = BlendMode.srcOver,
BackdropFilterEngineLayer? oldLayer,
});
ShaderMaskEngineLayer? pushShaderMask(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册