mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Engine support for ImageFiltered widget (#14491)
web_ui support coming in https://github.com/flutter/flutter/issues/47163
This commit is contained in:
parent
bd58af7431
commit
929b1edff5
@ -52,6 +52,9 @@ FILE: ../../../flutter/flow/layers/elevated_container_layer.cc
|
||||
FILE: ../../../flutter/flow/layers/elevated_container_layer.h
|
||||
FILE: ../../../flutter/flow/layers/fuchsia_system_composited_layer.cc
|
||||
FILE: ../../../flutter/flow/layers/fuchsia_system_composited_layer.h
|
||||
FILE: ../../../flutter/flow/layers/image_filter_layer.cc
|
||||
FILE: ../../../flutter/flow/layers/image_filter_layer.h
|
||||
FILE: ../../../flutter/flow/layers/image_filter_layer_unittests.cc
|
||||
FILE: ../../../flutter/flow/layers/layer.cc
|
||||
FILE: ../../../flutter/flow/layers/layer.h
|
||||
FILE: ../../../flutter/flow/layers/layer_tree.cc
|
||||
|
||||
@ -30,6 +30,8 @@ source_set("flow") {
|
||||
"layers/container_layer.h",
|
||||
"layers/elevated_container_layer.cc",
|
||||
"layers/elevated_container_layer.h",
|
||||
"layers/image_filter_layer.cc",
|
||||
"layers/image_filter_layer.h",
|
||||
"layers/layer.cc",
|
||||
"layers/layer.h",
|
||||
"layers/layer_tree.cc",
|
||||
@ -139,6 +141,7 @@ executable("flow_unittests") {
|
||||
"layers/clip_rrect_layer_unittests.cc",
|
||||
"layers/color_filter_layer_unittests.cc",
|
||||
"layers/container_layer_unittests.cc",
|
||||
"layers/image_filter_layer_unittests.cc",
|
||||
"layers/layer_tree_unittests.cc",
|
||||
"layers/opacity_layer_unittests.cc",
|
||||
"layers/performance_overlay_layer_unittests.cc",
|
||||
|
||||
@ -29,7 +29,7 @@ TEST_F(ColorFilterLayerTest, PaintingEmptyLayerDies) {
|
||||
"needs_painting\\(\\)");
|
||||
}
|
||||
|
||||
TEST_F(ColorFilterLayerTest, PaintBeforePreollDies) {
|
||||
TEST_F(ColorFilterLayerTest, 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);
|
||||
|
||||
56
flow/layers/image_filter_layer.cc
Normal file
56
flow/layers/image_filter_layer.cc
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/flow/layers/image_filter_layer.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
ImageFilterLayer::ImageFilterLayer(sk_sp<SkImageFilter> filter)
|
||||
: filter_(std::move(filter)) {}
|
||||
|
||||
void ImageFilterLayer::Preroll(PrerollContext* context,
|
||||
const SkMatrix& matrix) {
|
||||
Layer::AutoPrerollSaveLayerState save =
|
||||
Layer::AutoPrerollSaveLayerState::Create(context);
|
||||
ContainerLayer::Preroll(context, matrix);
|
||||
|
||||
if (!context->has_platform_view && context->raster_cache &&
|
||||
SkRect::Intersects(context->cull_rect, paint_bounds())) {
|
||||
SkMatrix ctm = matrix;
|
||||
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
|
||||
ctm = RasterCache::GetIntegralTransCTM(ctm);
|
||||
#endif
|
||||
context->raster_cache->Prepare(context, this, ctm);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageFilterLayer::Paint(PaintContext& context) const {
|
||||
TRACE_EVENT0("flutter", "ImageFilterLayer::Paint");
|
||||
FML_DCHECK(needs_painting());
|
||||
|
||||
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
|
||||
SkAutoCanvasRestore save(context.leaf_nodes_canvas, true);
|
||||
context.leaf_nodes_canvas->setMatrix(RasterCache::GetIntegralTransCTM(
|
||||
context.leaf_nodes_canvas->getTotalMatrix()));
|
||||
#endif
|
||||
|
||||
if (context.raster_cache) {
|
||||
const SkMatrix& ctm = context.leaf_nodes_canvas->getTotalMatrix();
|
||||
RasterCacheResult layer_cache =
|
||||
context.raster_cache->Get((Layer*)this, ctm);
|
||||
if (layer_cache.is_valid()) {
|
||||
layer_cache.draw(*context.leaf_nodes_canvas);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setImageFilter(filter_);
|
||||
|
||||
Layer::AutoSaveLayer save_layer =
|
||||
Layer::AutoSaveLayer::Create(context, paint_bounds(), &paint);
|
||||
PaintChildren(context);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
30
flow/layers/image_filter_layer.h
Normal file
30
flow/layers/image_filter_layer.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FLOW_LAYERS_IMAGE_FILTER_LAYER_H_
|
||||
#define FLUTTER_FLOW_LAYERS_IMAGE_FILTER_LAYER_H_
|
||||
|
||||
#include "flutter/flow/layers/container_layer.h"
|
||||
|
||||
#include "third_party/skia/include/core/SkImageFilter.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class ImageFilterLayer : public ContainerLayer {
|
||||
public:
|
||||
ImageFilterLayer(sk_sp<SkImageFilter> filter);
|
||||
|
||||
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
|
||||
|
||||
void Paint(PaintContext& context) const override;
|
||||
|
||||
private:
|
||||
sk_sp<SkImageFilter> filter_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ImageFilterLayer);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_FLOW_LAYERS_IMAGE_FILTER_LAYER_H_
|
||||
236
flow/layers/image_filter_layer_unittests.cc
Normal file
236
flow/layers/image_filter_layer_unittests.cc
Normal file
@ -0,0 +1,236 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/flow/layers/image_filter_layer.h"
|
||||
|
||||
#include "flutter/flow/testing/layer_test.h"
|
||||
#include "flutter/flow/testing/mock_layer.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/testing/mock_canvas.h"
|
||||
#include "third_party/skia/include/core/SkImageFilter.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
using ImageFilterLayerTest = LayerTest;
|
||||
|
||||
#ifndef NDEBUG
|
||||
TEST_F(ImageFilterLayerTest, PaintingEmptyLayerDies) {
|
||||
auto layer = std::make_shared<ImageFilterLayer>(sk_sp<SkImageFilter>());
|
||||
|
||||
layer->Preroll(preroll_context(), SkMatrix());
|
||||
EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
|
||||
EXPECT_FALSE(layer->needs_painting());
|
||||
EXPECT_FALSE(layer->needs_system_composite());
|
||||
|
||||
EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
|
||||
"needs_painting\\(\\)");
|
||||
}
|
||||
|
||||
TEST_F(ImageFilterLayerTest, 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<ImageFilterLayer>(sk_sp<SkImageFilter>());
|
||||
layer->Add(mock_layer);
|
||||
|
||||
EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
|
||||
EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
|
||||
"needs_painting\\(\\)");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(ImageFilterLayerTest, EmptyFilter) {
|
||||
const SkMatrix initial_transform = SkMatrix::MakeTrans(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 mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
|
||||
auto layer = std::make_shared<ImageFilterLayer>(nullptr);
|
||||
layer->Add(mock_layer);
|
||||
|
||||
layer->Preroll(preroll_context(), initial_transform);
|
||||
EXPECT_EQ(layer->paint_bounds(), child_bounds);
|
||||
EXPECT_TRUE(layer->needs_painting());
|
||||
EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
|
||||
|
||||
SkPaint filter_paint;
|
||||
filter_paint.setImageFilter(nullptr);
|
||||
layer->Paint(paint_context());
|
||||
EXPECT_EQ(mock_canvas().draw_calls(),
|
||||
std::vector({
|
||||
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}},
|
||||
MockCanvas::DrawCall{
|
||||
1, MockCanvas::SaveLayerData{child_bounds, filter_paint,
|
||||
nullptr, 2}},
|
||||
MockCanvas::DrawCall{
|
||||
2, MockCanvas::DrawPathData{child_path, child_paint}},
|
||||
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}},
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_F(ImageFilterLayerTest, SimpleFilter) {
|
||||
const SkMatrix initial_transform = SkMatrix::MakeTrans(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 = SkImageFilter::MakeMatrixFilter(
|
||||
SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
|
||||
auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint);
|
||||
auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
|
||||
layer->Add(mock_layer);
|
||||
|
||||
layer->Preroll(preroll_context(), initial_transform);
|
||||
EXPECT_EQ(layer->paint_bounds(), child_bounds);
|
||||
EXPECT_TRUE(layer->needs_painting());
|
||||
EXPECT_EQ(mock_layer->parent_matrix(), initial_transform);
|
||||
|
||||
SkPaint filter_paint;
|
||||
filter_paint.setImageFilter(layer_filter);
|
||||
layer->Paint(paint_context());
|
||||
EXPECT_EQ(mock_canvas().draw_calls(),
|
||||
std::vector({
|
||||
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}},
|
||||
MockCanvas::DrawCall{
|
||||
1, MockCanvas::SaveLayerData{child_bounds, filter_paint,
|
||||
nullptr, 2}},
|
||||
MockCanvas::DrawCall{
|
||||
2, MockCanvas::DrawPathData{child_path, child_paint}},
|
||||
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}},
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_F(ImageFilterLayerTest, MultipleChildren) {
|
||||
const SkMatrix initial_transform = SkMatrix::MakeTrans(0.5f, 1.0f);
|
||||
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
|
||||
const SkPath child_path1 = SkPath().addRect(child_bounds);
|
||||
const SkPath child_path2 =
|
||||
SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
|
||||
const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
|
||||
const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
|
||||
auto layer_filter = SkImageFilter::MakeMatrixFilter(
|
||||
SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
|
||||
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<ImageFilterLayer>(layer_filter);
|
||||
layer->Add(mock_layer1);
|
||||
layer->Add(mock_layer2);
|
||||
|
||||
SkRect children_bounds = child_path1.getBounds();
|
||||
children_bounds.join(child_path2.getBounds());
|
||||
layer->Preroll(preroll_context(), initial_transform);
|
||||
EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
|
||||
EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
|
||||
EXPECT_EQ(layer->paint_bounds(), children_bounds);
|
||||
EXPECT_TRUE(mock_layer1->needs_painting());
|
||||
EXPECT_TRUE(mock_layer2->needs_painting());
|
||||
EXPECT_TRUE(layer->needs_painting());
|
||||
EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
|
||||
EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
|
||||
|
||||
SkPaint filter_paint;
|
||||
filter_paint.setImageFilter(layer_filter);
|
||||
layer->Paint(paint_context());
|
||||
EXPECT_EQ(mock_canvas().draw_calls(),
|
||||
std::vector(
|
||||
{MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}},
|
||||
MockCanvas::DrawCall{
|
||||
1, MockCanvas::SaveLayerData{children_bounds, filter_paint,
|
||||
nullptr, 2}},
|
||||
MockCanvas::DrawCall{
|
||||
2, MockCanvas::DrawPathData{child_path1, child_paint1}},
|
||||
MockCanvas::DrawCall{
|
||||
2, MockCanvas::DrawPathData{child_path2, child_paint2}},
|
||||
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}));
|
||||
}
|
||||
|
||||
TEST_F(ImageFilterLayerTest, Nested) {
|
||||
const SkMatrix initial_transform = SkMatrix::MakeTrans(0.5f, 1.0f);
|
||||
const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 2.5f, 3.5f);
|
||||
const SkPath child_path1 = SkPath().addRect(child_bounds);
|
||||
const SkPath child_path2 =
|
||||
SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f));
|
||||
const SkPaint child_paint1 = SkPaint(SkColors::kYellow);
|
||||
const SkPaint child_paint2 = SkPaint(SkColors::kCyan);
|
||||
auto layer_filter1 = SkImageFilter::MakeMatrixFilter(
|
||||
SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
|
||||
auto layer_filter2 = SkImageFilter::MakeMatrixFilter(
|
||||
SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
|
||||
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<ImageFilterLayer>(layer_filter1);
|
||||
auto layer2 = std::make_shared<ImageFilterLayer>(layer_filter2);
|
||||
layer2->Add(mock_layer2);
|
||||
layer1->Add(mock_layer1);
|
||||
layer1->Add(layer2);
|
||||
|
||||
SkRect children_bounds = child_path1.getBounds();
|
||||
children_bounds.join(child_path2.getBounds());
|
||||
layer1->Preroll(preroll_context(), initial_transform);
|
||||
EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
|
||||
EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
|
||||
EXPECT_EQ(layer1->paint_bounds(), children_bounds);
|
||||
EXPECT_EQ(layer2->paint_bounds(), mock_layer2->paint_bounds());
|
||||
EXPECT_TRUE(mock_layer1->needs_painting());
|
||||
EXPECT_TRUE(mock_layer2->needs_painting());
|
||||
EXPECT_TRUE(layer1->needs_painting());
|
||||
EXPECT_TRUE(layer2->needs_painting());
|
||||
EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform);
|
||||
EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform);
|
||||
|
||||
SkPaint filter_paint1, filter_paint2;
|
||||
filter_paint1.setImageFilter(layer_filter1);
|
||||
filter_paint2.setImageFilter(layer_filter2);
|
||||
layer1->Paint(paint_context());
|
||||
EXPECT_EQ(mock_canvas().draw_calls(),
|
||||
std::vector({
|
||||
MockCanvas::DrawCall{0, MockCanvas::SaveData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkMatrix()}},
|
||||
MockCanvas::DrawCall{
|
||||
1, MockCanvas::SaveLayerData{children_bounds, filter_paint1,
|
||||
nullptr, 2}},
|
||||
MockCanvas::DrawCall{
|
||||
2, MockCanvas::DrawPathData{child_path1, child_paint1}},
|
||||
MockCanvas::DrawCall{2, MockCanvas::SaveData{3}},
|
||||
MockCanvas::DrawCall{3, MockCanvas::SetMatrixData{SkMatrix()}},
|
||||
MockCanvas::DrawCall{
|
||||
3, MockCanvas::SaveLayerData{child_path2.getBounds(),
|
||||
filter_paint2, nullptr, 4}},
|
||||
MockCanvas::DrawCall{
|
||||
4, MockCanvas::DrawPathData{child_path2, child_paint2}},
|
||||
MockCanvas::DrawCall{4, MockCanvas::RestoreData{3}},
|
||||
MockCanvas::DrawCall{3, MockCanvas::RestoreData{2}},
|
||||
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
|
||||
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}},
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_F(ImageFilterLayerTest, Readback) {
|
||||
auto layer_filter = SkImageFilter::MakeMatrixFilter(
|
||||
SkMatrix(), SkFilterQuality::kMedium_SkFilterQuality, nullptr);
|
||||
auto initial_transform = SkMatrix();
|
||||
|
||||
// ImageFilterLayer does not read from surface
|
||||
auto layer = std::make_shared<ImageFilterLayer>(layer_filter);
|
||||
preroll_context()->surface_needs_readback = false;
|
||||
layer->Preroll(preroll_context(), initial_transform);
|
||||
EXPECT_FALSE(preroll_context()->surface_needs_readback);
|
||||
|
||||
// ImageFilterLayer blocks child with readback
|
||||
auto mock_layer =
|
||||
std::make_shared<MockLayer>(SkPath(), SkPaint(), false, false, true);
|
||||
layer->Add(mock_layer);
|
||||
preroll_context()->surface_needs_readback = false;
|
||||
layer->Preroll(preroll_context(), initial_transform);
|
||||
EXPECT_FALSE(preroll_context()->surface_needs_readback);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@ -139,6 +139,15 @@ class ColorFilterEngineLayer extends _EngineLayerWrapper {
|
||||
ColorFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
|
||||
}
|
||||
|
||||
/// An opaque handle to an image filter engine layer.
|
||||
///
|
||||
/// Instances of this class are created by [SceneBuilder.pushImageFilter].
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
|
||||
class ImageFilterEngineLayer extends _EngineLayerWrapper {
|
||||
ImageFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
|
||||
}
|
||||
|
||||
/// An opaque handle to a backdrop filter engine layer.
|
||||
///
|
||||
/// Instances of this class are created by [SceneBuilder.pushBackdropFilter].
|
||||
@ -431,6 +440,31 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
|
||||
|
||||
EngineLayer _pushColorFilter(_ColorFilter filter) native 'SceneBuilder_pushColorFilter';
|
||||
|
||||
/// Pushes an image filter operation onto the operation stack.
|
||||
///
|
||||
/// The given filter is applied to the children's rasterization before compositing them into
|
||||
/// the scene.
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayer}
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
|
||||
///
|
||||
/// See [pop] for details about the operation stack.
|
||||
ImageFilterEngineLayer pushImageFilter(
|
||||
ImageFilter filter, {
|
||||
ImageFilterEngineLayer oldLayer,
|
||||
}) {
|
||||
assert(filter != null);
|
||||
assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushImageFilter'));
|
||||
final _ImageFilter nativeFilter = filter._toNativeImageFilter();
|
||||
assert(nativeFilter != null);
|
||||
final ImageFilterEngineLayer layer = ImageFilterEngineLayer._(_pushImageFilter(nativeFilter));
|
||||
assert(_debugPushLayer(layer));
|
||||
return layer;
|
||||
}
|
||||
|
||||
EngineLayer _pushImageFilter(_ImageFilter filter) native 'SceneBuilder_pushImageFilter';
|
||||
|
||||
/// Pushes a backdrop filter operation onto the operation stack.
|
||||
///
|
||||
/// The given filter is applied to the current contents of the scene prior to
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "flutter/flow/layers/clip_rrect_layer.h"
|
||||
#include "flutter/flow/layers/color_filter_layer.h"
|
||||
#include "flutter/flow/layers/container_layer.h"
|
||||
#include "flutter/flow/layers/image_filter_layer.h"
|
||||
#include "flutter/flow/layers/layer.h"
|
||||
#include "flutter/flow/layers/layer_tree.h"
|
||||
#include "flutter/flow/layers/opacity_layer.h"
|
||||
@ -49,6 +50,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, SceneBuilder);
|
||||
V(SceneBuilder, pushClipPath) \
|
||||
V(SceneBuilder, pushOpacity) \
|
||||
V(SceneBuilder, pushColorFilter) \
|
||||
V(SceneBuilder, pushImageFilter) \
|
||||
V(SceneBuilder, pushBackdropFilter) \
|
||||
V(SceneBuilder, pushShaderMask) \
|
||||
V(SceneBuilder, pushPhysicalShape) \
|
||||
@ -152,6 +154,14 @@ fml::RefPtr<EngineLayer> SceneBuilder::pushColorFilter(
|
||||
return EngineLayer::MakeRetained(layer);
|
||||
}
|
||||
|
||||
fml::RefPtr<EngineLayer> SceneBuilder::pushImageFilter(
|
||||
const ImageFilter* image_filter) {
|
||||
auto layer =
|
||||
std::make_shared<flutter::ImageFilterLayer>(image_filter->filter());
|
||||
PushLayer(layer);
|
||||
return EngineLayer::MakeRetained(layer);
|
||||
}
|
||||
|
||||
fml::RefPtr<EngineLayer> SceneBuilder::pushBackdropFilter(ImageFilter* filter) {
|
||||
auto layer = std::make_shared<flutter::BackdropFilterLayer>(filter->filter());
|
||||
PushLayer(layer);
|
||||
|
||||
@ -50,6 +50,7 @@ class SceneBuilder : public RefCountedDartWrappable<SceneBuilder> {
|
||||
int clipBehavior);
|
||||
fml::RefPtr<EngineLayer> pushOpacity(int alpha, double dx = 0, double dy = 0);
|
||||
fml::RefPtr<EngineLayer> pushColorFilter(const ColorFilter* color_filter);
|
||||
fml::RefPtr<EngineLayer> pushImageFilter(const ImageFilter* image_filter);
|
||||
fml::RefPtr<EngineLayer> pushBackdropFilter(ImageFilter* filter);
|
||||
fml::RefPtr<EngineLayer> pushShaderMask(Shader* shader,
|
||||
double maskRectLeft,
|
||||
|
||||
@ -2746,8 +2746,11 @@ class _ColorFilter extends NativeFieldWrapperClass2 {
|
||||
/// See also:
|
||||
///
|
||||
/// * [BackdropFilter], a widget that applies [ImageFilter] to its rendering.
|
||||
/// * [ImageFiltered], a widget that applies [ImageFilter] to its children.
|
||||
/// * [SceneBuilder.pushBackdropFilter], which is the low-level API for using
|
||||
/// this class.
|
||||
/// this class as a backdrop filter.
|
||||
/// * [SceneBuilder.pushImageFilter], which is the low-level API for using
|
||||
/// this class as a child layer filter.
|
||||
class ImageFilter {
|
||||
/// Creates an image filter that applies a Gaussian blur.
|
||||
ImageFilter.blur({ double sigmaX = 0.0, double sigmaY = 0.0 })
|
||||
|
||||
@ -26,7 +26,7 @@ class ImageFilter : public RefCountedDartWrappable<ImageFilter> {
|
||||
void initBlur(double sigma_x, double sigma_y);
|
||||
void initMatrix(const tonic::Float64List& matrix4, int filter_quality);
|
||||
|
||||
const sk_sp<SkImageFilter>& filter() { return filter_; }
|
||||
const sk_sp<SkImageFilter>& filter() const { return filter_; }
|
||||
|
||||
static void RegisterNatives(tonic::DartLibraryNatives* natives);
|
||||
|
||||
|
||||
@ -143,6 +143,14 @@ class LayerSceneBuilder implements ui.SceneBuilder {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
ui.ImageFilterEngineLayer pushImageFilter(
|
||||
ui.ImageFilter filter, {
|
||||
ui.ImageFilterEngineLayer oldLayer,
|
||||
}) {
|
||||
assert(filter != null);
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
ui.OffsetEngineLayer pushOffset(
|
||||
double dx,
|
||||
|
||||
@ -173,6 +173,25 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
/// Pushes an image filter operation onto the operation stack.
|
||||
///
|
||||
/// The given filter is applied to the children's rasterization before compositing them into
|
||||
/// the scene.
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayer}
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
|
||||
///
|
||||
/// See [pop] for details about the operation stack.
|
||||
@override
|
||||
ui.ImageFilterEngineLayer pushImageFilter(
|
||||
ui.ImageFilter filter, {
|
||||
ui.ImageFilterEngineLayer oldLayer,
|
||||
}) {
|
||||
assert(filter != null);
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
/// Pushes a backdrop filter operation onto the operation stack.
|
||||
///
|
||||
/// The given filter is applied to the current contents of the scene prior to
|
||||
|
||||
@ -74,6 +74,13 @@ abstract class OpacityEngineLayer implements EngineLayer {}
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
|
||||
abstract class ColorFilterEngineLayer implements EngineLayer {}
|
||||
|
||||
/// An opaque handle to an image filter engine layer.
|
||||
///
|
||||
/// Instances of this class are created by [SceneBuilder.pushImageFilter].
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
|
||||
abstract class ImageFilterEngineLayer implements EngineLayer {}
|
||||
|
||||
/// An opaque handle to a backdrop filter engine layer.
|
||||
///
|
||||
/// Instances of this class are created by [SceneBuilder.pushBackdropFilter].
|
||||
@ -196,6 +203,21 @@ abstract class SceneBuilder {
|
||||
ColorFilterEngineLayer oldLayer,
|
||||
});
|
||||
|
||||
/// Pushes an image filter operation onto the operation stack.
|
||||
///
|
||||
/// The given filter is applied to the children's rasterization before compositing them into
|
||||
/// the scene.
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayer}
|
||||
///
|
||||
/// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
|
||||
///
|
||||
/// See [pop] for details about the operation stack.
|
||||
ImageFilterEngineLayer pushImageFilter(
|
||||
ImageFilter filter, {
|
||||
ImageFilterEngineLayer oldLayer,
|
||||
});
|
||||
|
||||
/// Pushes a backdrop filter operation onto the operation stack.
|
||||
///
|
||||
/// The given filter is applied to the current contents of the scene prior to
|
||||
|
||||
@ -359,6 +359,23 @@ void main() {
|
||||
oldLayer: oldLayer,
|
||||
);
|
||||
});
|
||||
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
|
||||
return builder.pushImageFilter(
|
||||
ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
|
||||
oldLayer: oldLayer,
|
||||
);
|
||||
});
|
||||
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
|
||||
return builder.pushImageFilter(
|
||||
ImageFilter.matrix(Float64List.fromList(<double>[
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
])),
|
||||
oldLayer: oldLayer,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user