| // 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/backdrop_filter_layer.h" |
| #include "flutter/flow/layers/clip_rect_layer.h" |
| |
| #include "flutter/flow/layers/clip_rect_layer.h" |
| #include "flutter/flow/layers/transform_layer.h" |
| #include "flutter/flow/testing/diff_context_test.h" |
| #include "flutter/flow/testing/layer_test.h" |
| #include "flutter/flow/testing/mock_layer.h" |
| #include "flutter/fml/macros.h" |
| |
| namespace flutter { |
| namespace testing { |
| |
| using BackdropFilterLayerTest = LayerTest; |
| |
| #ifndef NDEBUG |
| TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies) { |
| auto filter = DlBlurImageFilter(5, 5, DlTileMode::kClamp); |
| auto layer = std::make_shared<BackdropFilterLayer>(filter.shared(), |
| DlBlendMode::kSrcOver); |
| auto parent = std::make_shared<ClipRectLayer>(kEmptyRect, Clip::kHardEdge); |
| parent->Add(layer); |
| |
| parent->Preroll(preroll_context()); |
| EXPECT_EQ(layer->paint_bounds(), kEmptyRect); |
| EXPECT_EQ(layer->child_paint_bounds(), kEmptyRect); |
| EXPECT_FALSE(layer->needs_painting(paint_context())); |
| |
| EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), |
| "needs_painting\\(context\\)"); |
| } |
| |
| 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 filter = DlBlurImageFilter(5, 5, DlTileMode::kClamp); |
| auto layer = std::make_shared<BackdropFilterLayer>(filter.shared(), |
| DlBlendMode::kSrcOver); |
| layer->Add(mock_layer); |
| |
| EXPECT_EQ(layer->paint_bounds(), kEmptyRect); |
| EXPECT_EQ(layer->child_paint_bounds(), kEmptyRect); |
| EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), |
| "needs_painting\\(context\\)"); |
| } |
| #endif |
| |
| TEST_F(BackdropFilterLayerTest, EmptyFilter) { |
| 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 DlPaint child_paint = DlPaint(DlColor::kYellow()); |
| auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
| auto layer = |
| std::make_shared<BackdropFilterLayer>(nullptr, DlBlendMode::kSrcOver); |
| layer->Add(mock_layer); |
| auto parent = std::make_shared<ClipRectLayer>(child_bounds, Clip::kHardEdge); |
| parent->Add(layer); |
| |
| preroll_context()->state_stack.set_preroll_delegate(initial_transform); |
| parent->Preroll(preroll_context()); |
| EXPECT_EQ(layer->paint_bounds(), child_bounds); |
| EXPECT_EQ(layer->child_paint_bounds(), child_bounds); |
| EXPECT_TRUE(layer->needs_painting(paint_context())); |
| EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); |
| |
| parent->Paint(display_list_paint_context()); |
| DisplayListBuilder expected_builder; |
| /* (ClipRect)parent::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.ClipRect(child_bounds, DlCanvas::ClipOp::kIntersect, |
| false); |
| /* (BackdropFilter)layer::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.SaveLayer(&child_bounds, nullptr, nullptr); |
| { |
| /* mock_layer::Paint */ { |
| expected_builder.DrawPath(child_path, child_paint); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| expected_builder.Restore(); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); |
| } |
| |
| TEST_F(BackdropFilterLayerTest, SimpleFilter) { |
| 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 DlPaint child_paint = DlPaint(DlColor::kYellow()); |
| auto layer_filter = |
| std::make_shared<DlBlurImageFilter>(2.5, 3.2, DlTileMode::kClamp); |
| auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
| auto layer = std::make_shared<BackdropFilterLayer>(layer_filter, |
| DlBlendMode::kSrcOver); |
| layer->Add(mock_layer); |
| auto parent = std::make_shared<ClipRectLayer>(child_bounds, Clip::kHardEdge); |
| parent->Add(layer); |
| |
| preroll_context()->state_stack.set_preroll_delegate(initial_transform); |
| parent->Preroll(preroll_context()); |
| EXPECT_EQ(layer->paint_bounds(), child_bounds); |
| EXPECT_EQ(layer->child_paint_bounds(), child_bounds); |
| EXPECT_TRUE(layer->needs_painting(paint_context())); |
| EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); |
| |
| parent->Paint(display_list_paint_context()); |
| DisplayListBuilder expected_builder; |
| /* (ClipRect)parent::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.ClipRect(child_bounds, DlCanvas::ClipOp::kIntersect, |
| false); |
| /* (BackdropFilter)layer::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.SaveLayer(&child_bounds, nullptr, |
| layer_filter.get()); |
| { |
| /* mock_layer::Paint */ { |
| expected_builder.DrawPath(child_path, child_paint); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| expected_builder.Restore(); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); |
| } |
| |
| 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 DlPaint child_paint = DlPaint(DlColor::kYellow()); |
| auto layer_filter = |
| std::make_shared<DlBlurImageFilter>(2.5, 3.2, DlTileMode::kClamp); |
| auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
| auto layer = |
| std::make_shared<BackdropFilterLayer>(layer_filter, DlBlendMode::kSrc); |
| layer->Add(mock_layer); |
| auto parent = std::make_shared<ClipRectLayer>(child_bounds, Clip::kHardEdge); |
| parent->Add(layer); |
| |
| preroll_context()->state_stack.set_preroll_delegate(initial_transform); |
| parent->Preroll(preroll_context()); |
| EXPECT_EQ(layer->paint_bounds(), child_bounds); |
| EXPECT_EQ(layer->child_paint_bounds(), child_bounds); |
| EXPECT_TRUE(layer->needs_painting(paint_context())); |
| EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); |
| |
| DlPaint filter_paint = DlPaint(); |
| filter_paint.setBlendMode(DlBlendMode::kSrc); |
| |
| parent->Paint(display_list_paint_context()); |
| DisplayListBuilder expected_builder; |
| /* (ClipRect)parent::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.ClipRect(child_bounds, DlCanvas::ClipOp::kIntersect, |
| false); |
| /* (BackdropFilter)layer::Paint */ { |
| expected_builder.Save(); |
| { |
| DlPaint save_paint = DlPaint().setBlendMode(DlBlendMode::kSrc); |
| expected_builder.SaveLayer(&child_bounds, &save_paint, |
| layer_filter.get()); |
| { |
| /* mock_layer::Paint */ { |
| expected_builder.DrawPath(child_path, child_paint); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| expected_builder.Restore(); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); |
| } |
| |
| 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); |
| const SkPath child_path1 = SkPath().addRect(child_bounds); |
| const SkPath child_path2 = |
| SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f)); |
| const DlPaint child_paint1 = DlPaint(DlColor::kYellow()); |
| const DlPaint child_paint2 = DlPaint(DlColor::kCyan()); |
| SkRect children_bounds = child_path1.getBounds(); |
| children_bounds.join(child_path2.getBounds()); |
| auto layer_filter = |
| std::make_shared<DlBlurImageFilter>(2.5, 3.2, DlTileMode::kClamp); |
| 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, |
| DlBlendMode::kSrcOver); |
| layer->Add(mock_layer1); |
| layer->Add(mock_layer2); |
| auto parent = |
| std::make_shared<ClipRectLayer>(children_bounds, Clip::kHardEdge); |
| parent->Add(layer); |
| |
| preroll_context()->state_stack.set_preroll_delegate(initial_transform); |
| parent->Preroll(preroll_context()); |
| 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_EQ(layer->child_paint_bounds(), children_bounds); |
| EXPECT_TRUE(mock_layer1->needs_painting(paint_context())); |
| EXPECT_TRUE(mock_layer2->needs_painting(paint_context())); |
| EXPECT_TRUE(layer->needs_painting(paint_context())); |
| EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); |
| EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); |
| |
| parent->Paint(display_list_paint_context()); |
| DisplayListBuilder expected_builder; |
| /* (ClipRect)parent::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.ClipRect(children_bounds, DlCanvas::ClipOp::kIntersect, |
| false); |
| /* (BackdropFilter)layer::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.SaveLayer(&children_bounds, nullptr, |
| layer_filter.get()); |
| { |
| /* mock_layer1::Paint */ { |
| expected_builder.DrawPath(child_path1, child_paint1); |
| } |
| /* mock_layer2::Paint */ { |
| expected_builder.DrawPath(child_path2, child_paint2); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| expected_builder.Restore(); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); |
| } |
| |
| TEST_F(BackdropFilterLayerTest, Nested) { |
| const SkMatrix initial_transform = SkMatrix::Translate(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 DlPaint child_paint1 = DlPaint(DlColor::kYellow()); |
| const DlPaint child_paint2 = DlPaint(DlColor::kCyan()); |
| SkRect children_bounds = child_path1.getBounds(); |
| children_bounds.join(child_path2.getBounds()); |
| auto layer_filter1 = |
| std::make_shared<DlBlurImageFilter>(2.5, 3.2, DlTileMode::kClamp); |
| auto layer_filter2 = |
| std::make_shared<DlBlurImageFilter>(2.7, 3.1, DlTileMode::kDecal); |
| 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, |
| DlBlendMode::kSrcOver); |
| auto layer2 = std::make_shared<BackdropFilterLayer>(layer_filter2, |
| DlBlendMode::kSrcOver); |
| layer2->Add(mock_layer2); |
| layer1->Add(mock_layer1); |
| layer1->Add(layer2); |
| auto parent = |
| std::make_shared<ClipRectLayer>(children_bounds, Clip::kHardEdge); |
| parent->Add(layer1); |
| |
| preroll_context()->state_stack.set_preroll_delegate(initial_transform); |
| parent->Preroll(preroll_context()); |
| |
| 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(), children_bounds); |
| EXPECT_TRUE(mock_layer1->needs_painting(paint_context())); |
| EXPECT_TRUE(mock_layer2->needs_painting(paint_context())); |
| EXPECT_TRUE(layer1->needs_painting(paint_context())); |
| EXPECT_TRUE(layer2->needs_painting(paint_context())); |
| EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); |
| EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); |
| |
| parent->Paint(display_list_paint_context()); |
| DisplayListBuilder expected_builder; |
| /* (ClipRect)parent::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.ClipRect(children_bounds, DlCanvas::ClipOp::kIntersect, |
| false); |
| /* (BackdropFilter)layer1::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.SaveLayer(&children_bounds, nullptr, |
| layer_filter1.get()); |
| { |
| /* mock_layer1::Paint */ { |
| expected_builder.DrawPath(child_path1, child_paint1); |
| } |
| /* (BackdropFilter)layer2::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.SaveLayer(&children_bounds, nullptr, |
| layer_filter2.get()); |
| { |
| /* mock_layer2::Paint */ { |
| expected_builder.DrawPath(child_path2, child_paint2); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| expected_builder.Restore(); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| expected_builder.Restore(); |
| } |
| } |
| expected_builder.Restore(); |
| } |
| EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); |
| } |
| |
| TEST_F(BackdropFilterLayerTest, Readback) { |
| std::shared_ptr<DlImageFilter> no_filter; |
| auto layer_filter = DlBlurImageFilter(5, 5, DlTileMode::kClamp); |
| auto initial_transform = SkMatrix(); |
| |
| // BDF with filter always reads from surface |
| auto layer1 = std::make_shared<BackdropFilterLayer>(layer_filter.shared(), |
| DlBlendMode::kSrcOver); |
| preroll_context()->surface_needs_readback = false; |
| preroll_context()->state_stack.set_preroll_delegate(initial_transform); |
| layer1->Preroll(preroll_context()); |
| 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, DlBlendMode::kSrcOver); |
| preroll_context()->surface_needs_readback = false; |
| layer2->Preroll(preroll_context()); |
| EXPECT_FALSE(preroll_context()->surface_needs_readback); |
| |
| // BDF with no filter does not block prior readback value |
| preroll_context()->surface_needs_readback = true; |
| layer2->Preroll(preroll_context()); |
| EXPECT_TRUE(preroll_context()->surface_needs_readback); |
| |
| // BDF with no filter blocks child with readback |
| auto mock_layer = std::make_shared<MockLayer>(SkPath(), DlPaint()); |
| mock_layer->set_fake_reads_surface(true); |
| layer2->Add(mock_layer); |
| preroll_context()->surface_needs_readback = false; |
| layer2->Preroll(preroll_context()); |
| 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 DlPaint mock_paint = DlPaint(DlColor::kRed()); |
| const SkRect clip_rect = SkRect::MakeLTRB(0, 0, 100, 100); |
| |
| auto clip = std::make_shared<ClipRectLayer>(clip_rect, Clip::kHardEdge); |
| 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()); |
| |
| clip->Paint(display_list_paint_context()); |
| |
| DisplayListBuilder expected_builder(clip_rect); |
| /* ClipRectLayer::Paint */ { |
| expected_builder.Save(); |
| { |
| expected_builder.ClipRect(clip_rect, DlCanvas::ClipOp::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) { |
| auto filter = DlBlurImageFilter(10, 10, DlTileMode::kClamp); |
| |
| { |
| // tests later assume 30px readback area, fail early if that's not the case |
| SkIRect readback; |
| EXPECT_EQ(filter.get_input_device_bounds(SkIRect::MakeWH(10, 10), |
| SkMatrix::I(), readback), |
| &readback); |
| EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); |
| } |
| |
| MockLayerTree l1(SkISize::Make(100, 100)); |
| l1.root()->Add(std::make_shared<BackdropFilterLayer>(filter.shared(), |
| DlBlendMode::kSrcOver)); |
| |
| // no clip, effect over entire surface |
| auto damage = DiffLayerTree(l1, MockLayerTree(SkISize::Make(100, 100))); |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeWH(100, 100)); |
| |
| MockLayerTree l2(SkISize::Make(100, 100)); |
| |
| auto clip = std::make_shared<ClipRectLayer>(SkRect::MakeLTRB(20, 20, 60, 60), |
| Clip::kHardEdge); |
| clip->Add(std::make_shared<BackdropFilterLayer>(filter.shared(), |
| DlBlendMode::kSrcOver)); |
| l2.root()->Add(clip); |
| damage = DiffLayerTree(l2, MockLayerTree(SkISize::Make(100, 100))); |
| |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 90, 90)); |
| |
| MockLayerTree l3; |
| auto scale = std::make_shared<TransformLayer>(SkMatrix::Scale(2.0, 2.0)); |
| scale->Add(clip); |
| l3.root()->Add(scale); |
| |
| damage = DiffLayerTree(l3, MockLayerTree()); |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 180, 180)); |
| |
| MockLayerTree l4; |
| l4.root()->Add(scale); |
| |
| // path just outside of readback region, doesn't affect blur |
| auto path1 = SkPath().addRect(SkRect::MakeLTRB(180, 180, 190, 190)); |
| l4.root()->Add(std::make_shared<MockLayer>(path1)); |
| damage = DiffLayerTree(l4, l3); |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(180, 180, 190, 190)); |
| |
| MockLayerTree l5; |
| l5.root()->Add(scale); |
| |
| // path just inside of readback region, must trigger backdrop repaint |
| auto path2 = SkPath().addRect(SkRect::MakeLTRB(179, 179, 189, 189)); |
| l5.root()->Add(std::make_shared<MockLayer>(path2)); |
| damage = DiffLayerTree(l5, l4); |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(0, 0, 190, 190)); |
| } |
| |
| TEST_F(BackdropLayerDiffTest, ReadbackOutsideOfPaintArea) { |
| auto filter = DlMatrixImageFilter(SkMatrix::Translate(50, 50), |
| DlImageSampling::kLinear); |
| |
| MockLayerTree l1(SkISize::Make(100, 100)); |
| |
| auto clip = std::make_shared<ClipRectLayer>(SkRect::MakeLTRB(60, 60, 80, 80), |
| Clip::kHardEdge); |
| clip->Add(std::make_shared<BackdropFilterLayer>(filter.shared(), |
| DlBlendMode::kSrcOver)); |
| l1.root()->Add(clip); |
| auto damage = DiffLayerTree(l1, MockLayerTree(SkISize::Make(100, 100))); |
| |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(60 - 50, 60 - 50, 80, 80)); |
| |
| MockLayerTree l2(SkISize::Make(100, 100)); |
| // path inside readback area must trigger whole readback repaint + filter |
| // repaint. |
| auto path2 = SkPath().addRect(SkRect::MakeXYWH(60 - 50, 60 - 50, 10, 10)); |
| l2.root()->Add(clip); |
| l2.root()->Add(std::make_shared<MockLayer>(path2)); |
| damage = DiffLayerTree(l2, l1); |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(60 - 50, 60 - 50, 80, 80)); |
| } |
| |
| TEST_F(BackdropLayerDiffTest, BackdropLayerInvalidTransform) { |
| auto filter = DlBlurImageFilter(10, 10, DlTileMode::kClamp); |
| |
| { |
| // tests later assume 30px readback area, fail early if that's not the case |
| SkIRect readback; |
| EXPECT_EQ(filter.get_input_device_bounds(SkIRect::MakeWH(10, 10), |
| SkMatrix::I(), readback), |
| &readback); |
| EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); |
| } |
| |
| MockLayerTree l1(SkISize::Make(100, 100)); |
| SkMatrix transform; |
| transform.setPerspX(0.1); |
| transform.setPerspY(0.1); |
| |
| auto transform_layer = std::make_shared<TransformLayer>(transform); |
| l1.root()->Add(transform_layer); |
| transform_layer->Add(std::make_shared<BackdropFilterLayer>( |
| filter.shared(), DlBlendMode::kSrcOver)); |
| |
| auto damage = DiffLayerTree(l1, MockLayerTree(SkISize::Make(100, 100))); |
| EXPECT_EQ(damage.frame_damage, SkIRect::MakeWH(100, 100)); |
| } |
| |
| } // namespace testing |
| } // namespace flutter |