From 42567b1ef322e2deeece82e0ddc8380d2b5a539c Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 19 Nov 2024 14:52:49 -0800 Subject: [PATCH 1/4] [DisplayList] migrate DlImageFilter code to Impeller geometry classes --- ci/licenses_golden/licenses_flutter | 34 + display_list/BUILD.gn | 17 + .../benchmarking/dl_transform_benchmarks.cc | 2 +- display_list/display_list_unittests.cc | 77 +- display_list/dl_builder.cc | 70 +- display_list/dl_builder.h | 24 +- display_list/dl_canvas.h | 5 +- display_list/dl_op_records.h | 1 + display_list/dl_paint.cc | 2 + display_list/dl_paint.h | 6 +- display_list/dl_paint_unittests.cc | 1 + display_list/effects/dl_blur_image_filter.cc | 52 ++ display_list/effects/dl_blur_image_filter.h | 66 ++ .../effects/dl_color_filter_image_filter.cc | 54 ++ .../effects/dl_color_filter_image_filter.h | 78 ++ .../effects/dl_color_source_unittests.cc | 2 +- .../effects/dl_compose_image_filter.cc | 107 +++ .../effects/dl_compose_image_filter.h | 69 ++ .../effects/dl_dilate_image_filter.cc | 45 ++ display_list/effects/dl_dilate_image_filter.h | 59 ++ display_list/effects/dl_erode_image_filter.cc | 45 ++ display_list/effects/dl_erode_image_filter.h | 61 ++ display_list/effects/dl_image_filter.cc | 154 ++-- display_list/effects/dl_image_filter.h | 744 +----------------- .../effects/dl_image_filter_unittests.cc | 498 +++++++----- display_list/effects/dl_image_filters.h | 17 + .../effects/dl_local_matrix_image_filter.cc | 65 ++ .../effects/dl_local_matrix_image_filter.h | 69 ++ .../effects/dl_matrix_image_filter.cc | 60 ++ display_list/effects/dl_matrix_image_filter.h | 61 ++ .../effects/dl_runtime_effect_image_filter.cc | 61 ++ .../effects/dl_runtime_effect_image_filter.h | 80 ++ display_list/geometry/dl_geometry_types.h | 17 +- display_list/skia/dl_sk_canvas.cc | 3 +- display_list/skia/dl_sk_canvas.h | 2 +- display_list/skia/dl_sk_conversions.cc | 6 +- display_list/skia/dl_sk_conversions.h | 3 +- .../skia/dl_sk_conversions_unittests.cc | 9 +- display_list/skia/dl_sk_dispatcher.cc | 4 +- .../skia/dl_sk_paint_dispatcher_unittests.cc | 2 +- .../testing/dl_rendering_unittests.cc | 20 +- display_list/testing/dl_test_snippets.cc | 8 +- display_list/testing/dl_test_snippets.h | 7 +- display_list/utils/dl_matrix_clip_tracker.cc | 2 +- display_list/utils/dl_matrix_clip_tracker.h | 2 +- flow/diff_context.cc | 4 + flow/diff_context.h | 3 + flow/embedded_views.cc | 2 +- flow/embedded_views.h | 12 +- flow/layers/backdrop_filter_layer.cc | 15 +- flow/layers/backdrop_filter_layer.h | 5 +- .../layers/backdrop_filter_layer_unittests.cc | 36 +- flow/layers/image_filter_layer.cc | 23 +- flow/layers/image_filter_layer.h | 6 +- flow/layers/image_filter_layer_unittests.cc | 117 +-- flow/layers/layer_state_stack.cc | 27 +- flow/layers/layer_state_stack.h | 21 +- flow/layers/layer_state_stack_unittests.cc | 24 +- flow/layers/opacity_layer_unittests.cc | 3 +- flow/layers/platform_view_layer_unittests.cc | 2 +- flow/mutators_stack_unittests.cc | 21 +- flow/raster_cache_unittests.cc | 3 +- .../display_list/aiks_dl_basic_unittests.cc | 14 +- .../display_list/aiks_dl_blur_unittests.cc | 23 +- .../aiks_dl_runtime_effect_unittests.cc | 3 +- impeller/display_list/aiks_dl_unittests.cc | 50 +- impeller/display_list/canvas_unittests.cc | 6 +- .../display_list/dl_golden_blur_unittests.cc | 1 + impeller/display_list/dl_golden_unittests.cc | 8 +- impeller/display_list/dl_unittests.cc | 23 +- impeller/display_list/image_filter.cc | 7 +- .../filters/local_matrix_filter_contents.cc | 2 +- .../filters/matrix_filter_contents.cc | 2 +- impeller/geometry/geometry_unittests.cc | 46 ++ impeller/geometry/matrix.cc | 2 +- impeller/geometry/matrix.h | 20 + impeller/geometry/matrix_unittests.cc | 87 ++ impeller/geometry/rect.h | 10 +- impeller/geometry/rect_unittests.cc | 14 + impeller/geometry/vector.h | 5 + impeller/toolkit/interop/dl_builder.cc | 3 +- impeller/toolkit/interop/image_filter.cc | 11 +- impeller/toolkit/interop/image_filter.h | 6 +- lib/ui/painting/canvas.cc | 2 +- lib/ui/painting/fragment_program.cc | 2 +- lib/ui/painting/image_filter.cc | 6 +- lib/ui/painting/image_filter.h | 4 +- lib/ui/painting/matrix.cc | 12 + lib/ui/painting/matrix.h | 3 + .../shell_test_external_view_embedder.cc | 2 +- .../shell_test_external_view_embedder.h | 2 +- shell/common/shell_unittests.cc | 3 +- .../Source/platform_views_controller.h | 2 +- .../Source/platform_views_controller.mm | 2 +- .../darwin/ios/ios_external_view_embedder.h | 2 +- .../darwin/ios/ios_external_view_embedder.mm | 2 +- testing/display_list_testing.cc | 24 +- testing/display_list_testing.h | 14 +- 98 files changed, 2158 insertions(+), 1362 deletions(-) create mode 100644 display_list/effects/dl_blur_image_filter.cc create mode 100644 display_list/effects/dl_blur_image_filter.h create mode 100644 display_list/effects/dl_color_filter_image_filter.cc create mode 100644 display_list/effects/dl_color_filter_image_filter.h create mode 100644 display_list/effects/dl_compose_image_filter.cc create mode 100644 display_list/effects/dl_compose_image_filter.h create mode 100644 display_list/effects/dl_dilate_image_filter.cc create mode 100644 display_list/effects/dl_dilate_image_filter.h create mode 100644 display_list/effects/dl_erode_image_filter.cc create mode 100644 display_list/effects/dl_erode_image_filter.h create mode 100644 display_list/effects/dl_image_filters.h create mode 100644 display_list/effects/dl_local_matrix_image_filter.cc create mode 100644 display_list/effects/dl_local_matrix_image_filter.h create mode 100644 display_list/effects/dl_matrix_image_filter.cc create mode 100644 display_list/effects/dl_matrix_image_filter.h create mode 100644 display_list/effects/dl_runtime_effect_image_filter.cc create mode 100644 display_list/effects/dl_runtime_effect_image_filter.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index c8b2aeae37e3e..d6483c2750ba5 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -42530,16 +42530,33 @@ ORIGIN: ../../../flutter/display_list/dl_storage.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_tile_mode.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_vertices.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/dl_vertices.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_blur_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_blur_image_filter.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_filter.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_color_filter_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_color_filter_image_filter.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_source.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_color_source.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_compose_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_compose_image_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_dilate_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_dilate_image_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_erode_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_erode_image_filter.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_image_filter.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_image_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_image_filters.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_local_matrix_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_local_matrix_image_filter.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_mask_filter.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_mask_filter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_matrix_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_matrix_image_filter.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_runtime_effect.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/effects/dl_runtime_effect.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_runtime_effect_image_filter.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/display_list/effects/dl_runtime_effect_image_filter.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/geometry/dl_geometry_types.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/geometry/dl_path.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/display_list/geometry/dl_path.h + ../../../flutter/LICENSE @@ -45399,16 +45416,33 @@ FILE: ../../../flutter/display_list/dl_storage.h FILE: ../../../flutter/display_list/dl_tile_mode.h FILE: ../../../flutter/display_list/dl_vertices.cc FILE: ../../../flutter/display_list/dl_vertices.h +FILE: ../../../flutter/display_list/effects/dl_blur_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_blur_image_filter.h FILE: ../../../flutter/display_list/effects/dl_color_filter.cc FILE: ../../../flutter/display_list/effects/dl_color_filter.h +FILE: ../../../flutter/display_list/effects/dl_color_filter_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_color_filter_image_filter.h FILE: ../../../flutter/display_list/effects/dl_color_source.cc FILE: ../../../flutter/display_list/effects/dl_color_source.h +FILE: ../../../flutter/display_list/effects/dl_compose_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_compose_image_filter.h +FILE: ../../../flutter/display_list/effects/dl_dilate_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_dilate_image_filter.h +FILE: ../../../flutter/display_list/effects/dl_erode_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_erode_image_filter.h FILE: ../../../flutter/display_list/effects/dl_image_filter.cc FILE: ../../../flutter/display_list/effects/dl_image_filter.h +FILE: ../../../flutter/display_list/effects/dl_image_filters.h +FILE: ../../../flutter/display_list/effects/dl_local_matrix_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_local_matrix_image_filter.h FILE: ../../../flutter/display_list/effects/dl_mask_filter.cc FILE: ../../../flutter/display_list/effects/dl_mask_filter.h +FILE: ../../../flutter/display_list/effects/dl_matrix_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_matrix_image_filter.h FILE: ../../../flutter/display_list/effects/dl_runtime_effect.cc FILE: ../../../flutter/display_list/effects/dl_runtime_effect.h +FILE: ../../../flutter/display_list/effects/dl_runtime_effect_image_filter.cc +FILE: ../../../flutter/display_list/effects/dl_runtime_effect_image_filter.h FILE: ../../../flutter/display_list/geometry/dl_geometry_types.h FILE: ../../../flutter/display_list/geometry/dl_path.cc FILE: ../../../flutter/display_list/geometry/dl_path.h diff --git a/display_list/BUILD.gn b/display_list/BUILD.gn index 48f1fd2341014..a65f4d6dffcff 100644 --- a/display_list/BUILD.gn +++ b/display_list/BUILD.gn @@ -47,16 +47,33 @@ source_set("display_list") { "dl_tile_mode.h", "dl_vertices.cc", "dl_vertices.h", + "effects/dl_blur_image_filter.cc", + "effects/dl_blur_image_filter.h", "effects/dl_color_filter.cc", "effects/dl_color_filter.h", + "effects/dl_color_filter_image_filter.cc", + "effects/dl_color_filter_image_filter.h", "effects/dl_color_source.cc", "effects/dl_color_source.h", + "effects/dl_compose_image_filter.cc", + "effects/dl_compose_image_filter.h", + "effects/dl_dilate_image_filter.cc", + "effects/dl_dilate_image_filter.h", + "effects/dl_erode_image_filter.cc", + "effects/dl_erode_image_filter.h", "effects/dl_image_filter.cc", "effects/dl_image_filter.h", + "effects/dl_image_filters.h", + "effects/dl_local_matrix_image_filter.cc", + "effects/dl_local_matrix_image_filter.h", "effects/dl_mask_filter.cc", "effects/dl_mask_filter.h", + "effects/dl_matrix_image_filter.cc", + "effects/dl_matrix_image_filter.h", "effects/dl_runtime_effect.cc", "effects/dl_runtime_effect.h", + "effects/dl_runtime_effect_image_filter.cc", + "effects/dl_runtime_effect_image_filter.h", "geometry/dl_geometry_types.h", "geometry/dl_path.cc", "geometry/dl_path.h", diff --git a/display_list/benchmarking/dl_transform_benchmarks.cc b/display_list/benchmarking/dl_transform_benchmarks.cc index e6581461be4c3..201efaf4846b3 100644 --- a/display_list/benchmarking/dl_transform_benchmarks.cc +++ b/display_list/benchmarking/dl_transform_benchmarks.cc @@ -457,7 +457,7 @@ class ImpellerMatrixAdapter : public TransformAdapter { bool InvertAndCheck(const TestTransform& transform, TestTransform& result) const override { result.impeller_matrix = transform.impeller_matrix.Invert(); - return transform.impeller_matrix.GetDeterminant() != 0.0f; + return transform.impeller_matrix.IsInvertible(); } }; diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index 6ead9386770ec..7058ac2577f16 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -12,6 +12,7 @@ #include "flutter/display_list/dl_blend_mode.h" #include "flutter/display_list/dl_builder.h" #include "flutter/display_list/dl_paint.h" +#include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/geometry/dl_rtree.h" #include "flutter/display_list/skia/dl_sk_dispatcher.h" #include "flutter/display_list/testing/dl_test_snippets.h" @@ -108,7 +109,7 @@ class DisplayListTestBase : public BaseT { static void check_defaults( DisplayListBuilder& builder, - const SkRect& cull_rect = DisplayListBuilder::kMaxCullRect) { + const DlRect& cull_rect = DisplayListBuilder::kMaxCullRect) { DlPaint builder_paint = DisplayListBuilderTestingAttributes(builder); DlPaint defaults; @@ -131,8 +132,8 @@ class DisplayListTestBase : public BaseT { EXPECT_EQ(builder.GetTransform(), SkMatrix()); EXPECT_EQ(builder.GetTransformFullPerspective(), SkM44()); - EXPECT_EQ(builder.GetLocalClipBounds(), cull_rect); - EXPECT_EQ(builder.GetDestinationClipBounds(), cull_rect); + EXPECT_EQ(builder.GetLocalClipCoverage(), cull_rect); + EXPECT_EQ(builder.GetDestinationClipCoverage(), cull_rect); EXPECT_EQ(builder.GetSaveCount(), 1); } @@ -346,7 +347,7 @@ TEST_F(DisplayListTest, BuilderCanBeReused) { } TEST_F(DisplayListTest, SaveRestoreRestoresTransform) { - SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); + DlRect cull_rect = DlRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); DisplayListBuilder builder(cull_rect); builder.Save(); @@ -395,7 +396,7 @@ TEST_F(DisplayListTest, SaveRestoreRestoresTransform) { } TEST_F(DisplayListTest, BuildRestoresTransform) { - SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); + DlRect cull_rect = DlRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); DisplayListBuilder builder(cull_rect); builder.Translate(10.0f, 10.0f); @@ -436,7 +437,7 @@ TEST_F(DisplayListTest, BuildRestoresTransform) { } TEST_F(DisplayListTest, SaveRestoreRestoresClip) { - SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); + DlRect cull_rect = DlRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); DisplayListBuilder builder(cull_rect); builder.Save(); @@ -456,7 +457,7 @@ TEST_F(DisplayListTest, SaveRestoreRestoresClip) { } TEST_F(DisplayListTest, BuildRestoresClip) { - SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); + DlRect cull_rect = DlRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); DisplayListBuilder builder(cull_rect); builder.ClipRect(SkRect{0.0f, 0.0f, 10.0f, 10.0f}); @@ -473,7 +474,7 @@ TEST_F(DisplayListTest, BuildRestoresClip) { } TEST_F(DisplayListTest, BuildRestoresAttributes) { - SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); + DlRect cull_rect = DlRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f); DisplayListBuilder builder(cull_rect); DlOpReceiver& receiver = ToReceiver(builder); @@ -658,8 +659,8 @@ TEST_F(DisplayListTest, ClippedSaveLayerContentAccountsForFilter) { } TEST_F(DisplayListTest, OOBSaveLayerContentCulledWithBlurFilter) { - SkRect cull_rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); - SkRect draw_rect = SkRect::MakeLTRB(25.0f, 25.0f, 99.0f, 75.0f); + DlRect cull_rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); + DlRect draw_rect = DlRect::MakeLTRB(25.0f, 25.0f, 99.0f, 75.0f); auto filter = DlBlurImageFilter::Make(10.0f, 10.0f, DlTileMode::kDecal); DlPaint layer_paint = DlPaint().setImageFilter(filter); @@ -667,13 +668,13 @@ TEST_F(DisplayListTest, OOBSaveLayerContentCulledWithBlurFilter) { // filtered output might be inside. The drawn rect should be culled by // the expectations of the layer bounds even though it is close enough // to be visible due to filtering. - ASSERT_FALSE(cull_rect.intersects(draw_rect)); - SkRect mapped_rect; + ASSERT_FALSE(cull_rect.IntersectsWithRect(draw_rect)); + DlRect mapped_rect; ASSERT_TRUE(filter->map_local_bounds(draw_rect, mapped_rect)); - ASSERT_TRUE(mapped_rect.intersects(cull_rect)); + ASSERT_TRUE(mapped_rect.IntersectsWithRect(cull_rect)); DisplayListBuilder builder; - builder.SaveLayer(&cull_rect, &layer_paint); + builder.SaveLayer(cull_rect, &layer_paint); { // builder.DrawRect(draw_rect, DlPaint()); } @@ -687,23 +688,23 @@ TEST_F(DisplayListTest, OOBSaveLayerContentCulledWithBlurFilter) { } TEST_F(DisplayListTest, OOBSaveLayerContentCulledWithMatrixFilter) { - SkRect cull_rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); - SkRect draw_rect = SkRect::MakeLTRB(25.0f, 125.0f, 75.0f, 175.0f); - auto filter = DlMatrixImageFilter::Make(SkMatrix::Translate(100.0f, 0.0f), - DlImageSampling::kLinear); + DlRect cull_rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); + DlRect draw_rect = DlRect::MakeLTRB(25.0f, 125.0f, 75.0f, 175.0f); + auto filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({100.0f, 0.0f}), DlImageSampling::kLinear); DlPaint layer_paint = DlPaint().setImageFilter(filter); // We want a draw rect that is outside the layer bounds even though its // filtered output might be inside. The drawn rect should be culled by // the expectations of the layer bounds even though it is close enough // to be visible due to filtering. - ASSERT_FALSE(cull_rect.intersects(draw_rect)); - SkRect mapped_rect; + ASSERT_FALSE(cull_rect.IntersectsWithRect(draw_rect)); + DlRect mapped_rect; ASSERT_TRUE(filter->map_local_bounds(draw_rect, mapped_rect)); - ASSERT_TRUE(mapped_rect.intersects(cull_rect)); + ASSERT_TRUE(mapped_rect.IntersectsWithRect(cull_rect)); DisplayListBuilder builder; - builder.SaveLayer(&cull_rect, &layer_paint); + builder.SaveLayer(cull_rect, &layer_paint); { // builder.DrawRect(draw_rect, DlPaint()); } @@ -4257,8 +4258,9 @@ TEST_F(DisplayListTest, TransformingFilterSaveLayerSimpleContentBounds) { builder.ClipRect(SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f)); DlPaint save_paint; - auto image_filter = DlMatrixImageFilter::Make( - SkMatrix::Translate(100.0f, 100.0f), DlImageSampling::kNearestNeighbor); + auto image_filter = + DlMatrixImageFilter::Make(DlMatrix::MakeTranslation({100.0f, 100.0f}), + DlImageSampling::kNearestNeighbor); save_paint.setImageFilter(image_filter); builder.SaveLayer(nullptr, &save_paint); @@ -4275,8 +4277,9 @@ TEST_F(DisplayListTest, TransformingFilterSaveLayerFloodedContentBounds) { builder.ClipRect(SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f)); DlPaint save_paint; - auto image_filter = DlMatrixImageFilter::Make( - SkMatrix::Translate(100.0f, 100.0f), DlImageSampling::kNearestNeighbor); + auto image_filter = + DlMatrixImageFilter::Make(DlMatrix::MakeTranslation({100.0f, 100.0f}), + DlImageSampling::kNearestNeighbor); save_paint.setImageFilter(image_filter); builder.SaveLayer(nullptr, &save_paint); @@ -5697,9 +5700,9 @@ TEST_F(DisplayListTest, BoundedRenderOpsDoNotReportUnbounded) { } TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { - static const SkRect root_cull = SkRect::MakeLTRB(100, 100, 200, 200); - static const SkRect clip_rect = SkRect::MakeLTRB(120, 120, 180, 180); - static const SkRect draw_rect = SkRect::MakeLTRB(110, 110, 190, 190); + static const DlRect root_cull = DlRect::MakeLTRB(100, 100, 200, 200); + static const DlRect clip_rect = DlRect::MakeLTRB(120, 120, 180, 180); + static const DlRect draw_rect = DlRect::MakeLTRB(110, 110, 190, 190); using Renderer = const std::function; auto test_unbounded = [](const std::string& label, // @@ -5710,7 +5713,7 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { renderer(builder); auto display_list = builder.Build(); - EXPECT_EQ(display_list->bounds(), root_cull) << label; + EXPECT_EQ(display_list->GetBounds(), root_cull) << label; EXPECT_TRUE(display_list->root_is_unbounded()) << label; } @@ -5720,7 +5723,7 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { renderer(builder); auto display_list = builder.Build(); - EXPECT_EQ(display_list->bounds(), clip_rect) << label; + EXPECT_EQ(display_list->GetBounds(), clip_rect) << label; EXPECT_FALSE(display_list->root_is_unbounded()) << label; } @@ -5731,7 +5734,7 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { builder.Restore(); auto display_list = builder.Build(); - EXPECT_EQ(display_list->bounds(), root_cull) << label; + EXPECT_EQ(display_list->GetBounds(), root_cull) << label; EXPECT_FALSE(display_list->root_is_unbounded()) << label; SAVE_LAYER_EXPECTOR(expector); @@ -5754,7 +5757,7 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { builder.Restore(); auto display_list = builder.Build(); - EXPECT_EQ(display_list->bounds(), clip_rect) << label; + EXPECT_EQ(display_list->GetBounds(), clip_rect) << label; EXPECT_FALSE(display_list->root_is_unbounded()) << label; SAVE_LAYER_EXPECTOR(expector); @@ -5783,13 +5786,13 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { }); test_unbounded("DrawPathEvenOddInverted", [](DlCanvas& builder) { - SkPath path = SkPath::Rect(draw_rect); + SkPath path = SkPath::Rect(ToSkRect(draw_rect)); path.setFillType(SkPathFillType::kInverseEvenOdd); builder.DrawPath(path, DlPaint()); }); test_unbounded("DrawPathWindingInverted", [](DlCanvas& builder) { - SkPath path = SkPath::Rect(draw_rect); + SkPath path = SkPath::Rect(ToSkRect(draw_rect)); path.setFillType(SkPathFillType::kInverseWinding); builder.DrawPath(path, DlPaint()); }); @@ -5799,7 +5802,7 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { nested_builder.DrawPaint(DlPaint()); auto nested_display_list = nested_builder.Build(); - EXPECT_EQ(nested_display_list->bounds(), root_cull); + EXPECT_EQ(nested_display_list->GetBounds(), root_cull); ASSERT_TRUE(nested_display_list->root_is_unbounded()); builder.DrawDisplayList(nested_display_list); @@ -5818,7 +5821,7 @@ TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) { // ColorFilter must modify transparent black to be "unbounded" ASSERT_TRUE(unbounded_cf->modifies_transparent_black()); auto unbounded_if = DlColorFilterImageFilter::Make(unbounded_cf); - SkRect output_bounds; + DlRect output_bounds; // ImageFilter returns null from bounds queries if it is "unbounded" ASSERT_EQ(unbounded_if->map_local_bounds(draw_rect, output_bounds), nullptr); diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index c973f0abcfe4d..74c0fc274a14b 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -9,6 +9,7 @@ #include "flutter/display_list/dl_op_flags.h" #include "flutter/display_list/dl_op_records.h" #include "flutter/display_list/effects/dl_color_source.h" +#include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/utils/dl_accumulation_rect.h" #include "fml/logging.h" #include "third_party/skia/include/core/SkScalar.h" @@ -117,12 +118,12 @@ sk_sp DisplayListBuilder::Build() { static constexpr DlRect kEmpty = DlRect(); -static const DlRect& ProtectEmpty(const SkRect& rect) { +static const DlRect& ProtectEmpty(const DlRect& rect) { // isEmpty protects us against NaN while we normalize any empty cull rects - return rect.isEmpty() ? kEmpty : ToDlRect(rect); + return rect.IsEmpty() ? kEmpty : rect; } -DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect, +DisplayListBuilder::DisplayListBuilder(const DlRect& cull_rect, bool prepare_rtree) : original_cull_rect_(ProtectEmpty(cull_rect)) { Init(prepare_rtree); @@ -437,7 +438,7 @@ void DisplayListBuilder::saveLayer(const DlRect& bounds, // A backdrop will affect up to the entire surface, bounded by the clip bool will_be_unbounded = (backdrop != nullptr); - std::shared_ptr filter; + std::shared_ptr filter; if (options.renders_with_attributes()) { if (!paint_nops_on_transparency()) { @@ -485,15 +486,16 @@ void DisplayListBuilder::saveLayer(const DlRect& bounds, // to adjust them so that we cull for the correct input space for the // output of the filter. if (filter) { - SkRect outer_cull_rect = current_info().global_state.device_cull_rect(); - SkMatrix matrix = current_info().global_state.matrix_3x3(); + DlRect outer_cull_rect = + current_info().global_state.GetDeviceCullCoverage(); + DlMatrix matrix = current_info().global_state.matrix(); - SkIRect output_bounds = outer_cull_rect.roundOut(); - SkIRect input_bounds; + DlIRect output_bounds = DlIRect::RoundOut(outer_cull_rect); + DlIRect input_bounds; if (filter->get_input_device_bounds(output_bounds, matrix, input_bounds)) { current_info().global_state.resetDeviceCullRect( - SkRect::Make(input_bounds)); + DlRect::Make(input_bounds)); } else { // Filter could not make any promises about the bounds it needs to // fill the output space, so we use a maximal rect to accumulate @@ -539,7 +541,7 @@ void DisplayListBuilder::saveLayer(const DlRect& bounds, } } } -void DisplayListBuilder::SaveLayer(std::optional& bounds, +void DisplayListBuilder::SaveLayer(const std::optional& bounds, const DlPaint* paint, const DlImageFilter* backdrop, std::optional backdrop_id) { @@ -693,8 +695,8 @@ void DisplayListBuilder::TransferLayerBounds(const SkRect& content_bounds) { // Matrix and Clip for the filter adjustment are the global values from // just before our saveLayer and should still be the current values // present in the parent layer. - const SkRect clip = parent_info().global_state.device_cull_rect(); - const SkMatrix matrix = parent_info().global_state.matrix_3x3(); + const DlRect clip = parent_info().global_state.GetDeviceCullCoverage(); + const DlMatrix matrix = parent_info().global_state.matrix(); if (rtree_data_.has_value()) { // Neither current or parent layer should have any global bounds in @@ -717,15 +719,17 @@ void DisplayListBuilder::TransferLayerBounds(const SkRect& content_bounds) { parent_is_flooded = true; } } else { - SkRect global_bounds = current_layer().global_space_accumulator.bounds(); - if (!global_bounds.isEmpty()) { - SkIRect global_ibounds = global_bounds.roundOut(); + DlRect global_bounds = current_layer().global_space_accumulator.GetBounds(); + if (!global_bounds.IsEmpty()) { + DlIRect global_ibounds = DlIRect::RoundOut(global_bounds); if (!filter->map_device_bounds(global_ibounds, matrix, global_ibounds)) { parent_is_flooded = true; } else { - global_bounds.set(global_ibounds); - if (global_bounds.intersect(clip)) { - parent_layer().global_space_accumulator.accumulate(global_bounds); + global_bounds = DlRect::Make(global_ibounds); + auto clipped_bounds = global_bounds.Intersection(clip); + if (clipped_bounds.has_value()) { + parent_layer().global_space_accumulator.accumulate( + clipped_bounds.value()); } } } @@ -742,7 +746,10 @@ void DisplayListBuilder::TransferLayerBounds(const SkRect& content_bounds) { // run the filter on the content bounds only to discover the same // condition. if (!parent_is_flooded && !bounds_for_parent.isEmpty()) { - if (!filter->map_local_bounds(bounds_for_parent, bounds_for_parent)) { + DlRect mappable_bounds = ToDlRect(bounds_for_parent); + if (filter->map_local_bounds(mappable_bounds, mappable_bounds)) { + bounds_for_parent = ToSkRect(mappable_bounds); + } else { parent_is_flooded = true; } } @@ -765,8 +772,8 @@ void DisplayListBuilder::TransferLayerBounds(const SkRect& content_bounds) { bool DisplayListBuilder::AdjustRTreeRects(RTreeData& data, const DlImageFilter& filter, - const SkMatrix& matrix, - const SkRect& clip, + const DlMatrix& matrix, + const DlRect& clip, size_t rect_start_index) { auto& rects = data.rects; auto& indices = data.indices; @@ -774,17 +781,18 @@ bool DisplayListBuilder::AdjustRTreeRects(RTreeData& data, int ret = false; auto rect_keep = rect_start_index; for (size_t i = rect_start_index; i < rects.size(); i++) { - SkRect bounds = rects[i]; - SkIRect ibounds; - if (filter.map_device_bounds(bounds.roundOut(), matrix, ibounds)) { - bounds.set(ibounds); + DlRect bounds = ToDlRect(rects[i]); + DlIRect ibounds = DlIRect::RoundOut(bounds); + if (filter.map_device_bounds(ibounds, matrix, ibounds)) { + bounds = DlRect::Make(ibounds); } else { bounds = clip; ret = true; } - if (bounds.intersect(clip)) { + auto clipped_bounds = bounds.Intersection(clip); + if (clipped_bounds.has_value()) { indices[rect_keep] = indices[i]; - rects[rect_keep] = bounds; + rects[rect_keep] = ToSkRect(clipped_bounds.value()); rect_keep++; } } @@ -1786,8 +1794,12 @@ bool DisplayListBuilder::AdjustBoundsForPaint(SkRect& bounds, if (flags.applies_image_filter()) { auto filter = current_.getImageFilterPtr(); - if (filter && !filter->map_local_bounds(bounds, bounds)) { - return false; + if (filter) { + DlRect dl_bounds; + if (!filter->map_local_bounds(ToDlRect(bounds), dl_bounds)) { + return false; + } + bounds = ToSkRect(dl_bounds); } } diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index f8132d819d62d..fb7464acc98a5 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -29,17 +29,21 @@ class DisplayListBuilder final : public virtual DlCanvas, virtual DlOpReceiver, DisplayListOpFlags { public: - static constexpr SkRect kMaxCullRect = - SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); + static constexpr DlRect kMaxCullRect = + DlRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); explicit DisplayListBuilder(bool prepare_rtree) : DisplayListBuilder(kMaxCullRect, prepare_rtree) {} - explicit DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect, + explicit DisplayListBuilder(const DlRect& cull_rect = kMaxCullRect, bool prepare_rtree = false); DisplayListBuilder(DlScalar width, DlScalar height) - : DisplayListBuilder(SkRect::MakeWH(width, height)) {} + : DisplayListBuilder(DlRect::MakeWH(width, height)) {} + + explicit DisplayListBuilder(const SkRect& cull_rect, + bool prepare_rtree = false) + : DisplayListBuilder(ToDlRect(cull_rect), prepare_rtree) {} ~DisplayListBuilder(); @@ -52,7 +56,7 @@ class DisplayListBuilder final : public virtual DlCanvas, void Save() override; // |DlCanvas| - void SaveLayer(std::optional& bounds, + void SaveLayer(const std::optional& bounds, const DlPaint* paint = nullptr, const DlImageFilter* backdrop = nullptr, std::optional backdrop_id = std::nullopt) override; @@ -520,14 +524,14 @@ class DisplayListBuilder final : public virtual DlCanvas, }; struct LayerInfo { - LayerInfo(const std::shared_ptr& filter, + LayerInfo(const std::shared_ptr& filter, size_t rtree_rects_start_index) : filter(filter), rtree_rects_start_index(rtree_rects_start_index) {} // The filter that will be applied to the contents of the saveLayer // when it is restored into the parent layer. - const std::shared_ptr filter; + const std::shared_ptr filter; // The index of the rtree rects when the saveLayer was called, used // only in the case that the saveLayer has a filter so that the @@ -590,7 +594,7 @@ class DisplayListBuilder final : public virtual DlCanvas, // For saveLayer calls: explicit SaveInfo(const SaveInfo* parent_info, - const std::shared_ptr& filter, + const std::shared_ptr& filter, int rtree_rect_index) : is_save_layer(true), has_valid_clip(false), @@ -697,8 +701,8 @@ class DisplayListBuilder final : public virtual DlCanvas, void TransferLayerBounds(const SkRect& content_bounds); bool AdjustRTreeRects(RTreeData& data, const DlImageFilter& filter, - const SkMatrix& matrix, - const SkRect& clip, + const DlMatrix& matrix, + const DlRect& clip, size_t rect_index); // This flag indicates whether or not the current rendering attributes diff --git a/display_list/dl_canvas.h b/display_list/dl_canvas.h index e27e4e7c7a192..9139d8e518c54 100644 --- a/display_list/dl_canvas.h +++ b/display_list/dl_canvas.h @@ -60,7 +60,7 @@ class DlCanvas { virtual SkImageInfo GetImageInfo() const = 0; virtual void Save() = 0; - virtual void SaveLayer(std::optional& bounds, + virtual void SaveLayer(const std::optional& bounds, const DlPaint* paint = nullptr, const DlImageFilter* backdrop = nullptr, std::optional backdrop_id = std::nullopt) = 0; @@ -237,8 +237,7 @@ class DlCanvas { const DlPaint* paint = nullptr, const DlImageFilter* backdrop = nullptr, std::optional backdrop_id = std::nullopt) { - auto optional_bounds = ToOptDlRect(bounds); - SaveLayer(optional_bounds, paint, backdrop, backdrop_id); + SaveLayer(ToOptDlRect(bounds), paint, backdrop, backdrop_id); } void Transform(const SkMatrix* matrix) { diff --git a/display_list/dl_op_records.h b/display_list/dl_op_records.h index ca8e5156d2559..b977c2d269117 100644 --- a/display_list/dl_op_records.h +++ b/display_list/dl_op_records.h @@ -10,6 +10,7 @@ #include "flutter/display_list/dl_op_receiver.h" #include "flutter/display_list/dl_sampling_options.h" #include "flutter/display_list/effects/dl_color_source.h" +#include "flutter/display_list/utils/dl_comparable.h" #include "flutter/fml/macros.h" #include "flutter/impeller/geometry/path.h" diff --git a/display_list/dl_paint.cc b/display_list/dl_paint.cc index 498f2ec2e8fda..76a682eab9967 100644 --- a/display_list/dl_paint.cc +++ b/display_list/dl_paint.cc @@ -4,6 +4,8 @@ #include "flutter/display_list/dl_paint.h" +#include "flutter/display_list/utils/dl_comparable.h" + namespace flutter { DlPaint::DlPaint(DlColor color) diff --git a/display_list/dl_paint.h b/display_list/dl_paint.h index 62bf15a04c52f..ca5e69aa50811 100644 --- a/display_list/dl_paint.h +++ b/display_list/dl_paint.h @@ -150,11 +150,11 @@ class DlPaint { return *this; } - std::shared_ptr getImageFilter() const { + std::shared_ptr getImageFilter() const { return image_filter_; } const DlImageFilter* getImageFilterPtr() const { return image_filter_.get(); } - DlPaint& setImageFilter(const std::shared_ptr& filter) { + DlPaint& setImageFilter(const std::shared_ptr& filter) { image_filter_ = filter; return *this; } @@ -212,7 +212,7 @@ class DlPaint { std::shared_ptr color_source_; std::shared_ptr color_filter_; - std::shared_ptr image_filter_; + std::shared_ptr image_filter_; std::shared_ptr mask_filter_; }; diff --git a/display_list/dl_paint_unittests.cc b/display_list/dl_paint_unittests.cc index 4974a209a7052..f3b27727b05db 100644 --- a/display_list/dl_paint_unittests.cc +++ b/display_list/dl_paint_unittests.cc @@ -4,6 +4,7 @@ #include "flutter/display_list/dl_paint.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/display_list/utils/dl_comparable.h" #include "gtest/gtest.h" diff --git a/display_list/effects/dl_blur_image_filter.cc b/display_list/effects/dl_blur_image_filter.cc new file mode 100644 index 0000000000000..a45a083579cde --- /dev/null +++ b/display_list/effects/dl_blur_image_filter.cc @@ -0,0 +1,52 @@ +// 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/display_list/effects/dl_blur_image_filter.h" + +namespace flutter { + +std::shared_ptr DlBlurImageFilter::Make(DlScalar sigma_x, + DlScalar sigma_y, + DlTileMode tile_mode) { + if (!std::isfinite(sigma_x) || !std::isfinite(sigma_y)) { + return nullptr; + } + if (sigma_x < SK_ScalarNearlyZero && sigma_y < SK_ScalarNearlyZero) { + return nullptr; + } + sigma_x = (sigma_x < SK_ScalarNearlyZero) ? 0 : sigma_x; + sigma_y = (sigma_y < SK_ScalarNearlyZero) ? 0 : sigma_y; + return std::make_shared(sigma_x, sigma_y, tile_mode); +} + +DlRect* DlBlurImageFilter::map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const { + output_bounds = input_bounds.Expand(sigma_x_ * 3.0f, sigma_y_ * 3.0f); + return &output_bounds; +} + +DlIRect* DlBlurImageFilter::map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + return outset_device_bounds(input_bounds, sigma_x_ * 3.0f, sigma_y_ * 3.0f, + ctm, output_bounds); +} + +DlIRect* DlBlurImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + // Blurs are symmetric in terms of output-for-input and input-for-output + return map_device_bounds(output_bounds, ctm, input_bounds); +} + +bool DlBlurImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kBlur); + auto that = static_cast(&other); + return (DlScalarNearlyEqual(sigma_x_, that->sigma_x_) && + DlScalarNearlyEqual(sigma_y_, that->sigma_y_) && + tile_mode_ == that->tile_mode_); +} + +} // namespace flutter diff --git a/display_list/effects/dl_blur_image_filter.h b/display_list/effects/dl_blur_image_filter.h new file mode 100644 index 0000000000000..090334ad9dbcf --- /dev/null +++ b/display_list/effects/dl_blur_image_filter.h @@ -0,0 +1,66 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_BLUR_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_BLUR_IMAGE_FILTER_H_ + +#include "flutter/display_list/effects/dl_image_filter.h" + +#include "flutter/display_list/dl_tile_mode.h" + +namespace flutter { + +class DlBlurImageFilter final : public DlImageFilter { + public: + DlBlurImageFilter(DlScalar sigma_x, DlScalar sigma_y, DlTileMode tile_mode) + : sigma_x_(sigma_x), sigma_y_(sigma_y), tile_mode_(tile_mode) {} + explicit DlBlurImageFilter(const DlBlurImageFilter* filter) + : DlBlurImageFilter(filter->sigma_x_, + filter->sigma_y_, + filter->tile_mode_) {} + DlBlurImageFilter(const DlBlurImageFilter& filter) + : DlBlurImageFilter(&filter) {} + + static std::shared_ptr Make(DlScalar sigma_x, + DlScalar sigma_y, + DlTileMode tile_mode); + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + DlImageFilterType type() const override { return DlImageFilterType::kBlur; } + size_t size() const override { return sizeof(*this); } + + const DlBlurImageFilter* asBlur() const override { return this; } + + bool modifies_transparent_black() const override { return false; } + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + DlScalar sigma_x() const { return sigma_x_; } + DlScalar sigma_y() const { return sigma_y_; } + DlTileMode tile_mode() const { return tile_mode_; } + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + DlScalar sigma_x_; + DlScalar sigma_y_; + DlTileMode tile_mode_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_BLUR_IMAGE_FILTER_H_ diff --git a/display_list/effects/dl_color_filter_image_filter.cc b/display_list/effects/dl_color_filter_image_filter.cc new file mode 100644 index 0000000000000..f06efc884d2b5 --- /dev/null +++ b/display_list/effects/dl_color_filter_image_filter.cc @@ -0,0 +1,54 @@ +// 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/display_list/effects/dl_color_filter_image_filter.h" + +#include "flutter/display_list/utils/dl_comparable.h" + +namespace flutter { + +std::shared_ptr DlColorFilterImageFilter::Make( + const std::shared_ptr& filter) { + if (filter) { + return std::make_shared(filter); + } + return nullptr; +} + +bool DlColorFilterImageFilter::modifies_transparent_black() const { + if (color_filter_) { + return color_filter_->modifies_transparent_black(); + } + return false; +} + +DlRect* DlColorFilterImageFilter::map_local_bounds( + const DlRect& input_bounds, + DlRect& output_bounds) const { + output_bounds = input_bounds; + return modifies_transparent_black() ? nullptr : &output_bounds; +} + +DlIRect* DlColorFilterImageFilter::map_device_bounds( + const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + output_bounds = input_bounds; + return modifies_transparent_black() ? nullptr : &output_bounds; +} + +DlIRect* DlColorFilterImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + return map_device_bounds(output_bounds, ctm, input_bounds); +} + +bool DlColorFilterImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kColorFilter); + auto that = static_cast(&other); + return Equals(color_filter_, that->color_filter_); +} + +} // namespace flutter diff --git a/display_list/effects/dl_color_filter_image_filter.h b/display_list/effects/dl_color_filter_image_filter.h new file mode 100644 index 0000000000000..845586d48f69c --- /dev/null +++ b/display_list/effects/dl_color_filter_image_filter.h @@ -0,0 +1,78 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_COLOR_FILTER_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_COLOR_FILTER_IMAGE_FILTER_H_ + +#include "display_list/effects/dl_image_filter.h" + +#include "flutter/display_list/effects/dl_color_filter.h" + +namespace flutter { + +class DlColorFilterImageFilter final : public DlImageFilter { + public: + explicit DlColorFilterImageFilter(std::shared_ptr filter) + : color_filter_(std::move(filter)) {} + explicit DlColorFilterImageFilter(const DlColorFilter* filter) + : color_filter_(filter->shared()) {} + explicit DlColorFilterImageFilter(const DlColorFilter& filter) + : color_filter_(filter.shared()) {} + explicit DlColorFilterImageFilter(const DlColorFilterImageFilter* filter) + : DlColorFilterImageFilter(filter->color_filter_) {} + DlColorFilterImageFilter(const DlColorFilterImageFilter& filter) + : DlColorFilterImageFilter(&filter) {} + + static std::shared_ptr Make( + const std::shared_ptr& filter); + + std::shared_ptr shared() const override { + return std::make_shared(color_filter_); + } + + DlImageFilterType type() const override { + return DlImageFilterType::kColorFilter; + } + size_t size() const override { return sizeof(*this); } + + const std::shared_ptr color_filter() const { + return color_filter_; + } + + const DlColorFilterImageFilter* asColorFilter() const override { + return this; + } + + bool modifies_transparent_black() const override; + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + MatrixCapability matrix_capability() const override { + return MatrixCapability::kComplex; + } + + std::shared_ptr makeWithLocalMatrix( + const DlMatrix& matrix) const override { + return shared(); + } + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + std::shared_ptr color_filter_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_COLOR_FILTER_IMAGE_FILTER_H_ diff --git a/display_list/effects/dl_color_source_unittests.cc b/display_list/effects/dl_color_source_unittests.cc index 6fc0aac4cddb4..1dcfda7b40313 100644 --- a/display_list/effects/dl_color_source_unittests.cc +++ b/display_list/effects/dl_color_source_unittests.cc @@ -5,7 +5,7 @@ #include #include -#include "display_list/dl_color.h" +#include "flutter/display_list/dl_color.h" #include "flutter/display_list/dl_sampling_options.h" #include "flutter/display_list/effects/dl_color_source.h" #include "flutter/display_list/effects/dl_runtime_effect.h" diff --git a/display_list/effects/dl_compose_image_filter.cc b/display_list/effects/dl_compose_image_filter.cc new file mode 100644 index 0000000000000..73ea92b547c2a --- /dev/null +++ b/display_list/effects/dl_compose_image_filter.cc @@ -0,0 +1,107 @@ +// 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/display_list/effects/dl_compose_image_filter.h" + +#include "flutter/display_list/utils/dl_comparable.h" + +namespace flutter { + +std::shared_ptr DlComposeImageFilter::Make( + const std::shared_ptr& outer, + const std::shared_ptr& inner) { + if (!outer) { + return inner; + } + if (!inner) { + return outer; + } + return std::make_shared(outer, inner); +} + +bool DlComposeImageFilter::modifies_transparent_black() const { + if (inner_ && inner_->modifies_transparent_black()) { + return true; + } + if (outer_ && outer_->modifies_transparent_black()) { + return true; + } + return false; +} + +DlRect* DlComposeImageFilter::map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const { + DlRect cur_bounds = input_bounds; + DlRect* ret = &output_bounds; + // We set this result in case neither filter is present. + output_bounds = input_bounds; + if (inner_) { + if (!inner_->map_local_bounds(cur_bounds, output_bounds)) { + ret = nullptr; + } + cur_bounds = output_bounds; + } + if (outer_) { + if (!outer_->map_local_bounds(cur_bounds, output_bounds)) { + ret = nullptr; + } + } + return ret; +} + +DlIRect* DlComposeImageFilter::map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + DlIRect cur_bounds = input_bounds; + DlIRect* ret = &output_bounds; + // We set this result in case neither filter is present. + output_bounds = input_bounds; + if (inner_) { + if (!inner_->map_device_bounds(cur_bounds, ctm, output_bounds)) { + ret = nullptr; + } + cur_bounds = output_bounds; + } + if (outer_) { + if (!outer_->map_device_bounds(cur_bounds, ctm, output_bounds)) { + ret = nullptr; + } + } + return ret; +} + +DlIRect* DlComposeImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + DlIRect cur_bounds = output_bounds; + DlIRect* ret = &input_bounds; + // We set this result in case neither filter is present. + input_bounds = output_bounds; + if (outer_) { + if (!outer_->get_input_device_bounds(cur_bounds, ctm, input_bounds)) { + ret = nullptr; + } + cur_bounds = input_bounds; + } + if (inner_) { + if (!inner_->get_input_device_bounds(cur_bounds, ctm, input_bounds)) { + ret = nullptr; + } + } + return ret; +} + +DlImageFilter::MatrixCapability DlComposeImageFilter::matrix_capability() + const { + return std::min(outer_->matrix_capability(), inner_->matrix_capability()); +} + +bool DlComposeImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kCompose); + auto that = static_cast(&other); + return (Equals(outer_, that->outer_) && Equals(inner_, that->inner_)); +} + +} // namespace flutter diff --git a/display_list/effects/dl_compose_image_filter.h b/display_list/effects/dl_compose_image_filter.h new file mode 100644 index 0000000000000..a66eb9cf07f89 --- /dev/null +++ b/display_list/effects/dl_compose_image_filter.h @@ -0,0 +1,69 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_COMPOSE_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_COMPOSE_IMAGE_FILTER_H_ + +#include "display_list/effects/dl_image_filter.h" + +namespace flutter { + +class DlComposeImageFilter final : public DlImageFilter { + public: + DlComposeImageFilter(const std::shared_ptr& outer, + const std::shared_ptr& inner) + : outer_(outer), inner_(inner) {} + DlComposeImageFilter(const DlImageFilter* outer, const DlImageFilter* inner) + : outer_(outer->shared()), inner_(inner->shared()) {} + DlComposeImageFilter(const DlImageFilter& outer, const DlImageFilter& inner) + : DlComposeImageFilter(&outer, &inner) {} + explicit DlComposeImageFilter(const DlComposeImageFilter* filter) + : DlComposeImageFilter(filter->outer_, filter->inner_) {} + DlComposeImageFilter(const DlComposeImageFilter& filter) + : DlComposeImageFilter(&filter) {} + + static std::shared_ptr Make( + const std::shared_ptr& outer, + const std::shared_ptr& inner); + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + DlImageFilterType type() const override { + return DlImageFilterType::kCompose; + } + size_t size() const override { return sizeof(*this); } + + std::shared_ptr outer() const { return outer_; } + std::shared_ptr inner() const { return inner_; } + + const DlComposeImageFilter* asCompose() const override { return this; } + + bool modifies_transparent_black() const override; + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + MatrixCapability matrix_capability() const override; + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + const std::shared_ptr outer_; + const std::shared_ptr inner_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_COMPOSE_IMAGE_FILTER_H_ diff --git a/display_list/effects/dl_dilate_image_filter.cc b/display_list/effects/dl_dilate_image_filter.cc new file mode 100644 index 0000000000000..89523e95a2299 --- /dev/null +++ b/display_list/effects/dl_dilate_image_filter.cc @@ -0,0 +1,45 @@ +// 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/display_list/effects/dl_dilate_image_filter.h" + +namespace flutter { + +std::shared_ptr DlDilateImageFilter::Make(DlScalar radius_x, + DlScalar radius_y) { + if (std::isfinite(radius_x) && radius_x > SK_ScalarNearlyZero && + std::isfinite(radius_y) && radius_y > SK_ScalarNearlyZero) { + return std::make_shared(radius_x, radius_y); + } + return nullptr; +} + +DlRect* DlDilateImageFilter::map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const { + output_bounds = input_bounds.Expand(radius_x_, radius_y_); + return &output_bounds; +} + +DlIRect* DlDilateImageFilter::map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + return outset_device_bounds(input_bounds, radius_x_, radius_y_, ctm, + output_bounds); +} + +DlIRect* DlDilateImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + return inset_device_bounds(output_bounds, radius_x_, radius_y_, ctm, + input_bounds); +} + +bool DlDilateImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kDilate); + auto that = static_cast(&other); + return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_); +} + +} // namespace flutter diff --git a/display_list/effects/dl_dilate_image_filter.h b/display_list/effects/dl_dilate_image_filter.h new file mode 100644 index 0000000000000..003f3092d67fd --- /dev/null +++ b/display_list/effects/dl_dilate_image_filter.h @@ -0,0 +1,59 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_DILATE_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_DILATE_IMAGE_FILTER_H_ + +#include "display_list/effects/dl_image_filter.h" + +namespace flutter { + +class DlDilateImageFilter final : public DlImageFilter { + public: + DlDilateImageFilter(DlScalar radius_x, DlScalar radius_y) + : radius_x_(radius_x), radius_y_(radius_y) {} + explicit DlDilateImageFilter(const DlDilateImageFilter* filter) + : DlDilateImageFilter(filter->radius_x_, filter->radius_y_) {} + DlDilateImageFilter(const DlDilateImageFilter& filter) + : DlDilateImageFilter(&filter) {} + + static std::shared_ptr Make(DlScalar radius_x, + DlScalar radius_y); + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + DlImageFilterType type() const override { return DlImageFilterType::kDilate; } + size_t size() const override { return sizeof(*this); } + + const DlDilateImageFilter* asDilate() const override { return this; } + + bool modifies_transparent_black() const override { return false; } + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + DlScalar radius_x() const { return radius_x_; } + DlScalar radius_y() const { return radius_y_; } + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + DlScalar radius_x_; + DlScalar radius_y_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_DILATE_IMAGE_FILTER_H_ diff --git a/display_list/effects/dl_erode_image_filter.cc b/display_list/effects/dl_erode_image_filter.cc new file mode 100644 index 0000000000000..71538b7d1f2e2 --- /dev/null +++ b/display_list/effects/dl_erode_image_filter.cc @@ -0,0 +1,45 @@ +// 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/display_list/effects/dl_erode_image_filter.h" + +namespace flutter { + +std::shared_ptr DlErodeImageFilter::Make(DlScalar radius_x, + DlScalar radius_y) { + if (std::isfinite(radius_x) && radius_x > SK_ScalarNearlyZero && + std::isfinite(radius_y) && radius_y > SK_ScalarNearlyZero) { + return std::make_shared(radius_x, radius_y); + } + return nullptr; +} + +DlRect* DlErodeImageFilter::map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const { + output_bounds = input_bounds.Expand(-radius_x_, -radius_y_); + return &output_bounds; +} + +DlIRect* DlErodeImageFilter::map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + return inset_device_bounds(input_bounds, radius_x_, radius_y_, ctm, + output_bounds); +} + +DlIRect* DlErodeImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + return outset_device_bounds(output_bounds, radius_x_, radius_y_, ctm, + input_bounds); +} + +bool DlErodeImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kErode); + auto that = static_cast(&other); + return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_); +} + +} // namespace flutter diff --git a/display_list/effects/dl_erode_image_filter.h b/display_list/effects/dl_erode_image_filter.h new file mode 100644 index 0000000000000..9cd28488237c4 --- /dev/null +++ b/display_list/effects/dl_erode_image_filter.h @@ -0,0 +1,61 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_ERODE_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_ERODE_IMAGE_FILTER_H_ + +#include + +#include "display_list/effects/dl_image_filter.h" + +namespace flutter { + +class DlErodeImageFilter final : public DlImageFilter { + public: + DlErodeImageFilter(DlScalar radius_x, DlScalar radius_y) + : radius_x_(radius_x), radius_y_(radius_y) {} + explicit DlErodeImageFilter(const DlErodeImageFilter* filter) + : DlErodeImageFilter(filter->radius_x_, filter->radius_y_) {} + DlErodeImageFilter(const DlErodeImageFilter& filter) + : DlErodeImageFilter(&filter) {} + + static std::shared_ptr Make(DlScalar radius_x, + DlScalar radius_y); + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + DlImageFilterType type() const override { return DlImageFilterType::kErode; } + size_t size() const override { return sizeof(*this); } + + const DlErodeImageFilter* asErode() const override { return this; } + + bool modifies_transparent_black() const override { return false; } + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + DlScalar radius_x() const { return radius_x_; } + DlScalar radius_y() const { return radius_y_; } + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + DlScalar radius_x_; + DlScalar radius_y_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_ERODE_IMAGE_FILTER_H_ diff --git a/display_list/effects/dl_image_filter.cc b/display_list/effects/dl_image_filter.cc index 7f0481f0562e0..c3fdac00602e4 100644 --- a/display_list/effects/dl_image_filter.cc +++ b/display_list/effects/dl_image_filter.cc @@ -4,24 +4,105 @@ #include "flutter/display_list/effects/dl_image_filter.h" +#include "flutter/display_list/effects/dl_local_matrix_image_filter.h" + namespace flutter { +DlVector2 DlImageFilter::map_vectors_affine(const DlMatrix& ctm, + DlScalar x, + DlScalar y) { + FML_DCHECK(std::isfinite(x) && x >= 0); + FML_DCHECK(std::isfinite(y) && y >= 0); + FML_DCHECK(ctm.IsFinite() && !ctm.HasPerspective2D()); + + // The x and y scalars would have been used to expand a local space + // rectangle which is then transformed by ctm. In order to do the + // expansion correctly, we should look at the relevant math. The + // 4 corners will be moved outward by the following vectors: + // (UL,UR,LR,LL) = ((-x, -y), (+x, -y), (+x, +y), (-x, +y)) + // After applying the transform, each of these vectors could be + // pointing in any direction so we need to examine each transformed + // delta vector and how it affected the bounds. + // Looking at just the affine 2x3 entries of the CTM we can delta + // transform these corner offsets and get the following: + // UL = dCTM(-x, -y) = (- x*m00 - y*m01, - x*m10 - y*m11) + // UR = dCTM(+x, -y) = ( x*m00 - y*m01, x*m10 - y*m11) + // LR = dCTM(+x, +y) = ( x*m00 + y*m01, x*m10 + y*m11) + // LL = dCTM(-x, +y) = (- x*m00 + y*m01, - x*m10 + y*m11) + // The X vectors are all some variation of adding or subtracting + // the sum of x*m00 and y*m01 or their difference. Similarly the Y + // vectors are +/- the associated sum/difference of x*m10 and y*m11. + // The largest displacements, both left/right or up/down, will + // happen when the signs of the m00/m01/m10/m11 matrix entries + // coincide with the signs of the scalars, i.e. are all positive. + return {x * abs(ctm.m[0]) + y * abs(ctm.m[4]), + x * abs(ctm.m[1]) + y * abs(ctm.m[5])}; +} + +DlIRect* DlImageFilter::inset_device_bounds(const DlIRect& input_bounds, + DlScalar radius_x, + DlScalar radius_y, + const DlMatrix& ctm, + DlIRect& output_bounds) { + if (ctm.IsFinite() && ctm.IsInvertible()) { + if (ctm.HasPerspective2D()) { + DlRect local_bounds = DlRect::Make(input_bounds) + .TransformAndClipBounds(ctm.Invert()) + .Expand(-radius_x, -radius_y); + output_bounds = + DlIRect::RoundOut(local_bounds.TransformAndClipBounds(ctm)); + return &output_bounds; + } else { + DlVector2 device_radius = map_vectors_affine(ctm, radius_x, radius_y); + output_bounds = + input_bounds.Expand(-floor(device_radius.x), -floor(device_radius.y)); + return &output_bounds; + } + } + output_bounds = input_bounds; + return nullptr; +} + +DlIRect* DlImageFilter::outset_device_bounds(const DlIRect& input_bounds, + DlScalar radius_x, + DlScalar radius_y, + const DlMatrix& ctm, + DlIRect& output_bounds) { + if (ctm.IsFinite() && ctm.IsInvertible()) { + if (ctm.HasPerspective2D()) { + DlRect local_bounds = DlRect::Make(input_bounds) + .TransformAndClipBounds(ctm.Invert()) + .Expand(radius_x, radius_y); + output_bounds = + DlIRect::RoundOut(local_bounds.TransformAndClipBounds(ctm)); + return &output_bounds; + } else { + DlVector2 device_radius = map_vectors_affine(ctm, radius_x, radius_y); + output_bounds = + input_bounds.Expand(ceil(device_radius.x), ceil(device_radius.y)); + return &output_bounds; + } + } + output_bounds = input_bounds; + return nullptr; +} + std::shared_ptr DlImageFilter::makeWithLocalMatrix( - const SkMatrix& matrix) const { - if (matrix.isIdentity()) { + const DlMatrix& matrix) const { + if (matrix.IsIdentity()) { return shared(); } // Matrix switch (this->matrix_capability()) { case MatrixCapability::kTranslate: { - if (!matrix.isTranslate()) { + if (!matrix.IsTranslationOnly()) { // Nothing we can do at this point return nullptr; } break; } case MatrixCapability::kScaleTranslate: { - if (!matrix.isScaleTranslate()) { + if (!matrix.IsTranslationScaleOnly()) { // Nothing we can do at this point return nullptr; } @@ -30,70 +111,7 @@ std::shared_ptr DlImageFilter::makeWithLocalMatrix( default: break; } - return std::make_shared(matrix, shared()); -} - -SkRect* DlComposeImageFilter::map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const { - SkRect cur_bounds = input_bounds; - SkRect* ret = &output_bounds; - // We set this result in case neither filter is present. - output_bounds = input_bounds; - if (inner_) { - if (!inner_->map_local_bounds(cur_bounds, output_bounds)) { - ret = nullptr; - } - cur_bounds = output_bounds; - } - if (outer_) { - if (!outer_->map_local_bounds(cur_bounds, output_bounds)) { - ret = nullptr; - } - } - return ret; -} - -SkIRect* DlComposeImageFilter::map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const { - SkIRect cur_bounds = input_bounds; - SkIRect* ret = &output_bounds; - // We set this result in case neither filter is present. - output_bounds = input_bounds; - if (inner_) { - if (!inner_->map_device_bounds(cur_bounds, ctm, output_bounds)) { - ret = nullptr; - } - cur_bounds = output_bounds; - } - if (outer_) { - if (!outer_->map_device_bounds(cur_bounds, ctm, output_bounds)) { - ret = nullptr; - } - } - return ret; -} - -SkIRect* DlComposeImageFilter::get_input_device_bounds( - const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const { - SkIRect cur_bounds = output_bounds; - SkIRect* ret = &input_bounds; - // We set this result in case neither filter is present. - input_bounds = output_bounds; - if (outer_) { - if (!outer_->get_input_device_bounds(cur_bounds, ctm, input_bounds)) { - ret = nullptr; - } - cur_bounds = input_bounds; - } - if (inner_) { - if (!inner_->get_input_device_bounds(cur_bounds, ctm, input_bounds)) { - ret = nullptr; - } - } - return ret; + return DlLocalMatrixImageFilter::Make(matrix, shared()); } } // namespace flutter diff --git a/display_list/effects/dl_image_filter.h b/display_list/effects/dl_image_filter.h index 0aa85d0f6b3bc..50b3444b03833 100644 --- a/display_list/effects/dl_image_filter.h +++ b/display_list/effects/dl_image_filter.h @@ -5,17 +5,8 @@ #ifndef FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTER_H_ #define FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTER_H_ -#include - -#include "display_list/effects/dl_color_source.h" #include "flutter/display_list/dl_attributes.h" -#include "flutter/display_list/dl_sampling_options.h" -#include "flutter/display_list/dl_tile_mode.h" -#include "flutter/display_list/effects/dl_color_filter.h" -#include "flutter/display_list/utils/dl_comparable.h" -#include "flutter/fml/logging.h" - -#include "third_party/skia/include/core/SkMatrix.h" +#include "flutter/display_list/geometry/dl_geometry_types.h" namespace flutter { @@ -76,7 +67,7 @@ class DlImageFilter : public DlAttribute { } virtual std::shared_ptr makeWithLocalMatrix( - const SkMatrix& matrix) const; + const DlMatrix& matrix) const; // Return a DlComposeImageFilter pointer to this object iff it is a Compose // type of ImageFilter, otherwise return nullptr. @@ -108,8 +99,8 @@ class DlImageFilter : public DlAttribute { // can successfully compute the output bounds of the filter, otherwise the // method will return a nullptr and the output_bounds will be filled with // a best guess for the answer, even if just a copy of the input_bounds. - virtual SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const = 0; + virtual DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const = 0; // Return the device bounds of the output for this image filtering operation // based on the supplied input device bounds where both are measured in the @@ -122,9 +113,9 @@ class DlImageFilter : public DlAttribute { // can successfully compute the output bounds of the filter, otherwise the // method will return a nullptr and the output_bounds will be filled with // a best guess for the answer, even if just a copy of the input_bounds. - virtual SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const = 0; + virtual DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const = 0; // Return the input bounds that will be needed in order for the filter to // properly fill the indicated output_bounds under the specified @@ -135,715 +126,30 @@ class DlImageFilter : public DlAttribute { // can successfully compute the required input bounds, otherwise the // method will return a nullptr and the input_bounds will be filled with // a best guess for the answer, even if just a copy of the output_bounds. - virtual SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const = 0; + virtual DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const = 0; virtual MatrixCapability matrix_capability() const { return MatrixCapability::kScaleTranslate; } protected: - static SkVector map_vectors_affine(const SkMatrix& ctm, - SkScalar x, - SkScalar y) { - FML_DCHECK(std::isfinite(x) && x >= 0); - FML_DCHECK(std::isfinite(y) && y >= 0); - FML_DCHECK(ctm.isFinite() && !ctm.hasPerspective()); - - // The x and y scalars would have been used to expand a local space - // rectangle which is then transformed by ctm. In order to do the - // expansion correctly, we should look at the relevant math. The - // 4 corners will be moved outward by the following vectors: - // (UL,UR,LR,LL) = ((-x, -y), (+x, -y), (+x, +y), (-x, +y)) - // After applying the transform, each of these vectors could be - // pointing in any direction so we need to examine each transformed - // delta vector and how it affected the bounds. - // Looking at just the affine 2x3 entries of the CTM we can delta - // transform these corner offsets and get the following: - // UL = dCTM(-x, -y) = (- x*m00 - y*m01, - x*m10 - y*m11) - // UR = dCTM(+x, -y) = ( x*m00 - y*m01, x*m10 - y*m11) - // LR = dCTM(+x, +y) = ( x*m00 + y*m01, x*m10 + y*m11) - // LL = dCTM(-x, +y) = (- x*m00 + y*m01, - x*m10 + y*m11) - // The X vectors are all some variation of adding or subtracting - // the sum of x*m00 and y*m01 or their difference. Similarly the Y - // vectors are +/- the associated sum/difference of x*m10 and y*m11. - // The largest displacements, both left/right or up/down, will - // happen when the signs of the m00/m01/m10/m11 matrix entries - // coincide with the signs of the scalars, i.e. are all positive. - return {x * abs(ctm[0]) + y * abs(ctm[1]), - x * abs(ctm[3]) + y * abs(ctm[4])}; - } - - static SkIRect* inset_device_bounds(const SkIRect& input_bounds, - SkScalar radius_x, - SkScalar radius_y, - const SkMatrix& ctm, - SkIRect& output_bounds) { - if (ctm.isFinite()) { - if (ctm.hasPerspective()) { - SkMatrix inverse; - if (ctm.invert(&inverse)) { - SkRect local_bounds = inverse.mapRect(SkRect::Make(input_bounds)); - local_bounds.inset(radius_x, radius_y); - output_bounds = ctm.mapRect(local_bounds).roundOut(); - return &output_bounds; - } - } else { - SkVector device_radius = map_vectors_affine(ctm, radius_x, radius_y); - output_bounds = input_bounds.makeInset(floor(device_radius.fX), // - floor(device_radius.fY)); - return &output_bounds; - } - } - output_bounds = input_bounds; - return nullptr; - } - - static SkIRect* outset_device_bounds(const SkIRect& input_bounds, - SkScalar radius_x, - SkScalar radius_y, - const SkMatrix& ctm, - SkIRect& output_bounds) { - if (ctm.isFinite()) { - if (ctm.hasPerspective()) { - SkMatrix inverse; - if (ctm.invert(&inverse)) { - SkRect local_bounds = inverse.mapRect(SkRect::Make(input_bounds)); - local_bounds.outset(radius_x, radius_y); - output_bounds = ctm.mapRect(local_bounds).roundOut(); - return &output_bounds; - } - } else { - SkVector device_radius = map_vectors_affine(ctm, radius_x, radius_y); - output_bounds = input_bounds.makeOutset(ceil(device_radius.fX), // - ceil(device_radius.fY)); - return &output_bounds; - } - } - output_bounds = input_bounds; - return nullptr; - } -}; - -class DlBlurImageFilter final : public DlImageFilter { - public: - DlBlurImageFilter(SkScalar sigma_x, SkScalar sigma_y, DlTileMode tile_mode) - : sigma_x_(sigma_x), sigma_y_(sigma_y), tile_mode_(tile_mode) {} - explicit DlBlurImageFilter(const DlBlurImageFilter* filter) - : DlBlurImageFilter(filter->sigma_x_, - filter->sigma_y_, - filter->tile_mode_) {} - DlBlurImageFilter(const DlBlurImageFilter& filter) - : DlBlurImageFilter(&filter) {} - - static std::shared_ptr Make(SkScalar sigma_x, - SkScalar sigma_y, - DlTileMode tile_mode) { - if (!std::isfinite(sigma_x) || !std::isfinite(sigma_y)) { - return nullptr; - } - if (sigma_x < SK_ScalarNearlyZero && sigma_y < SK_ScalarNearlyZero) { - return nullptr; - } - sigma_x = (sigma_x < SK_ScalarNearlyZero) ? 0 : sigma_x; - sigma_y = (sigma_y < SK_ScalarNearlyZero) ? 0 : sigma_y; - return std::make_shared(sigma_x, sigma_y, tile_mode); - } - - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - DlImageFilterType type() const override { return DlImageFilterType::kBlur; } - size_t size() const override { return sizeof(*this); } - - const DlBlurImageFilter* asBlur() const override { return this; } - - bool modifies_transparent_black() const override { return false; } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override { - output_bounds = input_bounds.makeOutset(sigma_x_ * 3.0f, sigma_y_ * 3.0f); - return &output_bounds; - } - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override { - return outset_device_bounds(input_bounds, sigma_x_ * 3.0f, sigma_y_ * 3.0f, - ctm, output_bounds); - } - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override { - // Blurs are symmetric in terms of output-for-input and input-for-output - return map_device_bounds(output_bounds, ctm, input_bounds); - } - - SkScalar sigma_x() const { return sigma_x_; } - SkScalar sigma_y() const { return sigma_y_; } - DlTileMode tile_mode() const { return tile_mode_; } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kBlur); - auto that = static_cast(&other); - return (SkScalarNearlyEqual(sigma_x_, that->sigma_x_) && - SkScalarNearlyEqual(sigma_y_, that->sigma_y_) && - tile_mode_ == that->tile_mode_); - } - - private: - SkScalar sigma_x_; - SkScalar sigma_y_; - DlTileMode tile_mode_; -}; - -class DlDilateImageFilter final : public DlImageFilter { - public: - DlDilateImageFilter(SkScalar radius_x, SkScalar radius_y) - : radius_x_(radius_x), radius_y_(radius_y) {} - explicit DlDilateImageFilter(const DlDilateImageFilter* filter) - : DlDilateImageFilter(filter->radius_x_, filter->radius_y_) {} - DlDilateImageFilter(const DlDilateImageFilter& filter) - : DlDilateImageFilter(&filter) {} - - static std::shared_ptr Make(SkScalar radius_x, - SkScalar radius_y) { - if (std::isfinite(radius_x) && radius_x > SK_ScalarNearlyZero && - std::isfinite(radius_y) && radius_y > SK_ScalarNearlyZero) { - return std::make_shared(radius_x, radius_y); - } - return nullptr; - } - - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - DlImageFilterType type() const override { return DlImageFilterType::kDilate; } - size_t size() const override { return sizeof(*this); } - - const DlDilateImageFilter* asDilate() const override { return this; } - - bool modifies_transparent_black() const override { return false; } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override { - output_bounds = input_bounds.makeOutset(radius_x_, radius_y_); - return &output_bounds; - } - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override { - return outset_device_bounds(input_bounds, radius_x_, radius_y_, ctm, - output_bounds); - } - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override { - return inset_device_bounds(output_bounds, radius_x_, radius_y_, ctm, - input_bounds); - } - - SkScalar radius_x() const { return radius_x_; } - SkScalar radius_y() const { return radius_y_; } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kDilate); - auto that = static_cast(&other); - return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_); - } - - private: - SkScalar radius_x_; - SkScalar radius_y_; -}; - -class DlErodeImageFilter final : public DlImageFilter { - public: - DlErodeImageFilter(SkScalar radius_x, SkScalar radius_y) - : radius_x_(radius_x), radius_y_(radius_y) {} - explicit DlErodeImageFilter(const DlErodeImageFilter* filter) - : DlErodeImageFilter(filter->radius_x_, filter->radius_y_) {} - DlErodeImageFilter(const DlErodeImageFilter& filter) - : DlErodeImageFilter(&filter) {} - - static std::shared_ptr Make(SkScalar radius_x, - SkScalar radius_y) { - if (std::isfinite(radius_x) && radius_x > SK_ScalarNearlyZero && - std::isfinite(radius_y) && radius_y > SK_ScalarNearlyZero) { - return std::make_shared(radius_x, radius_y); - } - return nullptr; - } - - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - DlImageFilterType type() const override { return DlImageFilterType::kErode; } - size_t size() const override { return sizeof(*this); } - - const DlErodeImageFilter* asErode() const override { return this; } - - bool modifies_transparent_black() const override { return false; } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override { - output_bounds = input_bounds.makeInset(radius_x_, radius_y_); - return &output_bounds; - } - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override { - return inset_device_bounds(input_bounds, radius_x_, radius_y_, ctm, - output_bounds); - } - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override { - return outset_device_bounds(output_bounds, radius_x_, radius_y_, ctm, - input_bounds); - } - - SkScalar radius_x() const { return radius_x_; } - SkScalar radius_y() const { return radius_y_; } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kErode); - auto that = static_cast(&other); - return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_); - } - - private: - SkScalar radius_x_; - SkScalar radius_y_; -}; - -class DlMatrixImageFilter final : public DlImageFilter { - public: - DlMatrixImageFilter(const SkMatrix& matrix, DlImageSampling sampling) - : matrix_(matrix), sampling_(sampling) {} - explicit DlMatrixImageFilter(const DlMatrixImageFilter* filter) - : DlMatrixImageFilter(filter->matrix_, filter->sampling_) {} - DlMatrixImageFilter(const DlMatrixImageFilter& filter) - : DlMatrixImageFilter(&filter) {} - - static std::shared_ptr Make(const SkMatrix& matrix, - DlImageSampling sampling) { - if (matrix.isFinite() && !matrix.isIdentity()) { - return std::make_shared(matrix, sampling); - } - return nullptr; - } - - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - DlImageFilterType type() const override { return DlImageFilterType::kMatrix; } - size_t size() const override { return sizeof(*this); } - - const SkMatrix& matrix() const { return matrix_; } - DlImageSampling sampling() const { return sampling_; } - - const DlMatrixImageFilter* asMatrix() const override { return this; } - - bool modifies_transparent_black() const override { return false; } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override { - output_bounds = matrix_.mapRect(input_bounds); - return &output_bounds; - } - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override { - SkMatrix matrix; - if (!ctm.invert(&matrix)) { - output_bounds = input_bounds; - return nullptr; - } - matrix.postConcat(matrix_); - matrix.postConcat(ctm); - SkRect device_rect; - matrix.mapRect(&device_rect, SkRect::Make(input_bounds)); - output_bounds = device_rect.roundOut(); - return &output_bounds; - } - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override { - SkMatrix matrix = SkMatrix::Concat(ctm, matrix_); - SkMatrix inverse; - if (!matrix.invert(&inverse)) { - input_bounds = output_bounds; - return nullptr; - } - inverse.postConcat(ctm); - SkRect bounds; - bounds.set(output_bounds); - inverse.mapRect(&bounds); - input_bounds = bounds.roundOut(); - return &input_bounds; - } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kMatrix); - auto that = static_cast(&other); - return (matrix_ == that->matrix_ && sampling_ == that->sampling_); - } - - private: - SkMatrix matrix_; - DlImageSampling sampling_; -}; - -class DlComposeImageFilter final : public DlImageFilter { - public: - DlComposeImageFilter(std::shared_ptr outer, - std::shared_ptr inner) - : outer_(std::move(outer)), inner_(std::move(inner)) {} - DlComposeImageFilter(const DlImageFilter* outer, const DlImageFilter* inner) - : outer_(outer->shared()), inner_(inner->shared()) {} - DlComposeImageFilter(const DlImageFilter& outer, const DlImageFilter& inner) - : DlComposeImageFilter(&outer, &inner) {} - explicit DlComposeImageFilter(const DlComposeImageFilter* filter) - : DlComposeImageFilter(filter->outer_, filter->inner_) {} - DlComposeImageFilter(const DlComposeImageFilter& filter) - : DlComposeImageFilter(&filter) {} - - static std::shared_ptr Make( - std::shared_ptr outer, - std::shared_ptr inner) { - if (!outer) { - return inner; - } - if (!inner) { - return outer; - } - return std::make_shared(outer, inner); - } - - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - DlImageFilterType type() const override { - return DlImageFilterType::kCompose; - } - size_t size() const override { return sizeof(*this); } - - std::shared_ptr outer() const { return outer_; } - std::shared_ptr inner() const { return inner_; } - - const DlComposeImageFilter* asCompose() const override { return this; } - - bool modifies_transparent_black() const override { - if (inner_ && inner_->modifies_transparent_black()) { - return true; - } - if (outer_ && outer_->modifies_transparent_black()) { - return true; - } - return false; - } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override; - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override; - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override; - - MatrixCapability matrix_capability() const override { - return std::min(outer_->matrix_capability(), inner_->matrix_capability()); - } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kCompose); - auto that = static_cast(&other); - return (Equals(outer_, that->outer_) && Equals(inner_, that->inner_)); - } - - private: - std::shared_ptr outer_; - std::shared_ptr inner_; -}; - -class DlColorFilterImageFilter final : public DlImageFilter { - public: - explicit DlColorFilterImageFilter(std::shared_ptr filter) - : color_filter_(std::move(filter)) {} - explicit DlColorFilterImageFilter(const DlColorFilter* filter) - : color_filter_(filter->shared()) {} - explicit DlColorFilterImageFilter(const DlColorFilter& filter) - : color_filter_(filter.shared()) {} - explicit DlColorFilterImageFilter(const DlColorFilterImageFilter* filter) - : DlColorFilterImageFilter(filter->color_filter_) {} - DlColorFilterImageFilter(const DlColorFilterImageFilter& filter) - : DlColorFilterImageFilter(&filter) {} - - static std::shared_ptr Make( - const std::shared_ptr& filter) { - if (filter) { - return std::make_shared(filter); - } - return nullptr; - } - - std::shared_ptr shared() const override { - return std::make_shared(color_filter_); - } - - DlImageFilterType type() const override { - return DlImageFilterType::kColorFilter; - } - size_t size() const override { return sizeof(*this); } - - const std::shared_ptr color_filter() const { - return color_filter_; - } - - const DlColorFilterImageFilter* asColorFilter() const override { - return this; - } - - bool modifies_transparent_black() const override { - if (color_filter_) { - return color_filter_->modifies_transparent_black(); - } - return false; - } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override { - output_bounds = input_bounds; - return modifies_transparent_black() ? nullptr : &output_bounds; - } - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override { - output_bounds = input_bounds; - return modifies_transparent_black() ? nullptr : &output_bounds; - } - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override { - return map_device_bounds(output_bounds, ctm, input_bounds); - } - - MatrixCapability matrix_capability() const override { - return MatrixCapability::kComplex; - } - - std::shared_ptr makeWithLocalMatrix( - const SkMatrix& matrix) const override { - return shared(); - } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kColorFilter); - auto that = static_cast(&other); - return Equals(color_filter_, that->color_filter_); - } - - private: - std::shared_ptr color_filter_; -}; - -class DlLocalMatrixImageFilter final : public DlImageFilter { - public: - explicit DlLocalMatrixImageFilter(const SkMatrix& matrix, - std::shared_ptr filter) - : matrix_(matrix), image_filter_(std::move(filter)) {} - explicit DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter* filter) - : DlLocalMatrixImageFilter(filter->matrix_, filter->image_filter_) {} - DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter& filter) - : DlLocalMatrixImageFilter(&filter) {} - std::shared_ptr shared() const override { - return std::make_shared(this); - } - - DlImageFilterType type() const override { - return DlImageFilterType::kLocalMatrix; - } - size_t size() const override { return sizeof(*this); } - - const SkMatrix& matrix() const { return matrix_; } - - const std::shared_ptr image_filter() const { - return image_filter_; - } - - const DlLocalMatrixImageFilter* asLocalMatrix() const override { - return this; - } - - bool modifies_transparent_black() const override { - if (!image_filter_) { - return false; - } - return image_filter_->modifies_transparent_black(); - } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override { - if (!image_filter_) { - output_bounds = input_bounds; - return &output_bounds; - } - return image_filter_->map_local_bounds(input_bounds, output_bounds); - } - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override { - if (!image_filter_) { - output_bounds = input_bounds; - return &output_bounds; - } - return image_filter_->map_device_bounds( - input_bounds, SkMatrix::Concat(ctm, matrix_), output_bounds); - } - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override { - if (!image_filter_) { - input_bounds = output_bounds; - return &input_bounds; - } - return image_filter_->get_input_device_bounds( - output_bounds, SkMatrix::Concat(ctm, matrix_), input_bounds); - } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kLocalMatrix); - auto that = static_cast(&other); - return (matrix_ == that->matrix_ && - Equals(image_filter_, that->image_filter_)); - } - - private: - SkMatrix matrix_; - std::shared_ptr image_filter_; -}; - -class DlRuntimeEffectImageFilter final : public DlImageFilter { - public: - explicit DlRuntimeEffectImageFilter( - sk_sp runtime_effect, - std::vector> samplers, - std::shared_ptr> uniform_data) - : runtime_effect_(std::move(runtime_effect)), - samplers_(std::move(samplers)), - uniform_data_(std::move(uniform_data)) {} - - std::shared_ptr shared() const override { - return std::make_shared( - this->runtime_effect_, this->samplers_, this->uniform_data_); - } - - static std::shared_ptr Make( - sk_sp runtime_effect, - std::vector> samplers, - std::shared_ptr> uniform_data) { - return std::make_shared( - std::move(runtime_effect), std::move(samplers), - std::move(uniform_data)); - } - - DlImageFilterType type() const override { - return DlImageFilterType::kRuntimeEffect; - } - size_t size() const override { return sizeof(*this); } - - bool modifies_transparent_black() const override { return false; } - - SkRect* map_local_bounds(const SkRect& input_bounds, - SkRect& output_bounds) const override { - output_bounds = input_bounds; - return &output_bounds; - } - - SkIRect* map_device_bounds(const SkIRect& input_bounds, - const SkMatrix& ctm, - SkIRect& output_bounds) const override { - output_bounds = input_bounds; - return &output_bounds; - } - - SkIRect* get_input_device_bounds(const SkIRect& output_bounds, - const SkMatrix& ctm, - SkIRect& input_bounds) const override { - input_bounds = output_bounds; - return &input_bounds; - } - - const DlRuntimeEffectImageFilter* asRuntimeEffectFilter() const override { - return this; - } - - const sk_sp runtime_effect() const { - return runtime_effect_; - } - - const std::vector>& samplers() const { - return samplers_; - } - - const std::shared_ptr>& uniform_data() const { - return uniform_data_; - } - - protected: - bool equals_(const DlImageFilter& other) const override { - FML_DCHECK(other.type() == DlImageFilterType::kRuntimeEffect); - auto that = static_cast(&other); - if (runtime_effect_ != that->runtime_effect_ || - samplers_.size() != that->samplers().size() || - uniform_data_->size() != that->uniform_data()->size()) { - return false; - } - for (auto i = 0u; i < samplers_.size(); i++) { - if (samplers_[i] != that->samplers()[i]) { - return false; - } - } - for (auto i = 0u; i < uniform_data_->size(); i++) { - if (uniform_data_->at(i) != that->uniform_data()->at(i)) { - return false; - } - } - return true; - } - - private: - sk_sp runtime_effect_; - std::vector> samplers_; - std::shared_ptr> uniform_data_; + static DlVector2 map_vectors_affine(const DlMatrix& ctm, + DlScalar x, + DlScalar y); + + static DlIRect* inset_device_bounds(const DlIRect& input_bounds, + DlScalar radius_x, + DlScalar radius_y, + const DlMatrix& ctm, + DlIRect& output_bounds); + + static DlIRect* outset_device_bounds(const DlIRect& input_bounds, + DlScalar radius_x, + DlScalar radius_y, + const DlMatrix& ctm, + DlIRect& output_bounds); }; } // namespace flutter diff --git a/display_list/effects/dl_image_filter_unittests.cc b/display_list/effects/dl_image_filter_unittests.cc index f01bb8987c5b1..c44245d4eb499 100644 --- a/display_list/effects/dl_image_filter_unittests.cc +++ b/display_list/effects/dl_image_filter_unittests.cc @@ -3,13 +3,15 @@ // found in the LICENSE file. #include "flutter/display_list/dl_blend_mode.h" +#include "flutter/display_list/dl_builder.h" #include "flutter/display_list/dl_color.h" #include "flutter/display_list/dl_sampling_options.h" #include "flutter/display_list/dl_tile_mode.h" #include "flutter/display_list/effects/dl_color_filter.h" -#include "flutter/display_list/effects/dl_image_filter.h" +#include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/testing/dl_test_equality.h" #include "flutter/display_list/utils/dl_comparable.h" +#include "flutter/testing/display_list_testing.h" #include "gtest/gtest.h" #include "include/core/SkMatrix.h" @@ -29,34 +31,34 @@ namespace testing { // and bottom edges are contained even if they are on the right or // bottom edge. This method does the "all sides inclusive" version // of SkRect::contains. -static bool containsInclusive(const SkRect rect, const SkPoint p) { +static bool containsInclusive(const DlRect rect, const DlPoint p) { // Test with a slight offset of 1E-9 to "forgive" IEEE bit-rounding // Ending up with bounds that are off by 1E-9 (these numbers are all // being tested in device space with this method) will be off by a // negligible amount of a pixel that wouldn't contribute to changing // the color of a pixel. - return (p.fX >= rect.fLeft - 1E-9 && // - p.fX <= rect.fRight + 1E-9 && // - p.fY >= rect.fTop - 1E-9 && // - p.fY <= rect.fBottom + 1E-9); + return (p.x >= rect.GetLeft() - 1E-9 && // + p.x <= rect.GetRight() + 1E-9 && // + p.y >= rect.GetTop() - 1E-9 && // + p.y <= rect.GetBottom() + 1E-9); } -static bool containsInclusive(const SkRect rect, const SkPoint quad[4]) { +static bool containsInclusive(const DlRect rect, const DlQuad quad) { return (containsInclusive(rect, quad[0]) && // containsInclusive(rect, quad[1]) && // containsInclusive(rect, quad[2]) && // containsInclusive(rect, quad[3])); } -static bool containsInclusive(const SkIRect rect, const SkPoint quad[4]) { - return containsInclusive(SkRect::Make(rect), quad); +static bool containsInclusive(const DlIRect rect, const DlQuad quad) { + return containsInclusive(DlRect::Make(rect), quad); } -static bool containsInclusive(const SkIRect rect, const SkRect bounds) { - return (bounds.fLeft >= rect.fLeft - 1E-9 && - bounds.fTop >= rect.fTop - 1E-9 && - bounds.fRight <= rect.fRight + 1E-9 && - bounds.fBottom <= rect.fBottom + 1E-9); +static bool containsInclusive(const DlIRect rect, const DlRect bounds) { + return (bounds.GetLeft() >= rect.GetLeft() - 1E-9 && + bounds.GetTop() >= rect.GetTop() - 1E-9 && + bounds.GetRight() <= rect.GetRight() + 1E-9 && + bounds.GetBottom() <= rect.GetBottom() + 1E-9); } // Used to verify that the expected output bounds and reverse-engineered @@ -64,43 +66,61 @@ static bool containsInclusive(const SkIRect rect, const SkRect bounds) { // returned from the various bounds computation methods under the specified // matrix. static void TestBoundsWithMatrix(const DlImageFilter& filter, - const SkMatrix& matrix, - const SkRect& sourceBounds, - const SkPoint expectedLocalOutputQuad[4]) { - SkRect device_input_bounds = matrix.mapRect(sourceBounds); - SkPoint expected_output_quad[4]; - matrix.mapPoints(expected_output_quad, expectedLocalOutputQuad, 4); - - SkIRect device_filter_ibounds; - ASSERT_EQ(filter.map_device_bounds(device_input_bounds.roundOut(), matrix, - device_filter_ibounds), + const DlMatrix& matrix, + const DlRect& sourceBounds, + const DlQuad& expectedLocalOutputQuad) { + DlRect device_input_bounds = sourceBounds.TransformAndClipBounds(matrix); + DlQuad expected_output_quad = matrix.Transform(expectedLocalOutputQuad); + + DlIRect device_filter_ibounds; + ASSERT_EQ(filter.map_device_bounds(DlIRect::RoundOut(device_input_bounds), + matrix, device_filter_ibounds), &device_filter_ibounds); - ASSERT_TRUE(containsInclusive(device_filter_ibounds, expected_output_quad)); - - SkIRect reverse_input_ibounds; + EXPECT_TRUE(containsInclusive(device_filter_ibounds, expected_output_quad)) + << filter << std::endl + << sourceBounds << ", {" << std::endl + << " " << expectedLocalOutputQuad[0] << ", " << std::endl + << " " << expectedLocalOutputQuad[1] << ", " << std::endl + << " " << expectedLocalOutputQuad[2] << ", " << std::endl + << " " << expectedLocalOutputQuad[3] << std::endl + << "}, " << matrix << ", " << std::endl + << device_filter_ibounds << std::endl + << device_input_bounds << ", {" << std::endl + << " " << expected_output_quad[0] << ", " << std::endl + << " " << expected_output_quad[1] << ", " << std::endl + << " " << expected_output_quad[2] << ", " << std::endl + << " " << expected_output_quad[3] << std::endl + << "}"; + + DlIRect reverse_input_ibounds; ASSERT_EQ(filter.get_input_device_bounds(device_filter_ibounds, matrix, reverse_input_ibounds), &reverse_input_ibounds); - ASSERT_TRUE(containsInclusive(reverse_input_ibounds, device_input_bounds)); + EXPECT_TRUE(containsInclusive(reverse_input_ibounds, device_input_bounds)) + << filter << std::endl + << matrix << ", " << std::endl + << reverse_input_ibounds << ", " << std::endl + << device_input_bounds; } static void TestInvalidBounds(const DlImageFilter& filter, - const SkMatrix& matrix, - const SkRect& localInputBounds) { - SkIRect device_input_bounds = matrix.mapRect(localInputBounds).roundOut(); + const DlMatrix& matrix, + const DlRect& localInputBounds) { + DlIRect device_input_bounds = + DlIRect::RoundOut(localInputBounds.TransformBounds(matrix)); - SkRect local_filter_bounds; + DlRect local_filter_bounds; ASSERT_EQ(filter.map_local_bounds(localInputBounds, local_filter_bounds), nullptr); ASSERT_EQ(local_filter_bounds, localInputBounds); - SkIRect device_filter_ibounds; + DlIRect device_filter_ibounds; ASSERT_EQ(filter.map_device_bounds(device_input_bounds, matrix, device_filter_ibounds), nullptr); ASSERT_EQ(device_filter_ibounds, device_input_bounds); - SkIRect reverse_input_ibounds; + DlIRect reverse_input_ibounds; ASSERT_EQ(filter.get_input_device_bounds(device_input_bounds, matrix, reverse_input_ibounds), nullptr); @@ -116,38 +136,56 @@ static void TestInvalidBounds(const DlImageFilter& filter, // be assumed to be unable to perform their computations for the given // image filter and will be returning null. static void TestBounds(const DlImageFilter& filter, - const SkRect& sourceBounds, - const SkPoint expectedLocalOutputQuad[4]) { - SkRect local_filter_bounds; + const DlRect& sourceBounds, + const DlQuad& expectedLocalOutputQuad) { + DlRect local_filter_bounds; ASSERT_EQ(filter.map_local_bounds(sourceBounds, local_filter_bounds), &local_filter_bounds); ASSERT_TRUE(containsInclusive(local_filter_bounds, expectedLocalOutputQuad)); - for (int scale = 1; scale <= 4; scale++) { - for (int skew = 0; skew < 8; skew++) { + for (int i_scale = 1; i_scale <= 4; i_scale++) { + DlScalar scale = i_scale; + for (int skew_eighths = 0; skew_eighths < 7; skew_eighths++) { + DlScalar skew = skew_eighths / 8.0f; for (int degrees = 0; degrees <= 360; degrees += 15) { - SkMatrix matrix; - matrix.setScale(scale, scale); - matrix.postSkew(skew / 8.0, skew / 8.0); - matrix.postRotate(degrees); - ASSERT_TRUE(matrix.invert(nullptr)); - TestBoundsWithMatrix(filter, matrix, sourceBounds, - expectedLocalOutputQuad); - matrix.setPerspX(0.001); - matrix.setPerspY(0.001); - ASSERT_TRUE(matrix.invert(nullptr)); + DlMatrix matrix; + matrix = matrix.Scale({scale, scale, 1}); + matrix = DlMatrix::MakeSkew(skew, skew) * matrix; + matrix = DlMatrix::MakeRotationZ(DlDegrees(degrees)) * matrix; + ASSERT_TRUE(matrix.IsInvertible()) << matrix; + ASSERT_FALSE(matrix.HasPerspective2D()) << matrix; TestBoundsWithMatrix(filter, matrix, sourceBounds, expectedLocalOutputQuad); } } } + + { + // Just test once with a reasonable perspective transform. Combining + // perspective with all of the abusively scaled and skewed transforms + // created in the loop above tends to lead to coordinates growing out + // of any reasonable scale. + DlMatrix matrix; + matrix = matrix.Scale({2.0f, 2.0f, 1}); + matrix = matrix.Translate({1000, 1000, 500}); + // matrix = DlMatrix::MakeSkew(0.125f, 0.125f) * matrix; + matrix = DlMatrix::MakeRotationX(DlDegrees(5)) * matrix; + // matrix = DlMatrix::MakeRotationY(DlDegrees(5)) * matrix; + // matrix = DlMatrix::MakeTranslation({0, 0, 5}); + matrix = DlMatrix::MakePerspective(DlDegrees(60), 0.5, -500, 1000) * matrix; + // matrix = DlMatrix::MakeLookAt({0, 0, -10}, {0, 0, 10}, {0, 1, 0}) + // * matrix; + ASSERT_TRUE(matrix.IsInvertible()) << matrix; + ASSERT_TRUE(matrix.HasPerspective2D()) << matrix; + TestBoundsWithMatrix(filter, matrix, sourceBounds, expectedLocalOutputQuad); + } } static void TestBounds(const DlImageFilter& filter, - const SkRect& sourceBounds, - const SkRect& expectedLocalOutputBounds) { - SkPoint expected_local_output_quad[4]; - expectedLocalOutputBounds.toQuad(expected_local_output_quad); + const DlRect& sourceBounds, + const DlRect& expectedLocalOutputBounds) { + DlQuad expected_local_output_quad = expectedLocalOutputBounds.GetPoints(); + ASSERT_EQ(expected_local_output_quad.size(), 4u); // Only 0u when empty TestBounds(filter, sourceBounds, expected_local_output_quad); } @@ -188,7 +226,7 @@ TEST(DisplayListImageFilter, BlurWithLocalMatrixEquals) { DlBlurImageFilter filter1(5.0, 6.0, DlTileMode::kMirror); DlBlurImageFilter filter2(5.0, 6.0, DlTileMode::kMirror); - SkMatrix local_matrix = SkMatrix::Translate(10, 10); + DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10}); TestEquals(*filter1.makeWithLocalMatrix(local_matrix), *filter2.makeWithLocalMatrix(local_matrix)); } @@ -206,8 +244,8 @@ TEST(DisplayListImageFilter, BlurNotEquals) { TEST(DisplayListImageFilter, BlurBounds) { DlBlurImageFilter filter = DlBlurImageFilter(5, 10, DlTileMode::kDecal); - SkRect input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - SkRect expected_output_bounds = input_bounds.makeOutset(15, 30); + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + DlRect expected_output_bounds = input_bounds.Expand(15, 30); TestBounds(filter, input_bounds, expected_output_bounds); } @@ -264,7 +302,7 @@ TEST(DisplayListImageFilter, DilateWithLocalMatrixEquals) { DlDilateImageFilter filter1(5.0, 6.0); DlDilateImageFilter filter2(5.0, 6.0); - SkMatrix local_matrix = SkMatrix::Translate(10, 10); + DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10}); TestEquals(*filter1.makeWithLocalMatrix(local_matrix), *filter2.makeWithLocalMatrix(local_matrix)); } @@ -280,8 +318,8 @@ TEST(DisplayListImageFilter, DilateNotEquals) { TEST(DisplayListImageFilter, DilateBounds) { DlDilateImageFilter filter = DlDilateImageFilter(5, 10); - SkRect input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - SkRect expected_output_bounds = input_bounds.makeOutset(5, 10); + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + DlRect expected_output_bounds = input_bounds.Expand(5, 10); TestBounds(filter, input_bounds, expected_output_bounds); } @@ -321,7 +359,7 @@ TEST(DisplayListImageFilter, ErodeWithLocalMatrixEquals) { DlErodeImageFilter filter1(5.0, 6.0); DlErodeImageFilter filter2(5.0, 6.0); - SkMatrix local_matrix = SkMatrix::Translate(10, 10); + DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10}); TestEquals(*filter1.makeWithLocalMatrix(local_matrix), *filter2.makeWithLocalMatrix(local_matrix)); } @@ -337,22 +375,24 @@ TEST(DisplayListImageFilter, ErodeNotEquals) { TEST(DisplayListImageFilter, ErodeBounds) { DlErodeImageFilter filter = DlErodeImageFilter(5, 10); - SkRect input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - SkRect expected_output_bounds = input_bounds.makeInset(5, 10); + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80).Shift(100, 100); + DlRect expected_output_bounds = input_bounds.Expand(-5, -10); TestBounds(filter, input_bounds, expected_output_bounds); } TEST(DisplayListImageFilter, MatrixConstructor) { - DlMatrixImageFilter filter(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter filter(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); } TEST(DisplayListImageFilter, MatrixShared) { - DlMatrixImageFilter filter(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter filter(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); ASSERT_NE(filter.shared().get(), &filter); @@ -360,9 +400,10 @@ TEST(DisplayListImageFilter, MatrixShared) { } TEST(DisplayListImageFilter, MatrixAsMatrix) { - DlMatrixImageFilter filter(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter filter(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); ASSERT_NE(filter.asMatrix(), nullptr); @@ -370,9 +411,10 @@ TEST(DisplayListImageFilter, MatrixAsMatrix) { } TEST(DisplayListImageFilter, MatrixContents) { - SkMatrix matrix = SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1); + DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0); DlMatrixImageFilter filter(matrix, DlImageSampling::kLinear); ASSERT_EQ(filter.matrix(), matrix); @@ -380,9 +422,10 @@ TEST(DisplayListImageFilter, MatrixContents) { } TEST(DisplayListImageFilter, MatrixEquals) { - SkMatrix matrix = SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1); + DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0); DlMatrixImageFilter filter1(matrix, DlImageSampling::kLinear); DlMatrixImageFilter filter2(matrix, DlImageSampling::kLinear); @@ -390,24 +433,27 @@ TEST(DisplayListImageFilter, MatrixEquals) { } TEST(DisplayListImageFilter, MatrixWithLocalMatrixEquals) { - SkMatrix matrix = SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1); + DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0); DlMatrixImageFilter filter1(matrix, DlImageSampling::kLinear); DlMatrixImageFilter filter2(matrix, DlImageSampling::kLinear); - SkMatrix local_matrix = SkMatrix::Translate(10, 10); + DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10}); TestEquals(*filter1.makeWithLocalMatrix(local_matrix), *filter2.makeWithLocalMatrix(local_matrix)); } TEST(DisplayListImageFilter, MatrixNotEquals) { - SkMatrix matrix1 = SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1); - SkMatrix matrix2 = SkMatrix::MakeAll(5.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1); + DlMatrix matrix1 = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0); + DlMatrix matrix2 = DlMatrix::MakeRow(5.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0); DlMatrixImageFilter filter1(matrix1, DlImageSampling::kLinear); DlMatrixImageFilter filter2(matrix2, DlImageSampling::kLinear); DlMatrixImageFilter filter3(matrix1, DlImageSampling::kNearestNeighbor); @@ -417,35 +463,37 @@ TEST(DisplayListImageFilter, MatrixNotEquals) { } TEST(DisplayListImageFilter, MatrixBounds) { - SkMatrix matrix = SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 7, // - 0.0, 0.0, 1); - SkMatrix inverse; - ASSERT_TRUE(matrix.invert(&inverse)); + DlMatrix matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 7, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0); + EXPECT_TRUE(matrix.IsInvertible()); DlMatrixImageFilter filter(matrix, DlImageSampling::kLinear); - SkRect input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - SkPoint expectedOutputQuad[4] = { - {50, 77}, // (20,20) => (20*2 + 10, 20/2 + 20*3 + 7) == (50, 77) - {50, 257}, // (20,80) => (20*2 + 10, 20/2 + 80*3 + 7) == (50, 257) - {170, 287}, // (80,80) => (80*2 + 10, 80/2 + 80*3 + 7) == (170, 287) - {170, 107}, // (80,20) => (80*2 + 10, 80/2 + 20*3 + 7) == (170, 107) + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + DlQuad expectedOutputQuad = { + DlPoint(50, 77), // == (20,20) => (20*2 + 10, 20/2 + 20*3 + 7) + DlPoint(50, 257), // == (20,80) => (20*2 + 10, 20/2 + 80*3 + 7) + DlPoint(170, 287), // == (80,80) => (80*2 + 10, 80/2 + 80*3 + 7) + DlPoint(170, 107), // == (80,20) => (80*2 + 10, 80/2 + 20*3 + 7) }; TestBounds(filter, input_bounds, expectedOutputQuad); } TEST(DisplayListImageFilter, ComposeConstructor) { - DlMatrixImageFilter outer(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter(outer, inner); } TEST(DisplayListImageFilter, ComposeShared) { - DlMatrixImageFilter outer(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter(outer, inner); @@ -455,9 +503,10 @@ TEST(DisplayListImageFilter, ComposeShared) { } TEST(DisplayListImageFilter, ComposeAsCompose) { - DlMatrixImageFilter outer(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter(outer, inner); @@ -467,9 +516,10 @@ TEST(DisplayListImageFilter, ComposeAsCompose) { } TEST(DisplayListImageFilter, ComposeContents) { - DlMatrixImageFilter outer(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter(outer, inner); @@ -479,16 +529,18 @@ TEST(DisplayListImageFilter, ComposeContents) { } TEST(DisplayListImageFilter, ComposeEquals) { - DlMatrixImageFilter outer1(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer1(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner1(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter1(outer1, inner1); - DlMatrixImageFilter outer2(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer2(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner2(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter2(outer1, inner1); @@ -497,35 +549,39 @@ TEST(DisplayListImageFilter, ComposeEquals) { } TEST(DisplayListImageFilter, ComposeWithLocalMatrixEquals) { - DlMatrixImageFilter outer1(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer1(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner1(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter1(outer1, inner1); - DlMatrixImageFilter outer2(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer2(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner2(5.0, 6.0, DlTileMode::kMirror); DlComposeImageFilter filter2(outer1, inner1); - SkMatrix local_matrix = SkMatrix::Translate(10, 10); + DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10}); TestEquals(*filter1.makeWithLocalMatrix(local_matrix), *filter2.makeWithLocalMatrix(local_matrix)); } TEST(DisplayListImageFilter, ComposeNotEquals) { - DlMatrixImageFilter outer1(SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer1(DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner1(5.0, 6.0, DlTileMode::kMirror); - DlMatrixImageFilter outer2(SkMatrix::MakeAll(5.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1), + DlMatrixImageFilter outer2(DlMatrix::MakeRow(5.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0), DlImageSampling::kLinear); DlBlurImageFilter inner2(7.0, 6.0, DlTileMode::kMirror); @@ -541,35 +597,34 @@ TEST(DisplayListImageFilter, ComposeBounds) { DlDilateImageFilter outer = DlDilateImageFilter(5, 10); DlBlurImageFilter inner = DlBlurImageFilter(12, 5, DlTileMode::kDecal); DlComposeImageFilter filter = DlComposeImageFilter(outer, inner); - SkRect input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - SkRect expected_output_bounds = - input_bounds.makeOutset(36, 15).makeOutset(5, 10); + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + DlRect expected_output_bounds = input_bounds.Expand(36, 15).Expand(5, 10); TestBounds(filter, input_bounds, expected_output_bounds); } static void TestUnboundedBounds(DlImageFilter& filter, - const SkRect& sourceBounds, - const SkRect& expectedOutputBounds, - const SkRect& expectedInputBounds) { - SkRect bounds; + const DlRect& sourceBounds, + const DlRect& expectedOutputBounds, + const DlRect& expectedInputBounds) { + DlRect bounds; EXPECT_EQ(filter.map_local_bounds(sourceBounds, bounds), nullptr); EXPECT_EQ(bounds, expectedOutputBounds); - SkIRect ibounds; - EXPECT_EQ( - filter.map_device_bounds(sourceBounds.roundOut(), SkMatrix::I(), ibounds), - nullptr); - EXPECT_EQ(ibounds, expectedOutputBounds.roundOut()); + DlIRect ibounds; + EXPECT_EQ(filter.map_device_bounds(DlIRect::RoundOut(sourceBounds), + DlMatrix(), ibounds), + nullptr); + EXPECT_EQ(ibounds, DlIRect::RoundOut(expectedOutputBounds)); - EXPECT_EQ(filter.get_input_device_bounds(sourceBounds.roundOut(), - SkMatrix::I(), ibounds), + EXPECT_EQ(filter.get_input_device_bounds(DlIRect::RoundOut(sourceBounds), + DlMatrix(), ibounds), nullptr); - EXPECT_EQ(ibounds, expectedInputBounds.roundOut()); + EXPECT_EQ(ibounds, DlIRect::RoundOut(expectedInputBounds)); } TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedInner) { - auto input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - auto expected_bounds = SkRect::MakeLTRB(5, 2, 95, 98); + auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + auto expected_bounds = DlRect::MakeLTRB(5, 2, 95, 98); DlBlendColorFilter color_filter(DlColor::kRed(), DlBlendMode::kSrcOver); auto outer = DlBlurImageFilter(5.0, 6.0, DlTileMode::kRepeat); @@ -580,8 +635,8 @@ TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedInner) { } TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedOuter) { - auto input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - auto expected_bounds = SkRect::MakeLTRB(5, 2, 95, 98); + auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + auto expected_bounds = DlRect::MakeLTRB(5, 2, 95, 98); DlBlendColorFilter color_filter(DlColor::kRed(), DlBlendMode::kSrcOver); auto outer = DlColorFilterImageFilter(color_filter.shared()); @@ -592,7 +647,7 @@ TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedOuter) { } TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedInnerAndOuter) { - auto input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); + auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); auto expected_bounds = input_bounds; DlBlendColorFilter color_filter1(DlColor::kRed(), DlBlendMode::kSrcOver); @@ -606,18 +661,17 @@ TEST(DisplayListImageFilter, ComposeBoundsWithUnboundedInnerAndOuter) { // See https://github.com/flutter/flutter/issues/108433 TEST(DisplayListImageFilter, Issue108433) { - auto input_bounds = SkIRect::MakeLTRB(20, 20, 80, 80); - auto expected_bounds = SkIRect::MakeLTRB(5, 2, 95, 98); + auto input_bounds = DlIRect::MakeLTRB(20, 20, 80, 80); + auto expected_bounds = DlIRect::MakeLTRB(5, 2, 95, 98); DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcOver); auto dl_outer = DlBlurImageFilter(5.0, 6.0, DlTileMode::kRepeat); auto dl_inner = DlColorFilterImageFilter(dl_color_filter.shared()); auto dl_compose = DlComposeImageFilter(dl_outer, dl_inner); - SkIRect dl_bounds; - ASSERT_EQ( - dl_compose.map_device_bounds(input_bounds, SkMatrix::I(), dl_bounds), - nullptr); + DlIRect dl_bounds; + ASSERT_EQ(dl_compose.map_device_bounds(input_bounds, DlMatrix(), dl_bounds), + nullptr); ASSERT_EQ(dl_bounds, expected_bounds); } @@ -665,7 +719,7 @@ TEST(DisplayListImageFilter, ColorFilterWithLocalMatrixEquals) { DlBlendColorFilter dl_color_filter2(DlColor::kRed(), DlBlendMode::kLighten); DlColorFilterImageFilter filter2(dl_color_filter2); - SkMatrix local_matrix = SkMatrix::Translate(10, 10); + DlMatrix local_matrix = DlMatrix::MakeTranslation({10, 10}); TestEquals(*filter1.makeWithLocalMatrix(local_matrix), *filter2.makeWithLocalMatrix(local_matrix)); } @@ -687,28 +741,30 @@ TEST(DisplayListImageFilter, ColorFilterNotEquals) { TEST(DisplayListImageFilter, ColorFilterBounds) { DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcIn); DlColorFilterImageFilter filter(dl_color_filter); - SkRect input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); TestBounds(filter, input_bounds, input_bounds); } TEST(DisplayListImageFilter, ColorFilterModifiesTransparencyBounds) { DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcOver); DlColorFilterImageFilter filter(dl_color_filter); - SkRect input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - TestInvalidBounds(filter, SkMatrix::I(), input_bounds); + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + TestInvalidBounds(filter, DlMatrix(), input_bounds); } TEST(DisplayListImageFilter, LocalImageFilterBounds) { - auto filter_matrix = SkMatrix::MakeAll(2.0, 0.0, 10, // - 0.5, 3.0, 15, // - 0.0, 0.0, 1); + auto filter_matrix = DlMatrix::MakeRow(2.0, 0.0, 0.0, 10, // + 0.5, 3.0, 0.0, 15, // + 0.0, 0.0, 1.0, 0.0, // + 0.0, 0.0, 0.0, 1.0); std::vector> sk_filters{ SkImageFilters::Blur(5.0, 6.0, SkTileMode::kRepeat, nullptr), SkImageFilters::ColorFilter( SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcOver), nullptr), SkImageFilters::Dilate(5.0, 10.0, nullptr), - SkImageFilters::MatrixTransform( - filter_matrix, SkSamplingOptions(SkFilterMode::kLinear), nullptr), + SkImageFilters::MatrixTransform(ToSkMatrix(filter_matrix), + SkSamplingOptions(SkFilterMode::kLinear), + nullptr), SkImageFilters::Compose( SkImageFilters::Blur(5.0, 6.0, SkTileMode::kRepeat, nullptr), SkImageFilters::ColorFilter( @@ -717,47 +773,58 @@ TEST(DisplayListImageFilter, LocalImageFilterBounds) { DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcOver); std::vector> dl_filters{ - std::make_shared(5.0, 6.0, DlTileMode::kRepeat), - std::make_shared(dl_color_filter.shared()), - std::make_shared(5, 10), - std::make_shared(filter_matrix, - DlImageSampling::kLinear), - std::make_shared( - std::make_shared(5.0, 6.0, DlTileMode::kRepeat), - std::make_shared( - dl_color_filter.shared()))}; + DlBlurImageFilter::Make(5.0, 6.0, DlTileMode::kRepeat), + DlColorFilterImageFilter::Make(dl_color_filter.shared()), + DlDilateImageFilter::Make(5, 10), + DlMatrixImageFilter::Make(filter_matrix, DlImageSampling::kLinear), + DlComposeImageFilter::Make( + DlBlurImageFilter::Make(5.0, 6.0, DlTileMode::kRepeat), + DlColorFilterImageFilter::Make(dl_color_filter.shared())), + }; auto persp = SkMatrix::I(); persp.setPerspY(0.001); - std::vector matrices = { + std::vector sk_matrices = { SkMatrix::Translate(10.0, 10.0), SkMatrix::Scale(2.0, 2.0).preTranslate(10.0, 10.0), - SkMatrix::RotateDeg(45).preTranslate(5.0, 5.0), persp}; - std::vector bounds_matrices{SkMatrix::Translate(5.0, 10.0), - SkMatrix::Scale(2.0, 2.0)}; + SkMatrix::RotateDeg(45).preTranslate(5.0, 5.0), // + persp}; + std::vector dl_matrices = { + DlMatrix::MakeTranslation({10.0, 10.0}), + DlMatrix::MakeScale({2.0, 2.0, 1.0}).Translate({10.0, 10.0}), + DlMatrix::MakeRotationZ(DlDegrees(45)).Translate({5.0, 5.0}), + ToDlMatrix(persp)}; + std::vector sk_bounds_matrices{ + SkMatrix::Translate(5.0, 10.0), + SkMatrix::Scale(2.0, 2.0), + }; + std::vector dl_bounds_matrices{ + DlMatrix::MakeTranslation({5.0, 10.0}), + DlMatrix::MakeScale({2.0, 2.0, 1.0}), + }; - for (unsigned j = 0; j < matrices.size(); j++) { - DlLocalMatrixImageFilter filter(matrices[j], nullptr); + for (unsigned j = 0; j < dl_matrices.size(); j++) { + DlLocalMatrixImageFilter filter(dl_matrices[j], nullptr); { - const auto input_bounds = SkRect::MakeLTRB(20, 20, 80, 80); - SkRect output_bounds; + const auto input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); + DlRect output_bounds; EXPECT_EQ(filter.map_local_bounds(input_bounds, output_bounds), &output_bounds); EXPECT_EQ(input_bounds, output_bounds); } - for (unsigned k = 0; k < bounds_matrices.size(); k++) { - auto& bounds_matrix = bounds_matrices[k]; + for (unsigned k = 0; k < dl_bounds_matrices.size(); k++) { + auto& bounds_matrix = dl_bounds_matrices[k]; { - const auto input_bounds = SkIRect::MakeLTRB(20, 20, 80, 80); - SkIRect output_bounds; + const auto input_bounds = DlIRect::MakeLTRB(20, 20, 80, 80); + DlIRect output_bounds; EXPECT_EQ(filter.map_device_bounds(input_bounds, bounds_matrix, output_bounds), &output_bounds); EXPECT_EQ(input_bounds, output_bounds); } { - const auto output_bounds = SkIRect::MakeLTRB(20, 20, 80, 80); - SkIRect input_bounds; + const auto output_bounds = DlIRect::MakeLTRB(20, 20, 80, 80); + DlIRect input_bounds; EXPECT_EQ(filter.get_input_device_bounds(output_bounds, bounds_matrix, input_bounds), &input_bounds); @@ -767,15 +834,15 @@ TEST(DisplayListImageFilter, LocalImageFilterBounds) { } for (unsigned i = 0; i < sk_filters.size(); i++) { - for (unsigned j = 0; j < matrices.size(); j++) { - for (unsigned k = 0; k < bounds_matrices.size(); k++) { + for (unsigned j = 0; j < dl_matrices.size(); j++) { + for (unsigned k = 0; k < dl_bounds_matrices.size(); k++) { auto desc = "filter " + std::to_string(i + 1) // + ", filter matrix " + std::to_string(j + 1) // + ", bounds matrix " + std::to_string(k + 1); - auto& m = matrices[j]; - auto& bounds_matrix = bounds_matrices[k]; - auto sk_local_filter = sk_filters[i]->makeWithLocalMatrix(m); - auto dl_local_filter = dl_filters[i]->makeWithLocalMatrix(m); + auto sk_local_filter = + sk_filters[i]->makeWithLocalMatrix(sk_matrices[j]); + auto dl_local_filter = + dl_filters[i]->makeWithLocalMatrix(dl_matrices[j]); if (!sk_local_filter || !dl_local_filter) { // Temporarily relax the equivalence testing to allow Skia to expand // their behavior. Once the Skia fixes are rolled in, the @@ -786,13 +853,14 @@ TEST(DisplayListImageFilter, LocalImageFilterBounds) { } { auto input_bounds = SkIRect::MakeLTRB(20, 20, 80, 80); - SkIRect sk_rect, dl_rect; + SkIRect sk_rect; + DlIRect dl_rect; sk_rect = sk_local_filter->filterBounds( - input_bounds, bounds_matrix, + input_bounds, sk_bounds_matrices[k], SkImageFilter::MapDirection::kForward_MapDirection); - if (dl_local_filter->map_device_bounds(input_bounds, bounds_matrix, - dl_rect)) { - ASSERT_EQ(sk_rect, dl_rect) << desc; + if (dl_local_filter->map_device_bounds( + ToDlIRect(input_bounds), dl_bounds_matrices[k], dl_rect)) { + ASSERT_EQ(sk_rect, ToSkIRect(dl_rect)) << desc; } else { ASSERT_TRUE(dl_local_filter->modifies_transparent_black()) << desc; ASSERT_FALSE(sk_local_filter->canComputeFastBounds()) << desc; @@ -808,13 +876,14 @@ TEST(DisplayListImageFilter, LocalImageFilterBounds) { continue; } auto outset_bounds = SkIRect::MakeLTRB(20, 20, 80, 80); - SkIRect sk_rect, dl_rect; + SkIRect sk_rect; + DlIRect dl_rect; sk_rect = sk_local_filter->filterBounds( - outset_bounds, bounds_matrix, + outset_bounds, sk_bounds_matrices[k], SkImageFilter::MapDirection::kReverse_MapDirection); if (dl_local_filter->get_input_device_bounds( - outset_bounds, bounds_matrix, dl_rect)) { - ASSERT_EQ(sk_rect, dl_rect) << desc; + ToDlIRect(outset_bounds), dl_bounds_matrices[k], dl_rect)) { + ASSERT_EQ(sk_rect, ToSkIRect(dl_rect)) << desc; } else { ASSERT_TRUE(dl_local_filter->modifies_transparent_black()); ASSERT_FALSE(sk_local_filter->canComputeFastBounds()); @@ -862,13 +931,14 @@ TEST(DisplayListImageFilter, RuntimeEffectMapDeviceBounds) { DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, std::make_shared>()); - auto input_bounds = SkIRect::MakeLTRB(0, 0, 100, 100); - SkMatrix identity; - SkIRect output_bounds; - SkIRect* result = + auto input_bounds = DlIRect::MakeLTRB(0, 0, 100, 100); + DlMatrix identity; + DlIRect output_bounds; + DlIRect* result = filter_a.map_device_bounds(input_bounds, identity, output_bounds); EXPECT_NE(result, nullptr); + EXPECT_EQ(result, &output_bounds); EXPECT_EQ(output_bounds, input_bounds); } @@ -876,12 +946,13 @@ TEST(DisplayListImageFilter, RuntimeEffectMapInputBounds) { DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, std::make_shared>()); - auto input_bounds = SkRect::MakeLTRB(0, 0, 100, 100); + auto input_bounds = DlRect::MakeLTRB(0, 0, 100, 100); - SkRect output_bounds; - SkRect* result = filter_a.map_local_bounds(input_bounds, output_bounds); + DlRect output_bounds; + DlRect* result = filter_a.map_local_bounds(input_bounds, output_bounds); EXPECT_NE(result, nullptr); + EXPECT_EQ(result, &output_bounds); EXPECT_EQ(output_bounds, input_bounds); } @@ -889,14 +960,15 @@ TEST(DisplayListImageFilter, RuntimeEffectGetInputDeviceBounds) { DlRuntimeEffectImageFilter filter_a(nullptr, {nullptr}, std::make_shared>()); - auto output_bounds = SkIRect::MakeLTRB(0, 0, 100, 100); + auto output_bounds = DlIRect::MakeLTRB(0, 0, 100, 100); - SkMatrix identity; - SkIRect input_bounds; - SkIRect* result = + DlMatrix identity; + DlIRect input_bounds; + DlIRect* result = filter_a.get_input_device_bounds(output_bounds, identity, input_bounds); EXPECT_NE(result, nullptr); + EXPECT_EQ(result, &input_bounds); EXPECT_EQ(output_bounds, input_bounds); } diff --git a/display_list/effects/dl_image_filters.h b/display_list/effects/dl_image_filters.h new file mode 100644 index 0000000000000..3a13e6899413b --- /dev/null +++ b/display_list/effects/dl_image_filters.h @@ -0,0 +1,17 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTERS_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTERS_H_ + +#include "flutter/display_list/effects/dl_blur_image_filter.h" +#include "flutter/display_list/effects/dl_color_filter_image_filter.h" +#include "flutter/display_list/effects/dl_compose_image_filter.h" +#include "flutter/display_list/effects/dl_dilate_image_filter.h" +#include "flutter/display_list/effects/dl_erode_image_filter.h" +#include "flutter/display_list/effects/dl_local_matrix_image_filter.h" +#include "flutter/display_list/effects/dl_matrix_image_filter.h" +#include "flutter/display_list/effects/dl_runtime_effect_image_filter.h" + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_IMAGE_FILTERS_H_ diff --git a/display_list/effects/dl_local_matrix_image_filter.cc b/display_list/effects/dl_local_matrix_image_filter.cc new file mode 100644 index 0000000000000..42a1782f2fb76 --- /dev/null +++ b/display_list/effects/dl_local_matrix_image_filter.cc @@ -0,0 +1,65 @@ +// 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/display_list/effects/dl_local_matrix_image_filter.h" + +#include "flutter/display_list/utils/dl_comparable.h" + +namespace flutter { + +std::shared_ptr DlLocalMatrixImageFilter::Make( + const DlMatrix& matrix, + const std::shared_ptr& filter) { + return std::make_shared(matrix, filter); +} + +bool DlLocalMatrixImageFilter::modifies_transparent_black() const { + if (!image_filter_) { + return false; + } + return image_filter_->modifies_transparent_black(); +} + +DlRect* DlLocalMatrixImageFilter::map_local_bounds( + const DlRect& input_bounds, + DlRect& output_bounds) const { + if (!image_filter_) { + output_bounds = input_bounds; + return &output_bounds; + } + return image_filter_->map_local_bounds(input_bounds, output_bounds); +} + +DlIRect* DlLocalMatrixImageFilter::map_device_bounds( + const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + if (!image_filter_) { + output_bounds = input_bounds; + return &output_bounds; + } + return image_filter_->map_device_bounds(input_bounds, ctm * matrix_, + output_bounds); +} + +DlIRect* DlLocalMatrixImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + if (!image_filter_) { + input_bounds = output_bounds; + return &input_bounds; + } + return image_filter_->get_input_device_bounds(output_bounds, ctm * matrix_, + input_bounds); +} + +bool DlLocalMatrixImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kLocalMatrix); + auto that = static_cast(&other); + return (matrix_ == that->matrix_ && + Equals(image_filter_, that->image_filter_)); +} + +} // namespace flutter diff --git a/display_list/effects/dl_local_matrix_image_filter.h b/display_list/effects/dl_local_matrix_image_filter.h new file mode 100644 index 0000000000000..8b212c675eefb --- /dev/null +++ b/display_list/effects/dl_local_matrix_image_filter.h @@ -0,0 +1,69 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_LOCAL_MATRIX_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_LOCAL_MATRIX_IMAGE_FILTER_H_ + +#include "display_list/effects/dl_image_filter.h" + +namespace flutter { + +class DlLocalMatrixImageFilter final : public DlImageFilter { + public: + explicit DlLocalMatrixImageFilter( + const DlMatrix& matrix, + const std::shared_ptr& filter) + : matrix_(matrix), image_filter_(filter) {} + explicit DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter* filter) + : DlLocalMatrixImageFilter(filter->matrix_, filter->image_filter_) {} + DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter& filter) + : DlLocalMatrixImageFilter(&filter) {} + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + static std::shared_ptr Make( + const DlMatrix& matrix, + const std::shared_ptr& filter); + + DlImageFilterType type() const override { + return DlImageFilterType::kLocalMatrix; + } + size_t size() const override { return sizeof(*this); } + + const DlMatrix& matrix() const { return matrix_; } + + const std::shared_ptr image_filter() const { + return image_filter_; + } + + const DlLocalMatrixImageFilter* asLocalMatrix() const override { + return this; + } + + bool modifies_transparent_black() const override; + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + DlMatrix matrix_; + std::shared_ptr image_filter_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_LOCAL_MATRIX_IMAGE_FILTER_H_ diff --git a/display_list/effects/dl_matrix_image_filter.cc b/display_list/effects/dl_matrix_image_filter.cc new file mode 100644 index 0000000000000..87bc08efbef77 --- /dev/null +++ b/display_list/effects/dl_matrix_image_filter.cc @@ -0,0 +1,60 @@ +// 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/display_list/effects/dl_matrix_image_filter.h" + +namespace flutter { + +std::shared_ptr DlMatrixImageFilter::Make( + const DlMatrix& matrix, + DlImageSampling sampling) { + if (matrix.IsFinite() && !matrix.IsIdentity()) { + return std::make_shared(matrix, sampling); + } + return nullptr; +} + +DlRect* DlMatrixImageFilter::map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const { + output_bounds = input_bounds.TransformAndClipBounds(matrix_); + return &output_bounds; +} + +DlIRect* DlMatrixImageFilter::map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + if (!ctm.IsInvertible()) { + output_bounds = input_bounds; + return nullptr; + } + DlMatrix matrix = ctm * matrix_ * ctm.Invert(); + DlRect device_rect = + DlRect::Make(input_bounds).TransformAndClipBounds(matrix); + output_bounds = DlIRect::RoundOut(device_rect); + return &output_bounds; +} + +DlIRect* DlMatrixImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + DlMatrix matrix = ctm * matrix_; + if (!matrix.IsInvertible()) { + input_bounds = output_bounds; + return nullptr; + } + DlMatrix inverse = ctm * matrix.Invert(); + DlRect bounds = DlRect::Make(output_bounds); + bounds = bounds.TransformAndClipBounds(inverse); + input_bounds = DlIRect::RoundOut(bounds); + return &input_bounds; +} + +bool DlMatrixImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kMatrix); + auto that = static_cast(&other); + return (matrix_ == that->matrix_ && sampling_ == that->sampling_); +} + +} // namespace flutter diff --git a/display_list/effects/dl_matrix_image_filter.h b/display_list/effects/dl_matrix_image_filter.h new file mode 100644 index 0000000000000..5d268ad87661b --- /dev/null +++ b/display_list/effects/dl_matrix_image_filter.h @@ -0,0 +1,61 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_MATRIX_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_MATRIX_IMAGE_FILTER_H_ + +#include "display_list/effects/dl_image_filter.h" + +#include "flutter/display_list/dl_sampling_options.h" + +namespace flutter { + +class DlMatrixImageFilter final : public DlImageFilter { + public: + DlMatrixImageFilter(const DlMatrix& matrix, DlImageSampling sampling) + : matrix_(matrix), sampling_(sampling) {} + explicit DlMatrixImageFilter(const DlMatrixImageFilter* filter) + : DlMatrixImageFilter(filter->matrix_, filter->sampling_) {} + DlMatrixImageFilter(const DlMatrixImageFilter& filter) + : DlMatrixImageFilter(&filter) {} + + static std::shared_ptr Make(const DlMatrix& matrix, + DlImageSampling sampling); + + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + DlImageFilterType type() const override { return DlImageFilterType::kMatrix; } + size_t size() const override { return sizeof(*this); } + + const DlMatrix& matrix() const { return matrix_; } + DlImageSampling sampling() const { return sampling_; } + + const DlMatrixImageFilter* asMatrix() const override { return this; } + + bool modifies_transparent_black() const override { return false; } + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + DlMatrix matrix_; + DlImageSampling sampling_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_MATRIX_IMAGE_FILTER_H_ diff --git a/display_list/effects/dl_runtime_effect_image_filter.cc b/display_list/effects/dl_runtime_effect_image_filter.cc new file mode 100644 index 0000000000000..451063a27ff57 --- /dev/null +++ b/display_list/effects/dl_runtime_effect_image_filter.cc @@ -0,0 +1,61 @@ +// 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/display_list/effects/dl_runtime_effect_image_filter.h" + +namespace flutter { + +std::shared_ptr DlRuntimeEffectImageFilter::Make( + sk_sp runtime_effect, + std::vector> samplers, + std::shared_ptr> uniform_data) { + return std::make_shared( + std::move(runtime_effect), std::move(samplers), std::move(uniform_data)); +} + +DlRect* DlRuntimeEffectImageFilter::map_local_bounds( + const DlRect& input_bounds, + DlRect& output_bounds) const { + output_bounds = input_bounds; + return &output_bounds; +} + +DlIRect* DlRuntimeEffectImageFilter::map_device_bounds( + const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const { + output_bounds = input_bounds; + return &output_bounds; +} + +DlIRect* DlRuntimeEffectImageFilter::get_input_device_bounds( + const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const { + input_bounds = output_bounds; + return &input_bounds; +} + +bool DlRuntimeEffectImageFilter::equals_(const DlImageFilter& other) const { + FML_DCHECK(other.type() == DlImageFilterType::kRuntimeEffect); + auto that = static_cast(&other); + if (runtime_effect_ != that->runtime_effect_ || + samplers_.size() != that->samplers().size() || + uniform_data_->size() != that->uniform_data()->size()) { + return false; + } + for (auto i = 0u; i < samplers_.size(); i++) { + if (samplers_[i] != that->samplers()[i]) { + return false; + } + } + for (auto i = 0u; i < uniform_data_->size(); i++) { + if (uniform_data_->at(i) != that->uniform_data()->at(i)) { + return false; + } + } + return true; +} + +} // namespace flutter diff --git a/display_list/effects/dl_runtime_effect_image_filter.h b/display_list/effects/dl_runtime_effect_image_filter.h new file mode 100644 index 0000000000000..dffa42ae0b91c --- /dev/null +++ b/display_list/effects/dl_runtime_effect_image_filter.h @@ -0,0 +1,80 @@ +// 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_DISPLAY_LIST_EFFECTS_DL_RUNTIME_EFFECT_IMAGE_FILTER_H_ +#define FLUTTER_DISPLAY_LIST_EFFECTS_DL_RUNTIME_EFFECT_IMAGE_FILTER_H_ + +#include "display_list/effects/dl_image_filter.h" + +#include "flutter/display_list/effects/dl_color_source.h" +#include "flutter/display_list/effects/dl_runtime_effect.h" + +namespace flutter { + +class DlRuntimeEffectImageFilter final : public DlImageFilter { + public: + explicit DlRuntimeEffectImageFilter( + sk_sp runtime_effect, + std::vector> samplers, + std::shared_ptr> uniform_data) + : runtime_effect_(std::move(runtime_effect)), + samplers_(std::move(samplers)), + uniform_data_(std::move(uniform_data)) {} + + std::shared_ptr shared() const override { + return std::make_shared( + this->runtime_effect_, this->samplers_, this->uniform_data_); + } + + static std::shared_ptr Make( + sk_sp runtime_effect, + std::vector> samplers, + std::shared_ptr> uniform_data); + + DlImageFilterType type() const override { + return DlImageFilterType::kRuntimeEffect; + } + size_t size() const override { return sizeof(*this); } + + bool modifies_transparent_black() const override { return false; } + + DlRect* map_local_bounds(const DlRect& input_bounds, + DlRect& output_bounds) const override; + + DlIRect* map_device_bounds(const DlIRect& input_bounds, + const DlMatrix& ctm, + DlIRect& output_bounds) const override; + + DlIRect* get_input_device_bounds(const DlIRect& output_bounds, + const DlMatrix& ctm, + DlIRect& input_bounds) const override; + + const DlRuntimeEffectImageFilter* asRuntimeEffectFilter() const override { + return this; + } + + const sk_sp runtime_effect() const { + return runtime_effect_; + } + + const std::vector>& samplers() const { + return samplers_; + } + + const std::shared_ptr>& uniform_data() const { + return uniform_data_; + } + + protected: + bool equals_(const DlImageFilter& other) const override; + + private: + sk_sp runtime_effect_; + std::vector> samplers_; + std::shared_ptr> uniform_data_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_EFFECTS_DL_RUNTIME_EFFECT_IMAGE_FILTER_H_ diff --git a/display_list/geometry/dl_geometry_types.h b/display_list/geometry/dl_geometry_types.h index 66ef9a7428464..0021a2b90964d 100644 --- a/display_list/geometry/dl_geometry_types.h +++ b/display_list/geometry/dl_geometry_types.h @@ -23,6 +23,7 @@ using DlDegrees = impeller::Degrees; using DlRadians = impeller::Radians; using DlPoint = impeller::Point; +using DlVector2 = impeller::Vector2; using DlIPoint = impeller::IPoint32; using DlSize = impeller::Size; using DlISize = impeller::ISize32; @@ -30,6 +31,7 @@ using DlRect = impeller::Rect; using DlIRect = impeller::IRect32; using DlRoundRect = impeller::RoundRect; using DlMatrix = impeller::Matrix; +using DlQuad = impeller::Quad; static_assert(sizeof(SkPoint) == sizeof(DlPoint)); static_assert(sizeof(SkIPoint) == sizeof(DlIPoint)); @@ -39,6 +41,19 @@ static_assert(sizeof(SkRect) == sizeof(DlRect)); static_assert(sizeof(SkIRect) == sizeof(DlIRect)); static_assert(sizeof(SkVector) == sizeof(DlSize)); +static constexpr DlScalar kEhCloseEnough = impeller::kEhCloseEnough; + +constexpr inline bool DlScalarNearlyZero(DlScalar x, + DlScalar tolerance = kEhCloseEnough) { + return impeller::ScalarNearlyZero(x, tolerance); +} + +constexpr inline bool DlScalarNearlyEqual(DlScalar x, + DlScalar y, + DlScalar tolerance = kEhCloseEnough) { + return impeller::ScalarNearlyEqual(x, y, tolerance); +} + inline const DlPoint& ToDlPoint(const SkPoint& point) { return *reinterpret_cast(&point); } @@ -131,7 +146,7 @@ inline const SkRect* ToSkRect(const DlRect* rect) { return rect == nullptr ? nullptr : reinterpret_cast(rect); } -inline const SkRect* ToSkRect(std::optional& rect) { +inline const SkRect* ToSkRect(const std::optional& rect) { return rect.has_value() ? &ToSkRect(rect.value()) : nullptr; } diff --git a/display_list/skia/dl_sk_canvas.cc b/display_list/skia/dl_sk_canvas.cc index 3746a88c3e038..1ffc234ac1d4e 100644 --- a/display_list/skia/dl_sk_canvas.cc +++ b/display_list/skia/dl_sk_canvas.cc @@ -6,6 +6,7 @@ #include "flutter/display_list/skia/dl_sk_canvas.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/display_list/skia/dl_sk_conversions.h" #include "flutter/display_list/skia/dl_sk_dispatcher.h" #include "flutter/fml/trace_event.h" @@ -52,7 +53,7 @@ void DlSkCanvasAdapter::Save() { delegate_->save(); } -void DlSkCanvasAdapter::SaveLayer(std::optional& bounds, +void DlSkCanvasAdapter::SaveLayer(const std::optional& bounds, const DlPaint* paint, const DlImageFilter* backdrop, std::optional backdrop_id) { diff --git a/display_list/skia/dl_sk_canvas.h b/display_list/skia/dl_sk_canvas.h index 70b0ffa97b95b..3a42c3a61f2e5 100644 --- a/display_list/skia/dl_sk_canvas.h +++ b/display_list/skia/dl_sk_canvas.h @@ -30,7 +30,7 @@ class DlSkCanvasAdapter final : public virtual DlCanvas { SkImageInfo GetImageInfo() const override; void Save() override; - void SaveLayer(std::optional& bounds, + void SaveLayer(const std::optional& bounds, const DlPaint* paint = nullptr, const DlImageFilter* backdrop = nullptr, std::optional backdrop_id = std::nullopt) override; diff --git a/display_list/skia/dl_sk_conversions.cc b/display_list/skia/dl_sk_conversions.cc index de0db51cb73ae..0db0e1ed3a958 100644 --- a/display_list/skia/dl_sk_conversions.cc +++ b/display_list/skia/dl_sk_conversions.cc @@ -4,6 +4,7 @@ #include "flutter/display_list/skia/dl_sk_conversions.h" +#include "flutter/display_list/effects/dl_image_filters.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "third_party/skia/include/effects/SkImageFilters.h" @@ -203,7 +204,8 @@ sk_sp ToSk(const DlImageFilter* filter) { const DlMatrixImageFilter* matrix_filter = filter->asMatrix(); FML_DCHECK(matrix_filter != nullptr); return SkImageFilters::MatrixTransform( - matrix_filter->matrix(), ToSk(matrix_filter->sampling()), nullptr); + ToSkMatrix(matrix_filter->matrix()), ToSk(matrix_filter->sampling()), + nullptr); } case DlImageFilterType::kCompose: { const DlComposeImageFilter* compose_filter = filter->asCompose(); @@ -229,7 +231,7 @@ sk_sp ToSk(const DlImageFilter* filter) { if (!skia_filter) { return nullptr; } - return skia_filter->makeWithLocalMatrix(lm_filter->matrix()); + return skia_filter->makeWithLocalMatrix(ToSkMatrix(lm_filter->matrix())); } case DlImageFilterType::kRuntimeEffect: // UNSUPPORTED. diff --git a/display_list/skia/dl_sk_conversions.h b/display_list/skia/dl_sk_conversions.h index 808d9842efd43..1e6a05cd16731 100644 --- a/display_list/skia/dl_sk_conversions.h +++ b/display_list/skia/dl_sk_conversions.h @@ -86,8 +86,7 @@ inline sk_sp ToSk(const DlColorSource& source) { } extern sk_sp ToSk(const DlImageFilter* filter); -inline sk_sp ToSk( - const std::shared_ptr& filter) { +inline sk_sp ToSk(const std::shared_ptr& filter) { return ToSk(filter.get()); } inline sk_sp ToSk(const DlImageFilter& filter) { diff --git a/display_list/skia/dl_sk_conversions_unittests.cc b/display_list/skia/dl_sk_conversions_unittests.cc index 575113b9f64ba..368caf13672dc 100644 --- a/display_list/skia/dl_sk_conversions_unittests.cc +++ b/display_list/skia/dl_sk_conversions_unittests.cc @@ -7,7 +7,9 @@ #include "flutter/display_list/dl_sampling_options.h" #include "flutter/display_list/dl_tile_mode.h" #include "flutter/display_list/dl_vertices.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/display_list/effects/dl_color_source.h" +#include "flutter/display_list/effects/dl_local_matrix_image_filter.h" #include "flutter/display_list/skia/dl_sk_conversions.h" #include "gtest/gtest.h" #include "third_party/skia/include/core/SkColorSpace.h" @@ -18,10 +20,9 @@ namespace flutter { namespace testing { TEST(DisplayListImageFilter, LocalImageSkiaNull) { - auto blur_filter = - std::make_shared(0, 0, DlTileMode::kClamp); - DlLocalMatrixImageFilter dl_local_matrix_filter(SkMatrix::RotateDeg(45), - blur_filter); + auto blur_filter = DlBlurImageFilter::Make(0, 0, DlTileMode::kClamp); + DlLocalMatrixImageFilter dl_local_matrix_filter( + DlMatrix::MakeRotationZ(DlDegrees(45)), blur_filter); // With sigmas set to zero on the blur filter, Skia will return a null filter. // The local matrix filter should return nullptr instead of crashing. ASSERT_EQ(ToSk(dl_local_matrix_filter), nullptr); diff --git a/display_list/skia/dl_sk_dispatcher.cc b/display_list/skia/dl_sk_dispatcher.cc index c79542d01e1f9..eca791a1bdbbe 100644 --- a/display_list/skia/dl_sk_dispatcher.cc +++ b/display_list/skia/dl_sk_dispatcher.cc @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/display_list/skia/dl_sk_dispatcher.h" #include +#include "flutter/display_list/skia/dl_sk_dispatcher.h" + #include "flutter/display_list/dl_blend_mode.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/display_list/skia/dl_sk_conversions.h" #include "flutter/display_list/skia/dl_sk_types.h" #include "flutter/fml/trace_event.h" diff --git a/display_list/skia/dl_sk_paint_dispatcher_unittests.cc b/display_list/skia/dl_sk_paint_dispatcher_unittests.cc index 808204dd33db2..405c6cbeb5cdf 100644 --- a/display_list/skia/dl_sk_paint_dispatcher_unittests.cc +++ b/display_list/skia/dl_sk_paint_dispatcher_unittests.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "display_list/effects/dl_color_source.h" +#include "flutter/display_list/effects/dl_color_source.h" #include "flutter/display_list/skia/dl_sk_paint_dispatcher.h" #include "flutter/display_list/skia/dl_sk_dispatcher.h" diff --git a/display_list/testing/dl_rendering_unittests.cc b/display_list/testing/dl_rendering_unittests.cc index 2bca5d6b1ef44..9c85527225645 100644 --- a/display_list/testing/dl_rendering_unittests.cc +++ b/display_list/testing/dl_rendering_unittests.cc @@ -8,6 +8,7 @@ #include "flutter/display_list/dl_builder.h" #include "flutter/display_list/dl_op_flags.h" #include "flutter/display_list/dl_sampling_options.h" +#include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/skia/dl_sk_canvas.h" #include "flutter/display_list/skia/dl_sk_conversions.h" #include "flutter/display_list/skia/dl_sk_dispatcher.h" @@ -3939,8 +3940,10 @@ TEST_F(DisplayListRendering, SaveLayerConsolidation) { 0, 0, 0, .7, 0, // clang-format on }; - SkMatrix contract_matrix; - contract_matrix.setScale(0.9f, 0.9f, kRenderCenterX, kRenderCenterY); + DlMatrix contract_matrix; + contract_matrix.Translate({kRenderCenterX, kRenderCenterY}); + contract_matrix.Scale({0.9f, 0.9f}); + contract_matrix.Translate({kRenderCenterX, kRenderCenterY}); std::vector opacities = { 0, @@ -3956,11 +3959,10 @@ TEST_F(DisplayListRendering, SaveLayerConsolidation) { DlLinearToSrgbGammaColorFilter::kInstance, }; std::vector> image_filters = { - std::make_shared(5.0f, 5.0f, DlTileMode::kDecal), - std::make_shared(5.0f, 5.0f), - std::make_shared(5.0f, 5.0f), - std::make_shared(contract_matrix, - DlImageSampling::kLinear), + DlBlurImageFilter::Make(5.0f, 5.0f, DlTileMode::kDecal), + DlDilateImageFilter::Make(5.0f, 5.0f), + DlErodeImageFilter::Make(5.0f, 5.0f), + DlMatrixImageFilter::Make(contract_matrix, DlImageSampling::kLinear), }; auto render_content = [](DisplayListBuilder& builder) { @@ -4603,7 +4605,7 @@ class DisplayListNopTest : public DisplayListRendering { desc_stream << BlendModeToString(mode); desc_stream << "/" << color; std::string desc = desc_stream.str(); - DisplayListBuilder builder({0.0f, 0.0f, 100.0f, 100.0f}); + DisplayListBuilder builder(DlRect::MakeWH(100.0f, 100.0f)); DlPaint paint = DlPaint(color).setBlendMode(mode); builder.DrawRect(SkRect{0.0f, 0.0f, 10.0f, 10.0f}, paint); auto dl = builder.Build(); @@ -4697,7 +4699,7 @@ class DisplayListNopTest : public DisplayListRendering { desc_stream << ", IF: " << if_mtb; std::string desc = desc_stream.str(); - DisplayListBuilder builder({0.0f, 0.0f, 100.0f, 100.0f}); + DisplayListBuilder builder(DlRect::MakeWH(100.0f, 100.0f)); DlPaint paint = DlPaint(color) // .setBlendMode(mode) // .setColorFilter(color_filter) // diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc index 3ce6e7ce1b11b..ccc25a2dbea81 100644 --- a/display_list/testing/dl_test_snippets.cc +++ b/display_list/testing/dl_test_snippets.cc @@ -177,15 +177,15 @@ std::vector CreateAllAttributesOps() { [](DlOpReceiver& r) { r.setImageFilter(&kTestErodeImageFilter2); }}, {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestErodeImageFilter3); }}, - {0, 64, 0, + {0, 88, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestMatrixImageFilter1); }}, - {0, 64, 0, + {0, 88, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestMatrixImageFilter2); }}, - {0, 64, 0, + {0, 88, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestMatrixImageFilter3); }}, @@ -209,7 +209,7 @@ std::vector CreateAllAttributesOps() { [](DlOpReceiver& r) { r.setImageFilter( kTestBlurImageFilter1 - .makeWithLocalMatrix(SkMatrix::Translate(2, 2)) + .makeWithLocalMatrix(DlMatrix::MakeTranslation({2, 2})) .get()); }}, diff --git a/display_list/testing/dl_test_snippets.h b/display_list/testing/dl_test_snippets.h index 055d7725e3eb5..3de3b39bffbef 100644 --- a/display_list/testing/dl_test_snippets.h +++ b/display_list/testing/dl_test_snippets.h @@ -7,6 +7,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/dl_builder.h" +#include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/testing/testing.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -150,13 +151,13 @@ static const DlErodeImageFilter kTestErodeImageFilter1(4.0, 4.0); static const DlErodeImageFilter kTestErodeImageFilter2(4.0, 3.0); static const DlErodeImageFilter kTestErodeImageFilter3(3.0, 4.0); static const DlMatrixImageFilter kTestMatrixImageFilter1( - SkMatrix::RotateDeg(45), + DlMatrix::MakeRotationZ(DlDegrees(45)), kNearestSampling); static const DlMatrixImageFilter kTestMatrixImageFilter2( - SkMatrix::RotateDeg(85), + DlMatrix::MakeRotationZ(DlDegrees(85)), kNearestSampling); static const DlMatrixImageFilter kTestMatrixImageFilter3( - SkMatrix::RotateDeg(45), + DlMatrix::MakeRotationZ(DlDegrees(45)), kLinearSampling); static const DlComposeImageFilter kTestComposeImageFilter1( kTestBlurImageFilter1, diff --git a/display_list/utils/dl_matrix_clip_tracker.cc b/display_list/utils/dl_matrix_clip_tracker.cc index 76d8fd4e64d95..a7f4c316190f7 100644 --- a/display_list/utils/dl_matrix_clip_tracker.cc +++ b/display_list/utils/dl_matrix_clip_tracker.cc @@ -241,7 +241,7 @@ DlRect DisplayListMatrixClipState::GetLocalCullCoverage() const { // We could do a 4-point long-form conversion, but since this is // only used for culling, let's just return a non-constricting // cull rect. - return ToDlRect(DisplayListBuilder::kMaxCullRect); + return DisplayListBuilder::kMaxCullRect; } DlMatrix inverse = matrix_.Invert(); // We eliminated perspective above so we can use the cheaper non-clipping diff --git a/display_list/utils/dl_matrix_clip_tracker.h b/display_list/utils/dl_matrix_clip_tracker.h index 344a54bd57ff8..1bcf67b6978d9 100644 --- a/display_list/utils/dl_matrix_clip_tracker.h +++ b/display_list/utils/dl_matrix_clip_tracker.h @@ -53,7 +53,7 @@ class DisplayListMatrixClipState { } bool using_4x4_matrix() const { return !matrix_.IsAffine(); } - bool is_matrix_invertable() const { return matrix_.GetDeterminant() != 0.0f; } + bool is_matrix_invertable() const { return matrix_.IsInvertible(); } bool has_perspective() const { return matrix_.HasPerspective(); } const DlMatrix& matrix() const { return matrix_; } diff --git a/flow/diff_context.cc b/flow/diff_context.cc index 6bcf444f008b7..aca12f6e8538b 100644 --- a/flow/diff_context.cc +++ b/flow/diff_context.cc @@ -166,6 +166,10 @@ bool DiffContext::PushCullRect(const SkRect& clip) { return !state_.matrix_clip.device_cull_rect().isEmpty(); } +const DlMatrix& DiffContext::GetMatrix() const { + return state_.matrix_clip.matrix(); +} + SkMatrix DiffContext::GetTransform3x3() const { return state_.matrix_clip.matrix_3x3(); } diff --git a/flow/diff_context.h b/flow/diff_context.h index 0eb536c49cbe4..9195ce0af7237 100644 --- a/flow/diff_context.h +++ b/flow/diff_context.h @@ -88,6 +88,9 @@ class DiffContext { // Instruct DiffContext that current layer will paint with integral transform. void WillPaintWithIntegralTransform() { state_.integral_transform = true; } + // Returns current transform as DlMatrix. + const DlMatrix& GetMatrix() const; + // Returns current transform as SkMatrix. SkMatrix GetTransform3x3() const; diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index b0d17870a707b..cb0faf33dae82 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -84,7 +84,7 @@ void MutatorsStack::PushOpacity(const int& alpha) { } void MutatorsStack::PushBackdropFilter( - const std::shared_ptr& filter, + const std::shared_ptr& filter, const SkRect& filter_rect) { std::shared_ptr element = std::make_shared(filter, filter_rect); diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 028fbd216a4aa..594ef93cdaa68 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -50,7 +50,7 @@ enum MutatorType { // https://github.com/flutter/flutter/issues/108470 class ImageFilterMutation { public: - ImageFilterMutation(std::shared_ptr filter, + ImageFilterMutation(std::shared_ptr filter, const SkRect& filter_rect) : filter_(std::move(filter)), filter_rect_(filter_rect) {} @@ -66,7 +66,7 @@ class ImageFilterMutation { } private: - std::shared_ptr filter_; + std::shared_ptr filter_; const SkRect filter_rect_; }; @@ -111,7 +111,7 @@ class Mutator { explicit Mutator(const SkMatrix& matrix) : type_(kTransform), matrix_(matrix) {} explicit Mutator(const int& alpha) : type_(kOpacity), alpha_(alpha) {} - explicit Mutator(const std::shared_ptr& filter, + explicit Mutator(const std::shared_ptr& filter, const SkRect& filter_rect) : type_(kBackdropFilter), filter_mutation_( @@ -197,7 +197,7 @@ class MutatorsStack { void PushTransform(const SkMatrix& matrix); void PushOpacity(const int& alpha); // `filter_rect` is in global coordinates. - void PushBackdropFilter(const std::shared_ptr& filter, + void PushBackdropFilter(const std::shared_ptr& filter, const SkRect& filter_rect); // Removes the `Mutator` on the top of the stack @@ -296,7 +296,7 @@ class EmbeddedViewParams { // Pushes the stored DlImageFilter object to the mutators stack. // // `filter_rect` is in global coordinates. - void PushImageFilter(const std::shared_ptr& filter, + void PushImageFilter(const std::shared_ptr& filter, const SkRect& filter_rect) { mutators_stack_.PushBackdropFilter(filter, filter_rect); } @@ -510,7 +510,7 @@ class ExternalViewEmbedder { // See also: |PushVisitedPlatformView| for pushing platform view ids to the // visited platform views list. virtual void PushFilterToVisitedPlatformViews( - const std::shared_ptr& filter, + const std::shared_ptr& filter, const SkRect& filter_rect) {} private: diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index aec04bafae872..7941101202416 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -7,12 +7,10 @@ namespace flutter { BackdropFilterLayer::BackdropFilterLayer( - std::shared_ptr filter, + const std::shared_ptr& filter, DlBlendMode blend_mode, std::optional backdrop_id) - : filter_(std::move(filter)), - blend_mode_(blend_mode), - backdrop_id_(backdrop_id) {} + : filter_(filter), blend_mode_(blend_mode), backdrop_id_(backdrop_id) {} void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { DiffContext::AutoSubtreeRestore subtree(context); @@ -31,10 +29,11 @@ void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { if (filter_) { paint_bounds = context->MapRect(paint_bounds); auto filter_target_bounds = paint_bounds.roundOut(); - SkIRect filter_input_bounds; // in screen coordinates - filter_->get_input_device_bounds( - filter_target_bounds, context->GetTransform3x3(), filter_input_bounds); - context->AddReadbackRegion(filter_target_bounds, filter_input_bounds); + DlIRect filter_input_bounds; // in screen coordinates + filter_->get_input_device_bounds(ToDlIRect(filter_target_bounds), + context->GetMatrix(), filter_input_bounds); + context->AddReadbackRegion(filter_target_bounds, + ToSkIRect(filter_input_bounds)); } DiffChildren(context, prev); diff --git a/flow/layers/backdrop_filter_layer.h b/flow/layers/backdrop_filter_layer.h index 180c5a641341a..76c61975e986d 100644 --- a/flow/layers/backdrop_filter_layer.h +++ b/flow/layers/backdrop_filter_layer.h @@ -6,13 +6,12 @@ #define FLUTTER_FLOW_LAYERS_BACKDROP_FILTER_LAYER_H_ #include "flutter/flow/layers/container_layer.h" -#include "third_party/skia/include/core/SkImageFilter.h" namespace flutter { class BackdropFilterLayer : public ContainerLayer { public: - BackdropFilterLayer(std::shared_ptr filter, + BackdropFilterLayer(const std::shared_ptr& filter, DlBlendMode blend_mode, std::optional backdrop_id = std::nullopt); @@ -23,7 +22,7 @@ class BackdropFilterLayer : public ContainerLayer { void Paint(PaintContext& context) const override; private: - std::shared_ptr filter_; + std::shared_ptr filter_; DlBlendMode blend_mode_; std::optional backdrop_id_; diff --git a/flow/layers/backdrop_filter_layer_unittests.cc b/flow/layers/backdrop_filter_layer_unittests.cc index a796bffb2a0cb..11c8cd7a84b9e 100644 --- a/flow/layers/backdrop_filter_layer_unittests.cc +++ b/flow/layers/backdrop_filter_layer_unittests.cc @@ -3,8 +3,9 @@ // found in the LICENSE file. #include "flutter/flow/layers/backdrop_filter_layer.h" -#include "flutter/flow/layers/clip_rect_layer.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" +#include "flutter/display_list/effects/dl_matrix_image_filter.h" #include "flutter/flow/layers/clip_rect_layer.h" #include "flutter/flow/layers/transform_layer.h" #include "flutter/flow/testing/diff_context_test.h" @@ -100,8 +101,7 @@ TEST_F(BackdropFilterLayerTest, SimpleFilter) { 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(2.5, 3.2, DlTileMode::kClamp); + auto layer_filter = DlBlurImageFilter::Make(2.5, 3.2, DlTileMode::kClamp); auto mock_layer = std::make_shared(child_path, child_paint); auto layer = std::make_shared(layer_filter, DlBlendMode::kSrcOver); @@ -148,8 +148,7 @@ TEST_F(BackdropFilterLayerTest, NonSrcOverBlend) { 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(2.5, 3.2, DlTileMode::kClamp); + auto layer_filter = DlBlurImageFilter::Make(2.5, 3.2, DlTileMode::kClamp); auto mock_layer = std::make_shared(child_path, child_paint); auto layer = std::make_shared(layer_filter, DlBlendMode::kSrc); @@ -205,8 +204,7 @@ TEST_F(BackdropFilterLayerTest, MultipleChildren) { 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(2.5, 3.2, DlTileMode::kClamp); + auto layer_filter = DlBlurImageFilter::Make(2.5, 3.2, DlTileMode::kClamp); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); auto layer = std::make_shared(layer_filter, @@ -269,10 +267,8 @@ TEST_F(BackdropFilterLayerTest, Nested) { 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(2.5, 3.2, DlTileMode::kClamp); - auto layer_filter2 = - std::make_shared(2.7, 3.1, DlTileMode::kDecal); + auto layer_filter1 = DlBlurImageFilter::Make(2.5, 3.2, DlTileMode::kClamp); + auto layer_filter2 = DlBlurImageFilter::Make(2.7, 3.1, DlTileMode::kDecal); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); auto layer1 = std::make_shared(layer_filter1, @@ -428,11 +424,11 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { { // 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), + DlIRect readback; + EXPECT_EQ(filter.get_input_device_bounds(DlIRect::MakeWH(10, 10), + DlMatrix(), readback), &readback); - EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); + EXPECT_EQ(readback, DlIRect::MakeLTRB(-30, -30, 40, 40)); } MockLayerTree l1(SkISize::Make(100, 100)); @@ -482,7 +478,7 @@ TEST_F(BackdropLayerDiffTest, BackdropLayer) { } TEST_F(BackdropLayerDiffTest, ReadbackOutsideOfPaintArea) { - auto filter = DlMatrixImageFilter(SkMatrix::Translate(50, 50), + auto filter = DlMatrixImageFilter(DlMatrix::MakeTranslation({50, 50}), DlImageSampling::kLinear); MockLayerTree l1(SkISize::Make(100, 100)); @@ -511,11 +507,11 @@ TEST_F(BackdropLayerDiffTest, BackdropLayerInvalidTransform) { { // 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), + DlIRect readback; + EXPECT_EQ(filter.get_input_device_bounds(DlIRect::MakeWH(10, 10), + DlMatrix(), readback), &readback); - EXPECT_EQ(readback, SkIRect::MakeLTRB(-30, -30, 40, 40)); + EXPECT_EQ(readback, DlIRect::MakeLTRB(-30, -30, 40, 40)); } MockLayerTree l1(SkISize::Make(100, 100)); diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 31c1f3a8e0be1..1fa13acd47d6c 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -10,12 +10,12 @@ namespace flutter { -ImageFilterLayer::ImageFilterLayer(std::shared_ptr filter, +ImageFilterLayer::ImageFilterLayer(const std::shared_ptr& filter, const SkPoint& offset) : CacheableContainerLayer( RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer), offset_(offset), - filter_(std::move(filter)), + filter_(filter), transformed_filter_(nullptr) {} void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { @@ -34,14 +34,14 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { } if (filter_) { - auto filter = filter_->makeWithLocalMatrix(context->GetTransform3x3()); + auto filter = filter_->makeWithLocalMatrix(context->GetMatrix()); if (filter) { // This transform will be applied to every child rect in the subtree context->PushFilterBoundsAdjustment([filter](SkRect rect) { - SkIRect filter_out_bounds; - filter->map_device_bounds(rect.roundOut(), SkMatrix::I(), + DlIRect filter_out_bounds; + filter->map_device_bounds(ToDlIRect(rect.roundOut()), DlMatrix(), filter_out_bounds); - return SkRect::Make(filter_out_bounds); + return SkRect::Make(ToSkIRect(filter_out_bounds)); }); } } @@ -78,11 +78,10 @@ void ImageFilterLayer::Preroll(PrerollContext* context) { (LayerStateStack::kCallerCanApplyOpacity | LayerStateStack::kCallerCanApplyColorFilter); - const SkIRect filter_in_bounds = child_bounds.roundOut(); - SkIRect filter_out_bounds; - filter_->map_device_bounds(filter_in_bounds, SkMatrix::I(), - filter_out_bounds); - child_bounds.set(filter_out_bounds); + const DlIRect filter_in_bounds = ToDlIRect(child_bounds.roundOut()); + DlIRect filter_out_bounds; + filter_->map_device_bounds(filter_in_bounds, DlMatrix(), filter_out_bounds); + child_bounds.set(ToSkIRect(filter_out_bounds)); child_bounds.offset(offset_); set_paint_bounds(child_bounds); @@ -94,7 +93,7 @@ void ImageFilterLayer::Preroll(PrerollContext* context) { #endif // !SLIMPELLER transformed_filter_ = - filter_->makeWithLocalMatrix(context->state_stack.transform_3x3()); + filter_->makeWithLocalMatrix(context->state_stack.matrix()); #if !SLIMPELLER if (transformed_filter_) { diff --git a/flow/layers/image_filter_layer.h b/flow/layers/image_filter_layer.h index b96937da1425a..bd8172c295e13 100644 --- a/flow/layers/image_filter_layer.h +++ b/flow/layers/image_filter_layer.h @@ -12,7 +12,7 @@ namespace flutter { class ImageFilterLayer : public CacheableContainerLayer { public: - explicit ImageFilterLayer(std::shared_ptr filter, + explicit ImageFilterLayer(const std::shared_ptr& filter, const SkPoint& offset = SkPoint::Make(0, 0)); void Diff(DiffContext* context, const Layer* old_layer) override; @@ -23,8 +23,8 @@ class ImageFilterLayer : public CacheableContainerLayer { private: SkPoint offset_; - std::shared_ptr filter_; - std::shared_ptr transformed_filter_; + const std::shared_ptr filter_; + std::shared_ptr transformed_filter_; FML_DISALLOW_COPY_AND_ASSIGN(ImageFilterLayer); }; diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 17ed929dd3b08..405d6a44377d7 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/display_list/dl_tile_mode.h" #include "flutter/flow/layers/image_filter_layer.h" +#include "flutter/display_list/dl_tile_mode.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" +#include "flutter/display_list/effects/dl_matrix_image_filter.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/layers/transform_layer.h" #include "flutter/flow/testing/diff_context_test.h" @@ -82,14 +84,14 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { 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 dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); auto mock_layer = std::make_shared(child_path, child_paint); auto layer = std::make_shared(dl_image_filter); layer->Add(mock_layer); const SkRect child_rounded_bounds = - SkRect::MakeLTRB(5.0f, 6.0f, 21.0f, 22.0f); + SkRect::MakeLTRB(6.0f, 8.0f, 22.0f, 24.0f); preroll_context()->state_stack.set_preroll_delegate(initial_transform); layer->Preroll(preroll_context()); @@ -123,8 +125,8 @@ TEST_F(ImageFilterLayerTest, SimpleFilterWithOffset) { const SkPath child_path = SkPath().addRect(child_bounds); const DlPaint child_paint = DlPaint(DlColor::kYellow()); const SkPoint layer_offset = SkPoint::Make(5.5, 6.5); - auto dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); auto mock_layer = std::make_shared(child_path, child_paint); auto layer = std::make_shared(dl_image_filter, layer_offset); @@ -133,7 +135,7 @@ TEST_F(ImageFilterLayerTest, SimpleFilterWithOffset) { SkMatrix child_matrix = initial_transform; child_matrix.preTranslate(layer_offset.fX, layer_offset.fY); const SkRect child_rounded_bounds = - SkRect::MakeLTRB(10.5f, 12.5f, 26.5f, 28.5f); + SkRect::MakeLTRB(11.5f, 14.5f, 27.5f, 30.5f); preroll_context()->state_stack.set_preroll_delegate(initial_cull_rect, initial_transform); @@ -173,9 +175,9 @@ TEST_F(ImageFilterLayerTest, SimpleFilterBounds) { 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()); - const SkMatrix filter_transform = SkMatrix::Scale(2.0, 2.0); + const DlMatrix filter_transform = DlMatrix::MakeScale({2.0, 2.0, 1}); - auto dl_image_filter = std::make_shared( + auto dl_image_filter = DlMatrixImageFilter::Make( filter_transform, DlImageSampling::kMipmapLinear); auto mock_layer = std::make_shared(child_path, child_paint); auto layer = std::make_shared(dl_image_filter); @@ -216,8 +218,8 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) { SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f)); const DlPaint child_paint1 = DlPaint(DlColor::kYellow()); const DlPaint child_paint2 = DlPaint(DlColor::kCyan()); - auto dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); auto layer = std::make_shared(dl_image_filter); @@ -226,7 +228,8 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) { SkRect children_bounds = child_path1.getBounds(); children_bounds.join(child_path2.getBounds()); - SkRect children_rounded_bounds = SkRect::Make(children_bounds.roundOut()); + SkRect children_rounded_bounds = + SkRect::Make(children_bounds.roundOut()).makeOffset(1.0f, 2.0f); preroll_context()->state_stack.set_preroll_delegate(initial_transform); layer->Preroll(preroll_context()); @@ -269,10 +272,10 @@ TEST_F(ImageFilterLayerTest, Nested) { SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f)); const DlPaint child_paint1 = DlPaint(DlColor::kYellow()); const DlPaint child_paint2 = DlPaint(DlColor::kCyan()); - auto dl_image_filter1 = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); - auto dl_image_filter2 = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter1 = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); + auto dl_image_filter2 = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({3.0, 4.0}), DlImageSampling::kMipmapLinear); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); auto layer1 = std::make_shared(dl_image_filter1); @@ -281,20 +284,31 @@ TEST_F(ImageFilterLayerTest, Nested) { layer1->Add(mock_layer1); layer1->Add(layer2); - SkRect children_bounds = child_path1.getBounds(); - children_bounds.join(SkRect::Make(child_path2.getBounds().roundOut())); - const SkRect children_rounded_bounds = - SkRect::Make(children_bounds.roundOut()); - const SkRect mock_layer2_rounded_bounds = - SkRect::Make(child_path2.getBounds().roundOut()); + // Filter(translate by 1, 2) + // / | + // Mock(child_path1) Filter(translate by 3, 4) + // | + // Mock(child_path2 (shifted (3, 0))) + + SkRect filter2_bounds = SkRect::Make( // + child_path2 + .getBounds() // includes shift(3, 0) on child_path2 + .makeOffset(3.0, 4.0) // filter2 translation + .roundOut()); + SkRect filter1_child_bounds = child_path1.getBounds(); + filter1_child_bounds.join(filter2_bounds); + SkRect filter1_bounds = SkRect::Make( // + filter1_child_bounds // no shift on child_path1 + .makeOffset(1.0, 2.0) // filter1 translation + .roundOut()); preroll_context()->state_stack.set_preroll_delegate(initial_transform); layer1->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_rounded_bounds); - EXPECT_EQ(layer1->child_paint_bounds(), children_bounds); - EXPECT_EQ(layer2->paint_bounds(), mock_layer2_rounded_bounds); + EXPECT_EQ(layer1->paint_bounds(), filter1_bounds); + EXPECT_EQ(layer1->child_paint_bounds(), filter1_child_bounds); + EXPECT_EQ(layer2->paint_bounds(), filter2_bounds); EXPECT_EQ(layer2->child_paint_bounds(), child_path2.getBounds()); EXPECT_TRUE(mock_layer1->needs_painting(paint_context())); EXPECT_TRUE(mock_layer2->needs_painting(paint_context())); @@ -307,7 +321,7 @@ TEST_F(ImageFilterLayerTest, Nested) { /* ImageFilterLayer::Paint() */ { DlPaint dl_paint; dl_paint.setImageFilter(dl_image_filter1.get()); - expected_builder.SaveLayer(&children_bounds, &dl_paint); + expected_builder.SaveLayer(&filter1_child_bounds, &dl_paint); { /* MockLayer::Paint() */ { expected_builder.DrawPath(child_path1, DlPaint(DlColor::kYellow())); @@ -331,8 +345,8 @@ TEST_F(ImageFilterLayerTest, Nested) { } TEST_F(ImageFilterLayerTest, Readback) { - auto dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kLinear); // ImageFilterLayer does not read from surface auto layer = std::make_shared(dl_image_filter); @@ -350,8 +364,8 @@ TEST_F(ImageFilterLayerTest, Readback) { } TEST_F(ImageFilterLayerTest, CacheChild) { - auto dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); @@ -384,6 +398,9 @@ TEST_F(ImageFilterLayerTest, CacheChild) { // his children EXPECT_EQ(cacheable_image_filter_item->cache_state(), RasterCacheItem::CacheState::kChildren); + // We assert here because the lines after it will crash if this is not true + // (It will generally only fail if another EXPECT test above also fails) + ASSERT_TRUE(cacheable_image_filter_item->GetId().has_value()); EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(), cache_canvas, &paint)); EXPECT_FALSE(raster_cache()->Draw( @@ -391,8 +408,8 @@ TEST_F(ImageFilterLayerTest, CacheChild) { } TEST_F(ImageFilterLayerTest, CacheChildren) { - auto dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); DlPaint paint; @@ -431,6 +448,9 @@ TEST_F(ImageFilterLayerTest, CacheChildren) { // children EXPECT_EQ(cacheable_image_filter_item->cache_state(), RasterCacheItem::CacheState::kChildren); + // We assert here because the lines after it will crash if this is not true + // (It will generally only fail if another EXPECT test above also fails) + ASSERT_TRUE(cacheable_image_filter_item->GetId().has_value()); EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(), cache_canvas, &paint)); EXPECT_FALSE(raster_cache()->Draw( @@ -446,7 +466,8 @@ TEST_F(ImageFilterLayerTest, CacheChildren) { 0, 0, 1); SkMatrix cache_matrix = initial_transform; cache_matrix.preConcat(snapped_matrix); - auto transformed_filter = dl_image_filter->makeWithLocalMatrix(cache_matrix); + auto transformed_filter = + dl_image_filter->makeWithLocalMatrix(ToDlMatrix(cache_matrix)); layer->Paint(display_list_paint_context()); DisplayListBuilder expected_builder; @@ -468,8 +489,8 @@ TEST_F(ImageFilterLayerTest, CacheChildren) { } TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) { - auto dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); @@ -570,8 +591,8 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { 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 dl_image_filter = std::make_shared( - SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter = DlMatrixImageFilter::Make( + DlMatrix::MakeTranslation({1.0, 2.0}), DlImageSampling::kMipmapLinear); // The mock_layer child will not be compatible with opacity auto mock_layer = MockLayer::Make(child_path, child_paint); @@ -623,14 +644,13 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { using ImageFilterLayerDiffTest = DiffContextTest; TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { - auto dl_blur_filter = - std::make_shared(10, 10, DlTileMode::kClamp); + auto dl_blur_filter = DlBlurImageFilter::Make(10, 10, DlTileMode::kClamp); { // tests later assume 30px paint area, fail early if that's not the case - SkIRect input_bounds; - dl_blur_filter->get_input_device_bounds(SkIRect::MakeWH(10, 10), - SkMatrix::I(), input_bounds); - EXPECT_EQ(input_bounds, SkIRect::MakeLTRB(-30, -30, 40, 40)); + DlIRect input_bounds; + dl_blur_filter->get_input_device_bounds(DlIRect::MakeWH(10, 10), DlMatrix(), + input_bounds); + EXPECT_EQ(input_bounds, DlIRect::MakeLTRB(-30, -30, 40, 40)); } MockLayerTree l1; @@ -670,15 +690,14 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { } TEST_F(ImageFilterLayerDiffTest, ImageFilterLayerInflatestChildSize) { - auto dl_blur_filter = - std::make_shared(10, 10, DlTileMode::kClamp); + auto dl_blur_filter = DlBlurImageFilter::Make(10, 10, DlTileMode::kClamp); { // tests later assume 30px paint area, fail early if that's not the case - SkIRect input_bounds; - dl_blur_filter->get_input_device_bounds(SkIRect::MakeWH(10, 10), - SkMatrix::I(), input_bounds); - EXPECT_EQ(input_bounds, SkIRect::MakeLTRB(-30, -30, 40, 40)); + DlIRect input_bounds; + dl_blur_filter->get_input_device_bounds(DlIRect::MakeWH(10, 10), DlMatrix(), + input_bounds); + EXPECT_EQ(input_bounds, DlIRect::MakeLTRB(-30, -30, 40, 40)); } MockLayerTree l1; diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 15cf79548edde..07ab3cc864b18 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -35,6 +35,10 @@ class DummyDelegate : public LayerStateStack::Delegate { error(); return {}; } + DlMatrix matrix() const override { + error(); + return dummy_matrix_; + } SkM44 matrix_4x4() const override { error(); return {}; @@ -69,6 +73,7 @@ class DummyDelegate : public LayerStateStack::Delegate { static void error() { FML_DCHECK(false) << "LayerStateStack state queried without a delegate"; } + const DlMatrix dummy_matrix_; }; const std::shared_ptr DummyDelegate::kInstance = std::make_shared(); @@ -88,6 +93,7 @@ class DlCanvasDelegate : public LayerStateStack::Delegate { SkRect device_cull_rect() const override { return canvas_->GetDestinationClipBounds(); } + DlMatrix matrix() const override { return canvas_->GetMatrix(); } SkM44 matrix_4x4() const override { return canvas_->GetTransformFullPerspective(); } @@ -147,6 +153,7 @@ class PrerollDelegate : public LayerStateStack::Delegate { void decommission() override {} + DlMatrix matrix() const override { return state().matrix(); } SkM44 matrix_4x4() const override { return state().matrix_4x4(); } SkMatrix matrix_3x3() const override { return state().matrix_3x3(); } SkRect local_cull_rect() const override { return state().local_cull_rect(); } @@ -282,7 +289,7 @@ class OpacityEntry : public LayerStateStack::StateEntry { class ImageFilterEntry : public LayerStateStack::StateEntry { public: ImageFilterEntry(const SkRect& bounds, - const std::shared_ptr& filter, + const std::shared_ptr& filter, const LayerStateStack::RenderingAttributes& prev) : bounds_(bounds), filter_(filter), @@ -304,8 +311,8 @@ class ImageFilterEntry : public LayerStateStack::StateEntry { private: const SkRect bounds_; - const std::shared_ptr filter_; - const std::shared_ptr old_filter_; + const std::shared_ptr filter_; + const std::shared_ptr old_filter_; const SkRect old_bounds_; FML_DISALLOW_COPY_ASSIGN_AND_MOVE(ImageFilterEntry); @@ -346,7 +353,7 @@ class ColorFilterEntry : public LayerStateStack::StateEntry { class BackdropFilterEntry : public SaveLayerEntry { public: BackdropFilterEntry(const SkRect& bounds, - const std::shared_ptr& filter, + const std::shared_ptr& filter, DlBlendMode blend_mode, std::optional backdrop_id, const LayerStateStack::RenderingAttributes& prev) @@ -373,7 +380,7 @@ class BackdropFilterEntry : public SaveLayerEntry { } private: - const std::shared_ptr filter_; + const std::shared_ptr filter_; std::optional backdrop_id_; FML_DISALLOW_COPY_ASSIGN_AND_MOVE(BackdropFilterEntry); @@ -550,7 +557,7 @@ void MutatorContext::applyOpacity(const SkRect& bounds, SkScalar opacity) { void MutatorContext::applyImageFilter( const SkRect& bounds, - const std::shared_ptr& filter) { + const std::shared_ptr& filter) { if (filter) { layer_state_stack_->push_image_filter(bounds, filter); } @@ -566,7 +573,7 @@ void MutatorContext::applyColorFilter( void MutatorContext::applyBackdropFilter( const SkRect& bounds, - const std::shared_ptr& filter, + const std::shared_ptr& filter, DlBlendMode blend_mode, std::optional backdrop_id) { layer_state_stack_->push_backdrop(bounds, filter, blend_mode, backdrop_id); @@ -706,7 +713,7 @@ void LayerStateStack::push_color_filter( void LayerStateStack::push_image_filter( const SkRect& bounds, - const std::shared_ptr& filter) { + const std::shared_ptr& filter) { maybe_save_layer(filter); state_stack_.emplace_back( std::make_unique(bounds, filter, outstanding_)); @@ -715,7 +722,7 @@ void LayerStateStack::push_image_filter( void LayerStateStack::push_backdrop( const SkRect& bounds, - const std::shared_ptr& filter, + const std::shared_ptr& filter, DlBlendMode blend_mode, std::optional backdrop_id) { state_stack_.emplace_back(std::make_unique( @@ -828,7 +835,7 @@ void LayerStateStack::maybe_save_layer( } void LayerStateStack::maybe_save_layer( - const std::shared_ptr& filter) { + const std::shared_ptr& filter) { if (outstanding_.image_filter) { // TBD: compose the 2 image filters together. save_layer(outstanding_.save_layer_bounds); diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index a5cec34ed1cc4..ad505c09340aa 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -177,7 +177,7 @@ class LayerStateStack { // outstanding attributes. // (Currently only opacity is recorded for batching) void applyImageFilter(const SkRect& bounds, - const std::shared_ptr& filter); + const std::shared_ptr& filter); // Records the color filter for application at the next call to // saveLayer or applyState. A saveLayer may be executed at @@ -196,7 +196,7 @@ class LayerStateStack { // subsequent canvas or builder objects that are made delegates // will only see a saveLayer with the indicated blend_mode. void applyBackdropFilter(const SkRect& bounds, - const std::shared_ptr& filter, + const std::shared_ptr& filter, DlBlendMode blend_mode, std::optional backdrop_id); @@ -252,7 +252,7 @@ class LayerStateStack { return outstanding_.color_filter; } - std::shared_ptr outstanding_image_filter() const { + std::shared_ptr outstanding_image_filter() const { return outstanding_.image_filter; } @@ -278,6 +278,12 @@ class LayerStateStack { // This rectangle may be a conservative estimate of the true clip region. SkRect local_cull_rect() const { return delegate_->local_cull_rect(); } + // The transform from the local coordinates to the device coordinates + // in 4x4 DlMatrix representation. This matrix provides all information + // needed to compute bounds for a 2D rendering primitive, and it will + // accurately concatenate with other 4x4 matrices without losing information. + const DlMatrix matrix() const { return delegate_->matrix(); } + // The transform from the local coordinates to the device coordinates // in the most capable 4x4 matrix representation. This matrix may be // more information than is needed to compute bounds for a 2D rendering @@ -332,9 +338,9 @@ class LayerStateStack { void push_color_filter(const SkRect& bounds, const std::shared_ptr& filter); void push_image_filter(const SkRect& bounds, - const std::shared_ptr& filter); + const std::shared_ptr& filter); void push_backdrop(const SkRect& bounds, - const std::shared_ptr& filter, + const std::shared_ptr& filter, DlBlendMode blend_mode, std::optional backdrop_id); @@ -362,7 +368,7 @@ class LayerStateStack { void maybe_save_layer(int apply_flags); void maybe_save_layer(SkScalar opacity); void maybe_save_layer(const std::shared_ptr& filter); - void maybe_save_layer(const std::shared_ptr& filter); + void maybe_save_layer(const std::shared_ptr& filter); // --------------------- struct RenderingAttributes { @@ -379,7 +385,7 @@ class LayerStateStack { SkScalar opacity = SK_Scalar1; std::shared_ptr color_filter; - std::shared_ptr image_filter; + std::shared_ptr image_filter; DlPaint* fill(DlPaint& paint, DlBlendMode mode = DlBlendMode::kSrcOver) const; @@ -441,6 +447,7 @@ class LayerStateStack { virtual SkRect local_cull_rect() const = 0; virtual SkRect device_cull_rect() const = 0; + virtual DlMatrix matrix() const = 0; virtual SkM44 matrix_4x4() const = 0; virtual SkMatrix matrix_3x3() const = 0; virtual bool content_culled(const SkRect& content_bounds) const = 0; diff --git a/flow/layers/layer_state_stack_unittests.cc b/flow/layers/layer_state_stack_unittests.cc index 928961f3621c2..1a11e6742b65e 100644 --- a/flow/layers/layer_state_stack_unittests.cc +++ b/flow/layers/layer_state_stack_unittests.cc @@ -4,6 +4,7 @@ #include "gtest/gtest.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/display_list/effects/dl_color_filter.h" #include "flutter/display_list/effects/dl_image_filter.h" #include "flutter/flow/layers/layer.h" @@ -287,14 +288,15 @@ TEST(LayerStateStack, ColorFilter) { TEST(LayerStateStack, ImageFilter) { SkRect rect = {10, 10, 20, 20}; - std::shared_ptr outer_filter = - std::make_shared(2.0f, 2.0f, DlTileMode::kClamp); - std::shared_ptr inner_filter = - std::make_shared(3.0f, 3.0f, DlTileMode::kClamp); + std::shared_ptr outer_filter = + DlBlurImageFilter::Make(2.0f, 2.0f, DlTileMode::kClamp); + std::shared_ptr inner_filter = + DlBlurImageFilter::Make(3.0f, 3.0f, DlTileMode::kClamp); SkRect inner_src_rect = rect; - SkRect outer_src_rect; - ASSERT_EQ(inner_filter->map_local_bounds(rect, outer_src_rect), - &outer_src_rect); + DlRect dl_outer_src_rect; + ASSERT_EQ(inner_filter->map_local_bounds(ToDlRect(rect), dl_outer_src_rect), + &dl_outer_src_rect); + SkRect outer_src_rect = ToSkRect(dl_outer_src_rect); LayerStateStack state_stack; state_stack.set_preroll_delegate(SkRect::MakeLTRB(0, 0, 50, 50)); @@ -429,8 +431,8 @@ TEST(LayerStateStack, OpacityAndColorFilterInteraction) { TEST(LayerStateStack, OpacityAndImageFilterInteraction) { SkRect rect = {10, 10, 20, 20}; - std::shared_ptr image_filter = - std::make_shared(2.0f, 2.0f, DlTileMode::kClamp); + std::shared_ptr image_filter = + DlBlurImageFilter::Make(2.0f, 2.0f, DlTileMode::kClamp); DisplayListBuilder builder; LayerStateStack state_stack; @@ -491,8 +493,8 @@ TEST(LayerStateStack, ColorFilterAndImageFilterInteraction) { std::shared_ptr color_filter = std::make_shared(DlColor::kYellow(), DlBlendMode::kColorBurn); - std::shared_ptr image_filter = - std::make_shared(2.0f, 2.0f, DlTileMode::kClamp); + std::shared_ptr image_filter = + DlBlurImageFilter::Make(2.0f, 2.0f, DlTileMode::kClamp); DisplayListBuilder builder; LayerStateStack state_stack; diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index e9c0db8a9a714..e32437e3a52a5 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -4,6 +4,7 @@ #include "flutter/flow/layers/opacity_layer.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/flow/layers/clip_rect_layer.h" #include "flutter/flow/layers/image_filter_layer.h" #include "flutter/flow/layers/layer_tree.h" @@ -542,7 +543,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughImageFilter) { auto opacity_layer = std::make_shared(128, SkPoint::Make(20, 20)); auto filter_layer = std::make_shared( - std::make_shared(5.0, 5.0, DlTileMode::kClamp)); + DlBlurImageFilter::Make(5.0, 5.0, DlTileMode::kClamp)); auto mock_layer = MockLayer::MakeOpacityCompatible(SkPath()); filter_layer->Add(mock_layer); opacity_layer->Add(filter_layer); diff --git a/flow/layers/platform_view_layer_unittests.cc b/flow/layers/platform_view_layer_unittests.cc index 31eab1bd3f315..df8ccfc30c609 100644 --- a/flow/layers/platform_view_layer_unittests.cc +++ b/flow/layers/platform_view_layer_unittests.cc @@ -132,7 +132,7 @@ TEST_F(PlatformViewLayerTest, StateTransfer) { transform_layer2->Add(child2); auto embedder = MockViewEmbedder(); - DisplayListBuilder builder({0, 0, 500, 500}); + DisplayListBuilder builder(DlRect::MakeWH(500, 500)); embedder.AddCanvas(&builder); PrerollContext* preroll_ctx = preroll_context(); diff --git a/flow/mutators_stack_unittests.cc b/flow/mutators_stack_unittests.cc index 42ce6363d47ff..93fd081bf8e1e 100644 --- a/flow/mutators_stack_unittests.cc +++ b/flow/mutators_stack_unittests.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/flow/embedded_views.h" #include "gtest/gtest.h" @@ -93,7 +94,7 @@ TEST(MutatorsStack, PushBackdropFilter) { MutatorsStack stack; const int num_of_mutators = 10; for (int i = 0; i < num_of_mutators; i++) { - auto filter = std::make_shared(i, 5, DlTileMode::kClamp); + auto filter = DlBlurImageFilter::Make(i, 5, DlTileMode::kClamp); stack.PushBackdropFilter(filter, SkRect::MakeXYWH(i, i, i, i)); } @@ -168,7 +169,7 @@ TEST(MutatorsStack, Equality) { stack.PushClipPath(path); int alpha = 240; stack.PushOpacity(alpha); - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + auto filter = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); stack.PushBackdropFilter(filter, SkRect::MakeEmpty()); MutatorsStack stack_other; @@ -182,8 +183,7 @@ TEST(MutatorsStack, Equality) { stack_other.PushClipPath(other_path); int other_alpha = 240; stack_other.PushOpacity(other_alpha); - auto other_filter = - std::make_shared(5, 5, DlTileMode::kClamp); + auto other_filter = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); stack_other.PushBackdropFilter(other_filter, SkRect::MakeEmpty()); ASSERT_TRUE(stack == stack_other); @@ -215,7 +215,7 @@ TEST(Mutator, Initialization) { Mutator mutator5 = Mutator(alpha); ASSERT_TRUE(mutator5.GetType() == MutatorType::kOpacity); - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + auto filter = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); Mutator mutator6 = Mutator(filter, SkRect::MakeEmpty()); ASSERT_TRUE(mutator6.GetType() == MutatorType::kBackdropFilter); ASSERT_TRUE(mutator6.GetFilterMutation().GetFilter() == *filter); @@ -248,7 +248,7 @@ TEST(Mutator, CopyConstructor) { Mutator copy5 = Mutator(mutator5); ASSERT_TRUE(mutator5 == copy5); - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + auto filter = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); Mutator mutator6 = Mutator(filter, SkRect::MakeEmpty()); Mutator copy6 = Mutator(mutator6); ASSERT_TRUE(mutator6 == copy6); @@ -281,8 +281,8 @@ TEST(Mutator, Equality) { Mutator other_mutator5 = Mutator(alpha); ASSERT_TRUE(mutator5 == other_mutator5); - auto filter1 = std::make_shared(5, 5, DlTileMode::kClamp); - auto filter2 = std::make_shared(5, 5, DlTileMode::kClamp); + auto filter1 = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); + auto filter2 = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); Mutator mutator6 = Mutator(filter1, SkRect::MakeEmpty()); Mutator other_mutator6 = Mutator(filter2, SkRect::MakeEmpty()); ASSERT_TRUE(mutator6 == other_mutator6); @@ -302,9 +302,8 @@ TEST(Mutator, UnEquality) { Mutator other_mutator2 = Mutator(alpha2); ASSERT_TRUE(mutator2 != other_mutator2); - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - auto filter2 = - std::make_shared(10, 10, DlTileMode::kClamp); + auto filter = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); + auto filter2 = DlBlurImageFilter::Make(10, 10, DlTileMode::kClamp); Mutator mutator3 = Mutator(filter, SkRect::MakeEmpty()); Mutator other_mutator3 = Mutator(filter2, SkRect::MakeEmpty()); ASSERT_TRUE(mutator3 != other_mutator3); diff --git a/flow/raster_cache_unittests.cc b/flow/raster_cache_unittests.cc index 255509952daf5..ea814184fa0ca 100644 --- a/flow/raster_cache_unittests.cc +++ b/flow/raster_cache_unittests.cc @@ -553,8 +553,7 @@ TEST(RasterCache, PrepareLayerTransform) { SkRect child_bounds = SkRect::MakeLTRB(10, 10, 50, 50); SkPath child_path = SkPath().addOval(child_bounds); auto child_layer = MockLayer::Make(child_path); - auto blur_filter = - std::make_shared(5, 5, DlTileMode::kClamp); + auto blur_filter = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); auto blur_layer = std::make_shared(blur_filter); SkMatrix matrix = SkMatrix::Scale(2, 2); auto transform_layer = std::make_shared(matrix); diff --git a/impeller/display_list/aiks_dl_basic_unittests.cc b/impeller/display_list/aiks_dl_basic_unittests.cc index bb813e29a31c0..e017d71d92670 100644 --- a/impeller/display_list/aiks_dl_basic_unittests.cc +++ b/impeller/display_list/aiks_dl_basic_unittests.cc @@ -7,7 +7,7 @@ #include "display_list/dl_tile_mode.h" #include "display_list/effects/dl_color_filter.h" #include "display_list/effects/dl_color_source.h" -#include "display_list/effects/dl_image_filter.h" +#include "display_list/effects/dl_image_filters.h" #include "display_list/effects/dl_mask_filter.h" #include "flutter/impeller/display_list/aiks_unittests.h" @@ -835,7 +835,7 @@ TEST_P(AiksTest, CanRenderClippedBackdropFilter) { builder.ClipRRect(clip_rrect, DlCanvas::ClipOp::kIntersect); DlPaint save_paint; - auto backdrop_filter = std::make_shared( + auto backdrop_filter = DlColorFilterImageFilter::Make( DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kExclusion)); builder.SaveLayer(&clip_rect, &save_paint, backdrop_filter.get()); @@ -996,7 +996,7 @@ TEST_P(AiksTest, MatrixImageFilterDoesntCullWhenTranslatedFromOffscreen) { // Draw a circle in a SaveLayer at -300, but move it back on-screen with a // +300 translation applied by a SaveLayer image filter. DlPaint paint; - SkMatrix translate = SkMatrix::Translate(300, 0); + DlMatrix translate = DlMatrix::MakeTranslation({300, 0}); paint.setImageFilter( DlMatrixImageFilter::Make(translate, DlImageSampling::kLinear)); builder.SaveLayer(nullptr, &paint); @@ -1020,7 +1020,7 @@ TEST_P(AiksTest, DlPaint paint; paint.setImageFilter(DlMatrixImageFilter::Make( - SkMatrix::Translate(300, 0) * SkMatrix::Scale(2, 2), + DlMatrix::MakeTranslation({300, 0}) * DlMatrix::MakeScale({2, 2, 1}), DlImageSampling::kNearestNeighbor)); builder.SaveLayer(nullptr, &paint); @@ -1043,7 +1043,7 @@ TEST_P(AiksTest, ClearColorOptimizationWhenSubpassIsBiggerThanParentPass) { paint.setColor(DlColor::kRed()); builder.DrawRect(SkRect::MakeLTRB(200, 200, 300, 300), paint); - paint.setImageFilter(DlMatrixImageFilter::Make(SkMatrix::Scale(2, 2), + paint.setImageFilter(DlMatrixImageFilter::Make(DlMatrix::MakeScale({2, 2, 1}), DlImageSampling::kLinear)); builder.SaveLayer(nullptr, &paint); // Draw a rectangle that would fully cover the parent pass size, but not @@ -1538,8 +1538,8 @@ TEST_P(AiksTest, MassiveScalingMatrixImageFilter) { } DisplayListBuilder builder(SkRect::MakeSize(SkSize::Make(1000, 1000))); - auto filter = DlMatrixImageFilter::Make(SkMatrix::Scale(0.001, 0.001), - DlImageSampling::kLinear); + auto filter = DlMatrixImageFilter::Make( + DlMatrix::MakeScale({0.001, 0.001, 1}), DlImageSampling::kLinear); DlPaint paint; paint.setImageFilter(filter); diff --git a/impeller/display_list/aiks_dl_blur_unittests.cc b/impeller/display_list/aiks_dl_blur_unittests.cc index d8e9f587854e4..987f3f1a1d856 100644 --- a/impeller/display_list/aiks_dl_blur_unittests.cc +++ b/impeller/display_list/aiks_dl_blur_unittests.cc @@ -2,17 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "display_list/display_list.h" -#include "display_list/dl_blend_mode.h" -#include "display_list/dl_builder.h" -#include "display_list/dl_color.h" -#include "display_list/dl_paint.h" -#include "display_list/dl_sampling_options.h" -#include "display_list/dl_tile_mode.h" -#include "display_list/effects/dl_color_filter.h" -#include "display_list/effects/dl_color_source.h" -#include "display_list/effects/dl_image_filter.h" -#include "display_list/effects/dl_mask_filter.h" +#include "flutter/display_list/display_list.h" +#include "flutter/display_list/dl_blend_mode.h" +#include "flutter/display_list/dl_builder.h" +#include "flutter/display_list/dl_color.h" +#include "flutter/display_list/dl_paint.h" +#include "flutter/display_list/dl_sampling_options.h" +#include "flutter/display_list/dl_tile_mode.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" +#include "flutter/display_list/effects/dl_color_filter.h" +#include "flutter/display_list/effects/dl_color_source.h" +#include "flutter/display_list/effects/dl_image_filter.h" +#include "flutter/display_list/effects/dl_mask_filter.h" #include "flutter/impeller/display_list/aiks_unittests.h" #include "gmock/gmock.h" diff --git a/impeller/display_list/aiks_dl_runtime_effect_unittests.cc b/impeller/display_list/aiks_dl_runtime_effect_unittests.cc index 705ddc50f2699..32c90338aa394 100644 --- a/impeller/display_list/aiks_dl_runtime_effect_unittests.cc +++ b/impeller/display_list/aiks_dl_runtime_effect_unittests.cc @@ -9,6 +9,7 @@ #include "flutter/display_list/effects/dl_color_source.h" #include "flutter/display_list/effects/dl_image_filter.h" #include "flutter/display_list/effects/dl_runtime_effect.h" +#include "flutter/display_list/effects/dl_runtime_effect_image_filter.h" #include "flutter/impeller/display_list/aiks_unittests.h" #include "include/core/SkPath.h" @@ -101,7 +102,7 @@ TEST_P(AiksTest, CanRenderRuntimeEffectFilter) { DlPaint paint; paint.setColor(DlColor::kAqua()); - paint.setImageFilter(std::make_shared( + paint.setImageFilter(DlRuntimeEffectImageFilter::Make( DlRuntimeEffect::MakeImpeller(runtime_stage), sampler_inputs, uniform_data)); diff --git a/impeller/display_list/aiks_dl_unittests.cc b/impeller/display_list/aiks_dl_unittests.cc index 01aff4309ad26..7030ed48ee56f 100644 --- a/impeller/display_list/aiks_dl_unittests.cc +++ b/impeller/display_list/aiks_dl_unittests.cc @@ -8,7 +8,7 @@ #include "display_list/dl_tile_mode.h" #include "display_list/effects/dl_color_filter.h" #include "display_list/effects/dl_color_source.h" -#include "display_list/effects/dl_image_filter.h" +#include "display_list/effects/dl_image_filters.h" #include "display_list/geometry/dl_geometry_types.h" #include "display_list/geometry/dl_path.h" #include "display_list/image/dl_image.h" @@ -641,7 +641,7 @@ TEST_P(AiksTest, MatrixImageFilterMagnify) { builder.Translate(600, -200); - SkMatrix matrix = SkMatrix::Scale(scale, scale); + DlMatrix matrix = DlMatrix::MakeScale({scale, scale, 1}); DlPaint paint; paint.setImageFilter( DlMatrixImageFilter::Make(matrix, DlImageSampling::kLinear)); @@ -663,7 +663,7 @@ TEST_P(AiksTest, ImageFilteredSaveLayerWithUnboundedContents) { DisplayListBuilder builder; builder.Scale(GetContentScale().x, GetContentScale().y); - auto test = [&builder](const std::shared_ptr& filter) { + auto test = [&builder](const std::shared_ptr& filter) { auto DrawLine = [&builder](const SkPoint& p0, const SkPoint& p1, const DlPaint& p) { DlPaint paint = p; @@ -696,22 +696,22 @@ TEST_P(AiksTest, ImageFilteredSaveLayerWithUnboundedContents) { builder.Restore(); }; - test(std::make_shared(10.0, 10.0, DlTileMode::kDecal)); + test(DlBlurImageFilter::Make(10.0, 10.0, DlTileMode::kDecal)); builder.Translate(200.0, 0.0); - test(std::make_shared(10.0, 10.0)); + test(DlDilateImageFilter::Make(10.0, 10.0)); builder.Translate(200.0, 0.0); - test(std::make_shared(10.0, 10.0)); + test(DlErodeImageFilter::Make(10.0, 10.0)); builder.Translate(-400.0, 200.0); - SkMatrix sk_matrix = SkMatrix::RotateDeg(10); + DlMatrix matrix = DlMatrix::MakeRotationZ(DlDegrees(10)); - auto rotate_filter = std::make_shared( - sk_matrix, DlImageSampling::kLinear); + auto rotate_filter = + DlMatrixImageFilter::Make(matrix, DlImageSampling::kLinear); test(rotate_filter); builder.Translate(200.0, 0.0); @@ -722,8 +722,8 @@ TEST_P(AiksTest, ImageFilteredSaveLayerWithUnboundedContents) { 1, 0, 0, 0, 0, // 0, 0, 0, 1, 0 // }; - auto rgb_swap_filter = std::make_shared( - std::make_shared(m)); + auto rgb_swap_filter = + DlColorFilterImageFilter::Make(std::make_shared(m)); test(rgb_swap_filter); builder.Translate(200.0, 0.0); @@ -732,18 +732,18 @@ TEST_P(AiksTest, ImageFilteredSaveLayerWithUnboundedContents) { builder.Translate(-400.0, 200.0); - test(std::make_shared( - SkMatrix::Translate(25.0, 25.0), rotate_filter)); + test(DlLocalMatrixImageFilter::Make(DlMatrix::MakeTranslation({25.0, 25.0}), + rotate_filter)); builder.Translate(200.0, 0.0); - test(std::make_shared( - SkMatrix::Translate(25.0, 25.0), rgb_swap_filter)); + test(DlLocalMatrixImageFilter::Make(DlMatrix::MakeTranslation({25.0, 25.0}), + rgb_swap_filter)); builder.Translate(200.0, 0.0); - test(std::make_shared( - SkMatrix::Translate(25.0, 25.0), + test(DlLocalMatrixImageFilter::Make( + DlMatrix::MakeTranslation({25.0, 25.0}), DlComposeImageFilter::Make(rotate_filter, rgb_swap_filter))); ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); @@ -769,10 +769,10 @@ TEST_P(AiksTest, MatrixBackdropFilter) { builder.DrawCircle(SkPoint::Make(200, 200), 100, paint); // Should render a second circle, centered on the bottom-right-most edge of // the circle. - SkMatrix matrix = SkMatrix::Translate((100 + 100 * k1OverSqrt2), - (100 + 100 * k1OverSqrt2)) * - SkMatrix::Scale(0.5, 0.5) * - SkMatrix::Translate(-100, -100); + DlMatrix matrix = DlMatrix::MakeTranslation({(100 + 100 * k1OverSqrt2), + (100 + 100 * k1OverSqrt2)}) * + DlMatrix::MakeScale({0.5, 0.5, 1}) * + DlMatrix::MakeTranslation({-100, -100}); auto backdrop_filter = DlMatrixImageFilter::Make(matrix, DlImageSampling::kLinear); builder.SaveLayer(nullptr, nullptr, backdrop_filter.get()); @@ -797,10 +797,10 @@ TEST_P(AiksTest, MatrixSaveLayerFilter) { // Should render a second circle, centered on the bottom-right-most edge of // the circle. - SkMatrix matrix = SkMatrix::Translate((200 + 100 * k1OverSqrt2), - (200 + 100 * k1OverSqrt2)) * - SkMatrix::Scale(0.5, 0.5) * - SkMatrix::Translate(-200, -200); + DlMatrix matrix = DlMatrix::MakeTranslation({(200 + 100 * k1OverSqrt2), + (200 + 100 * k1OverSqrt2)}) * + DlMatrix::MakeScale({0.5, 0.5, 1}) * + DlMatrix::MakeTranslation({-200, -200}); DlPaint save_paint; save_paint.setImageFilter( DlMatrixImageFilter::Make(matrix, DlImageSampling::kLinear)); diff --git a/impeller/display_list/canvas_unittests.cc b/impeller/display_list/canvas_unittests.cc index fc04272715977..73d045ecf7daf 100644 --- a/impeller/display_list/canvas_unittests.cc +++ b/impeller/display_list/canvas_unittests.cc @@ -4,9 +4,9 @@ #include -#include "display_list/dl_tile_mode.h" -#include "display_list/effects/dl_image_filter.h" -#include "display_list/geometry/dl_geometry_types.h" +#include "flutter/display_list/dl_tile_mode.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" +#include "flutter/display_list/geometry/dl_geometry_types.h" #include "flutter/testing/testing.h" #include "gtest/gtest.h" #include "impeller/core/formats.h" diff --git a/impeller/display_list/dl_golden_blur_unittests.cc b/impeller/display_list/dl_golden_blur_unittests.cc index 378cb765bd740..64c82add8defd 100644 --- a/impeller/display_list/dl_golden_blur_unittests.cc +++ b/impeller/display_list/dl_golden_blur_unittests.cc @@ -5,6 +5,7 @@ #include "impeller/display_list/dl_golden_unittests.h" #include "flutter/display_list/dl_builder.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/display_list/effects/dl_mask_filter.h" #include "flutter/impeller/geometry/round_rect.h" #include "flutter/impeller/golden_tests/screenshot.h" diff --git a/impeller/display_list/dl_golden_unittests.cc b/impeller/display_list/dl_golden_unittests.cc index 10edeafb5f53f..fdcb0d85490b7 100644 --- a/impeller/display_list/dl_golden_unittests.cc +++ b/impeller/display_list/dl_golden_unittests.cc @@ -5,6 +5,7 @@ #include "impeller/display_list/dl_golden_unittests.h" #include "flutter/display_list/dl_builder.h" +#include "flutter/display_list/effects/dl_matrix_image_filter.h" #include "flutter/impeller/geometry/path_builder.h" #include "flutter/testing/testing.h" #include "gtest/gtest.h" @@ -78,9 +79,10 @@ TEST_P(DlGoldenTest, Bug147807) { SkRRect::MakeOval(SkRect::MakeLTRB(201.25, 10, 361.25, 170)), DlCanvas::ClipOp::kIntersect, true); SkRect save_layer_bounds = SkRect::MakeLTRB(201.25, 10, 361.25, 170); - DlMatrixImageFilter backdrop(SkMatrix::MakeAll(3, 0, -280, // - 0, 3, -920, // - 0, 0, 1), + DlMatrixImageFilter backdrop(DlMatrix::MakeRow(3, 0, 0.0, -280, // + 0, 3, 0.0, -920, // + 0, 0, 1.0, 0.0, // + 0, 0, 0.0, 1.0), DlImageSampling::kLinear); canvas->SaveLayer(&save_layer_bounds, /*paint=*/nullptr, &backdrop); { diff --git a/impeller/display_list/dl_unittests.cc b/impeller/display_list/dl_unittests.cc index 0cb493c71cefe..be868e5fb7b07 100644 --- a/impeller/display_list/dl_unittests.cc +++ b/impeller/display_list/dl_unittests.cc @@ -14,7 +14,7 @@ #include "flutter/display_list/dl_tile_mode.h" #include "flutter/display_list/effects/dl_color_filter.h" #include "flutter/display_list/effects/dl_color_source.h" -#include "flutter/display_list/effects/dl_image_filter.h" +#include "flutter/display_list/effects/dl_image_filters.h" #include "flutter/display_list/effects/dl_mask_filter.h" #include "flutter/testing/testing.h" #include "gtest/gtest.h" @@ -1010,9 +1010,10 @@ TEST_P(DisplayListTest, CanDrawWithMatrixFilter) { // Set the matrix filter auto filter_matrix = - SkMatrix::MakeAll(scale[0], skew[0], translation[0], // - skew[1], scale[1], translation[1], // - 0, 0, 1); + Matrix::MakeRow(scale[0], skew[0], 0.0f, translation[0], // + skew[1], scale[1], 0.0f, translation[1], // + 0.0f, 0.0f, 1.0f, 0.0f, // + 0.0f, 0.0f, 0.0f, 1.0f); if (enable) { switch (selected_matrix_type) { @@ -1071,8 +1072,8 @@ TEST_P(DisplayListTest, CanDrawWithMatrixFilterWhenSavingLayer) { flutter::DlPaint save_paint; SkRect bounds = SkRect::MakeXYWH(100, 100, 100, 100); - SkMatrix translate_matrix = - SkMatrix::Translate(translation[0], translation[1]); + Matrix translate_matrix = + Matrix::MakeTranslation({translation[0], translation[1]}); if (enable_save_layer) { auto filter = flutter::DlMatrixImageFilter( translate_matrix, flutter::DlImageSampling::kNearestNeighbor); @@ -1083,10 +1084,10 @@ TEST_P(DisplayListTest, CanDrawWithMatrixFilterWhenSavingLayer) { builder.Transform(translate_matrix); } - SkMatrix filter_matrix = SkMatrix::I(); - filter_matrix.postTranslate(-150, -150); - filter_matrix.postScale(0.2f, 0.2f); - filter_matrix.postTranslate(150, 150); + Matrix filter_matrix; + filter_matrix.Translate({150, 150}); + filter_matrix.Scale({0.2f, 0.2f}); + filter_matrix.Translate({-150, -150}); auto filter = flutter::DlMatrixImageFilter( filter_matrix, flutter::DlImageSampling::kNearestNeighbor); @@ -1532,7 +1533,7 @@ TEST_P(DisplayListTest, DrawMaskBlursThatMightUseSaveLayers) { auto normal_filter = flutter::DlBlurMaskFilter::Make(flutter::DlBlurStyle::kNormal, 5.0f); auto rotate_if = flutter::DlMatrixImageFilter::Make( - SkMatrix::RotateDeg(10), flutter::DlImageSampling::kLinear); + Matrix::MakeRotationZ(Degrees(10)), flutter::DlImageSampling::kLinear); flutter::DlPaint normal_if_paint = flutter::DlPaint() // .setMaskFilter(solid_filter) // diff --git a/impeller/display_list/image_filter.cc b/impeller/display_list/image_filter.cc index 50d2489df771b..1546cbf31f294 100644 --- a/impeller/display_list/image_filter.cc +++ b/impeller/display_list/image_filter.cc @@ -3,7 +3,8 @@ // found in the LICENSE file. #include "impeller/display_list/image_filter.h" -#include "display_list/effects/dl_image_filter.h" + +#include "flutter/display_list/effects/dl_image_filters.h" #include "fml/logging.h" #include "impeller/display_list/color_filter.h" #include "impeller/display_list/skia_conversions.h" @@ -56,7 +57,7 @@ std::shared_ptr WrapInput(const flutter::DlImageFilter* filter, auto matrix_filter = filter->asMatrix(); FML_DCHECK(matrix_filter); - auto matrix = skia_conversions::ToMatrix(matrix_filter->matrix()); + auto matrix = matrix_filter->matrix(); auto desc = skia_conversions::ToSamplerDescriptor(matrix_filter->sampling()); return FilterContents::MakeMatrixFilter(input, matrix, desc); @@ -66,7 +67,7 @@ std::shared_ptr WrapInput(const flutter::DlImageFilter* filter, FML_DCHECK(matrix_filter); FML_DCHECK(matrix_filter->image_filter()); - auto matrix = skia_conversions::ToMatrix(matrix_filter->matrix()); + auto matrix = matrix_filter->matrix(); return FilterContents::MakeLocalMatrixFilter( FilterInput::Make( WrapInput(matrix_filter->image_filter().get(), input)), diff --git a/impeller/entity/contents/filters/local_matrix_filter_contents.cc b/impeller/entity/contents/filters/local_matrix_filter_contents.cc index 568346b9a3694..de06e4f953a24 100644 --- a/impeller/entity/contents/filters/local_matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/local_matrix_filter_contents.cc @@ -23,7 +23,7 @@ std::optional LocalMatrixFilterContents::GetFilterSourceCoverage( const Matrix& effect_transform, const Rect& output_limit) const { auto matrix = matrix_.Basis(); - if (matrix.GetDeterminant() == 0.0) { + if (!matrix.IsInvertible()) { return std::nullopt; } auto inverse = matrix.Invert(); diff --git a/impeller/entity/contents/filters/matrix_filter_contents.cc b/impeller/entity/contents/filters/matrix_filter_contents.cc index 289e67fc922cb..444a62ee298aa 100644 --- a/impeller/entity/contents/filters/matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/matrix_filter_contents.cc @@ -110,7 +110,7 @@ std::optional MatrixFilterContents::GetFilterSourceCoverage( auto transform = effect_transform * // matrix_ * // effect_transform.Invert(); // - if (transform.GetDeterminant() == 0.0) { + if (!transform.IsInvertible()) { return std::nullopt; } auto inverse = transform.Invert(); diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index cdc4078c49a0a..3a88ff85a826b 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1008,6 +1008,52 @@ TEST(GeometryTest, PointMin) { ASSERT_POINT_NEAR(result, expected); } +TEST(GeometryTest, Vector4IsFinite) { + { + Vector4 v; + ASSERT_TRUE(v.IsFinite()); + v.x = std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.x = -std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.x = -std::numeric_limits::quiet_NaN(); + ASSERT_FALSE(v.IsFinite()); + } + + { + Vector4 v; + ASSERT_TRUE(v.IsFinite()); + v.y = std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.y = -std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.y = -std::numeric_limits::quiet_NaN(); + ASSERT_FALSE(v.IsFinite()); + } + + { + Vector4 v; + ASSERT_TRUE(v.IsFinite()); + v.z = std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.z = -std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.z = -std::numeric_limits::quiet_NaN(); + ASSERT_FALSE(v.IsFinite()); + } + + { + Vector4 v; + ASSERT_TRUE(v.IsFinite()); + v.w = std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.w = -std::numeric_limits::infinity(); + ASSERT_FALSE(v.IsFinite()); + v.w = -std::numeric_limits::quiet_NaN(); + ASSERT_FALSE(v.IsFinite()); + } +} + TEST(GeometryTest, Vector3Min) { Vector3 p(1, 2, 3); Vector3 result = p.Min({0, 10, 2}); diff --git a/impeller/geometry/matrix.cc b/impeller/geometry/matrix.cc index e47dd867bd718..ba49965498aa5 100644 --- a/impeller/geometry/matrix.cc +++ b/impeller/geometry/matrix.cc @@ -224,7 +224,7 @@ std::optional Matrix::Decompose() const { perpectiveMatrix.e[3][3] = 1; - if (perpectiveMatrix.GetDeterminant() == 0.0) { + if (!perpectiveMatrix.IsInvertible()) { return std::nullopt; } diff --git a/impeller/geometry/matrix.h b/impeller/geometry/matrix.h index 848d004505d9e..484bf40ddcc73 100644 --- a/impeller/geometry/matrix.h +++ b/impeller/geometry/matrix.h @@ -305,6 +305,8 @@ struct Matrix { Scalar GetDeterminant() const; + bool IsInvertible() const { return GetDeterminant() != 0; } + constexpr Scalar GetMaxBasisLengthXY() const { // The full basis computation requires computing the squared scaling factor // for translate/scale only matrices. This substantially limits the range of @@ -333,6 +335,11 @@ struct Matrix { direction.GetLength(); } + constexpr bool IsFinite() const { + return vec[0].IsFinite() && vec[1].IsFinite() && vec[2].IsFinite() && + vec[3].IsFinite(); + } + constexpr bool IsAffine() const { return (m[2] == 0 && m[3] == 0 && m[6] == 0 && m[7] == 0 && m[8] == 0 && m[9] == 0 && m[10] == 1 && m[11] == 0 && m[14] == 0 && m[15] == 1); @@ -402,6 +409,19 @@ struct Matrix { ); } + /// @brief Returns true if the matrix has no entries other than translation + /// components. Note that an identity matrix meets this criteria. + constexpr bool IsTranslationOnly() const { + return ( + // clang-format off + m[0] == 1.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 0.0 && + m[4] == 0.0 && m[5] == 1.0 && m[6] == 0.0 && m[7] == 0.0 && + m[8] == 0.0 && m[9] == 0.0 && m[10] == 1.0 && m[11] == 0.0 && + m[15] == 1.0 + // clang-format on + ); + } + /// @brief Returns true if the matrix has a scale-only basis and is /// non-projective. Note that an identity matrix meets this criteria. constexpr bool IsTranslationScaleOnly() const { diff --git a/impeller/geometry/matrix_unittests.cc b/impeller/geometry/matrix_unittests.cc index 8d99466e012b1..6c2ef35228a2a 100644 --- a/impeller/geometry/matrix_unittests.cc +++ b/impeller/geometry/matrix_unittests.cc @@ -80,6 +80,93 @@ TEST(MatrixTest, HasTranslation) { EXPECT_FALSE(Matrix().HasTranslation()); } +TEST(MatrixTest, IsTranslationOnly) { + EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsTranslationOnly()); + EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsTranslationScaleOnly()); + EXPECT_TRUE(Matrix::MakeTranslation({0, 100, 0}).IsTranslationOnly()); + EXPECT_TRUE(Matrix::MakeTranslation({0, 100, 0}).IsTranslationScaleOnly()); + EXPECT_TRUE(Matrix::MakeTranslation({100, 0, 0}).IsTranslationOnly()); + EXPECT_TRUE(Matrix::MakeTranslation({100, 0, 0}).IsTranslationScaleOnly()); + EXPECT_TRUE(Matrix().IsTranslationOnly()); + EXPECT_TRUE(Matrix().IsTranslationScaleOnly()); +} + +TEST(MatrixTest, IsTranslationScaleOnly) { + EXPECT_FALSE(Matrix::MakeScale({100, 100, 1}).IsTranslationOnly()); + EXPECT_TRUE(Matrix::MakeScale({100, 100, 1}).IsTranslationScaleOnly()); + EXPECT_FALSE(Matrix::MakeScale({1, 100, 1}).IsTranslationOnly()); + EXPECT_TRUE(Matrix::MakeScale({1, 100, 1}).IsTranslationScaleOnly()); + EXPECT_FALSE(Matrix::MakeScale({100, 1, 1}).IsTranslationOnly()); + EXPECT_TRUE(Matrix::MakeScale({100, 1, 1}).IsTranslationScaleOnly()); + EXPECT_TRUE(Matrix().IsTranslationOnly()); + EXPECT_TRUE(Matrix().IsTranslationScaleOnly()); +} + +TEST(MatrixTest, IsInvertibleGetDeterminant) { + EXPECT_TRUE(Matrix().IsInvertible()); + EXPECT_NE(Matrix().GetDeterminant(), 0.0f); + + EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsInvertible()); + EXPECT_NE(Matrix::MakeTranslation({100, 100, 0}).GetDeterminant(), 0.0f); + + EXPECT_TRUE(Matrix::MakeScale({100, 100, 1}).IsInvertible()); + EXPECT_NE(Matrix::MakeScale({100, 100, 1}).GetDeterminant(), 0.0f); + + EXPECT_TRUE(Matrix::MakeRotationX(Degrees(30)).IsInvertible()); + EXPECT_NE(Matrix::MakeRotationX(Degrees(30)).GetDeterminant(), 0.0f); + + EXPECT_TRUE(Matrix::MakeRotationY(Degrees(30)).IsInvertible()); + EXPECT_NE(Matrix::MakeRotationY(Degrees(30)).GetDeterminant(), 0.0f); + + EXPECT_TRUE(Matrix::MakeRotationZ(Degrees(30)).IsInvertible()); + EXPECT_NE(Matrix::MakeRotationZ(Degrees(30)).GetDeterminant(), 0.0f); + + EXPECT_FALSE(Matrix::MakeScale({0, 1, 1}).IsInvertible()); + EXPECT_EQ(Matrix::MakeScale({0, 1, 1}).GetDeterminant(), 0.0f); + EXPECT_FALSE(Matrix::MakeScale({1, 0, 1}).IsInvertible()); + EXPECT_EQ(Matrix::MakeScale({1, 0, 1}).GetDeterminant(), 0.0f); + EXPECT_FALSE(Matrix::MakeScale({1, 1, 0}).IsInvertible()); + EXPECT_EQ(Matrix::MakeScale({1, 1, 0}).GetDeterminant(), 0.0f); +} + +TEST(MatrixTest, IsFinite) { + EXPECT_TRUE(Matrix().IsFinite()); + + EXPECT_TRUE(Matrix::MakeTranslation({100, 100, 0}).IsFinite()); + EXPECT_TRUE(Matrix::MakeScale({100, 100, 1}).IsFinite()); + + EXPECT_TRUE(Matrix::MakeRotationX(Degrees(30)).IsFinite()); + EXPECT_TRUE(Matrix::MakeRotationY(Degrees(30)).IsFinite()); + EXPECT_TRUE(Matrix::MakeRotationZ(Degrees(30)).IsFinite()); + + EXPECT_TRUE(Matrix::MakeScale({0, 1, 1}).IsFinite()); + EXPECT_TRUE(Matrix::MakeScale({1, 0, 1}).IsFinite()); + EXPECT_TRUE(Matrix::MakeScale({1, 1, 0}).IsFinite()); + + for (int i = 0; i < 16; i++) { + { + Matrix matrix; + ASSERT_TRUE(matrix.IsFinite()); + matrix.m[i] = std::numeric_limits::infinity(); + ASSERT_FALSE(matrix.IsFinite()); + } + + { + Matrix matrix; + ASSERT_TRUE(matrix.IsFinite()); + matrix.m[i] = -std::numeric_limits::infinity(); + ASSERT_FALSE(matrix.IsFinite()); + } + + { + Matrix matrix; + ASSERT_TRUE(matrix.IsFinite()); + matrix.m[i] = -std::numeric_limits::quiet_NaN(); + ASSERT_FALSE(matrix.IsFinite()); + } + } +} + TEST(MatrixTest, IsAligned2D) { EXPECT_TRUE(Matrix().IsAligned2D()); EXPECT_TRUE(Matrix::MakeScale({1.0f, 1.0f, 2.0f}).IsAligned2D()); diff --git a/impeller/geometry/rect.h b/impeller/geometry/rect.h index 86344e2b6b4f5..32b43b9a82be2 100644 --- a/impeller/geometry/rect.h +++ b/impeller/geometry/rect.h @@ -151,6 +151,14 @@ struct TRect { return TRect(0.0, 0.0, size.width, size.height); } + template + constexpr static std::enable_if_t, TRect> Make( + const TRect& rect) { + return MakeLTRB( + static_cast(rect.GetLeft()), static_cast(rect.GetTop()), + static_cast(rect.GetRight()), static_cast(rect.GetBottom())); + } + template constexpr static std::optional MakePointBounds(const U& value) { return MakePointBounds(value.begin(), value.end()); @@ -788,7 +796,7 @@ namespace std { template inline std::ostream& operator<<(std::ostream& out, const impeller::TRect& r) { - out << "(" << r.GetOrigin() << ", " << r.GetSize() << ")"; + out << "(" << r.GetLeftTop() << " => " << r.GetRightBottom() << ")"; return out; } diff --git a/impeller/geometry/rect_unittests.cc b/impeller/geometry/rect_unittests.cc index 401c64fc23f0d..17d6ff6489b3d 100644 --- a/impeller/geometry/rect_unittests.cc +++ b/impeller/geometry/rect_unittests.cc @@ -161,6 +161,20 @@ TEST(RectTest, IRectSimpleWH) { EXPECT_FALSE(rect.IsEmpty()); } +TEST(RectTest, RectFromIRect) { + IRect irect = IRect::MakeLTRB(10, 20, 30, 40); + Rect rect = Rect::Make(irect); + + EXPECT_EQ(rect.GetLeft(), 10); + EXPECT_EQ(rect.GetTop(), 20); + EXPECT_EQ(rect.GetRight(), 30); + EXPECT_EQ(rect.GetBottom(), 40); + + // The following do not compile + // IRect irect2 = IRect::Make(rect); + // IRect irect2 = IRect::Make(irect); +} + TEST(RectTest, RectOverflowXYWH) { auto min = std::numeric_limits::lowest(); auto max = std::numeric_limits::max(); diff --git a/impeller/geometry/vector.h b/impeller/geometry/vector.h index d1358bffef4de..0f1c4dc10681e 100644 --- a/impeller/geometry/vector.h +++ b/impeller/geometry/vector.h @@ -255,6 +255,11 @@ struct Vector4 { constexpr Vector4(std::array values) : x(values[0]), y(values[1]), z(values[2]), w(values[3]) {} + constexpr bool IsFinite() const { + return std::isfinite(x) && std::isfinite(y) && std::isfinite(z) && + std::isfinite(w); + } + Vector4 Normalize() const { const Scalar inverse = 1.0f / sqrt(x * x + y * y + z * z + w * w); return Vector4(x * inverse, y * inverse, z * inverse, w * inverse); diff --git a/impeller/toolkit/interop/dl_builder.cc b/impeller/toolkit/interop/dl_builder.cc index 75b389bb6bc8b..d1a4a1964355e 100644 --- a/impeller/toolkit/interop/dl_builder.cc +++ b/impeller/toolkit/interop/dl_builder.cc @@ -9,8 +9,7 @@ namespace impeller::interop { DisplayListBuilder::DisplayListBuilder(const ImpellerRect* rect) - : builder_(ToSkiaType(rect).value_or( - flutter::DisplayListBuilder::kMaxCullRect)) {} + : builder_(rect) {} DisplayListBuilder::~DisplayListBuilder() = default; diff --git a/impeller/toolkit/interop/image_filter.cc b/impeller/toolkit/interop/image_filter.cc index b5dbf8955812c..4929200483f5a 100644 --- a/impeller/toolkit/interop/image_filter.cc +++ b/impeller/toolkit/interop/image_filter.cc @@ -4,9 +4,11 @@ #include "impeller/toolkit/interop/image_filter.h" +#include "flutter/display_list/effects/dl_image_filters.h" + namespace impeller::interop { -ImageFilter::ImageFilter(std::shared_ptr filter) +ImageFilter::ImageFilter(std::shared_ptr filter) : filter_(std::move(filter)) {} ImageFilter::~ImageFilter() = default; @@ -42,8 +44,7 @@ ScopedObject ImageFilter::MakeErode(Scalar x_radius, ScopedObject ImageFilter::MakeMatrix( const Matrix& matrix, flutter::DlImageSampling sampling) { - auto filter = - flutter::DlMatrixImageFilter::Make(ToSkMatrix(matrix), sampling); + auto filter = flutter::DlMatrixImageFilter::Make(matrix, sampling); if (!filter) { return nullptr; } @@ -60,8 +61,8 @@ ScopedObject ImageFilter::MakeCompose(const ImageFilter& outer, return Create(std::move(filter)); } -const std::shared_ptr& -ImageFilter::GetImageFilter() const { +const std::shared_ptr& ImageFilter::GetImageFilter() + const { return filter_; } diff --git a/impeller/toolkit/interop/image_filter.h b/impeller/toolkit/interop/image_filter.h index 4c6ae4e9beba9..4db52f98eb99f 100644 --- a/impeller/toolkit/interop/image_filter.h +++ b/impeller/toolkit/interop/image_filter.h @@ -31,7 +31,7 @@ class ImageFilter final static ScopedObject MakeCompose(const ImageFilter& outer, const ImageFilter& inner); - explicit ImageFilter(std::shared_ptr filter); + explicit ImageFilter(std::shared_ptr filter); ~ImageFilter() override; @@ -39,10 +39,10 @@ class ImageFilter final ImageFilter& operator=(const ImageFilter&) = delete; - const std::shared_ptr& GetImageFilter() const; + const std::shared_ptr& GetImageFilter() const; private: - std::shared_ptr filter_; + std::shared_ptr filter_; }; } // namespace impeller::interop diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 79f902a3cd941..217854d93b293 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -245,7 +245,7 @@ void Canvas::drawPaint(Dart_Handle paint_objects, Dart_Handle paint_data) { if (display_list_builder_) { DlPaint dl_paint; paint.paint(dl_paint, kDrawPaintFlags, DlTileMode::kClamp); - std::shared_ptr filter = dl_paint.getImageFilter(); + std::shared_ptr filter = dl_paint.getImageFilter(); if (filter && !filter->asColorFilter()) { // drawPaint does an implicit saveLayer if an SkImageFilter is // present that cannot be replaced by an SkColorFilter. diff --git a/lib/ui/painting/fragment_program.cc b/lib/ui/painting/fragment_program.cc index 2bb8b0e7a9cfb..9399fb9c051ac 100644 --- a/lib/ui/painting/fragment_program.cc +++ b/lib/ui/painting/fragment_program.cc @@ -5,8 +5,8 @@ #include #include -#include "display_list/effects/dl_image_filter.h" #include "display_list/effects/dl_runtime_effect.h" +#include "display_list/effects/dl_runtime_effect_image_filter.h" #include "flutter/lib/ui/painting/fragment_program.h" #include "flutter/assets/asset_manager.h" diff --git a/lib/ui/painting/image_filter.cc b/lib/ui/painting/image_filter.cc index edc2d522f67d7..2319008bc4fa2 100644 --- a/lib/ui/painting/image_filter.cc +++ b/lib/ui/painting/image_filter.cc @@ -5,7 +5,7 @@ #include "flutter/lib/ui/painting/image_filter.h" #include "display_list/dl_sampling_options.h" -#include "display_list/effects/dl_image_filter.h" +#include "display_list/effects/dl_image_filters.h" #include "flutter/lib/ui/floating_point.h" #include "flutter/lib/ui/painting/matrix.h" #include "flutter/lib/ui/ui_dart_state.h" @@ -55,7 +55,7 @@ ImageFilter::ImageFilter() {} ImageFilter::~ImageFilter() {} -const std::shared_ptr ImageFilter::filter( +const std::shared_ptr ImageFilter::filter( DlTileMode mode) const { if (is_dynamic_tile_mode_) { FML_DCHECK(filter_.get() != nullptr); @@ -104,7 +104,7 @@ void ImageFilter::initMatrix(const tonic::Float64List& matrix4, int filterQualityIndex) { is_dynamic_tile_mode_ = false; auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); - filter_ = DlMatrixImageFilter::Make(ToSkMatrix(matrix4), sampling); + filter_ = DlMatrixImageFilter::Make(ToDlMatrix(matrix4), sampling); } void ImageFilter::initColorFilter(ColorFilter* colorFilter) { diff --git a/lib/ui/painting/image_filter.h b/lib/ui/painting/image_filter.h index 642d34950bca7..c7bb6369bdb3a 100644 --- a/lib/ui/painting/image_filter.h +++ b/lib/ui/painting/image_filter.h @@ -37,14 +37,14 @@ class ImageFilter : public RefCountedDartWrappable { void initComposeFilter(ImageFilter* outer, ImageFilter* inner); void initShader(ReusableFragmentShader* shader); - const std::shared_ptr filter(DlTileMode mode) const; + const std::shared_ptr filter(DlTileMode mode) const; static void RegisterNatives(tonic::DartLibraryNatives* natives); private: ImageFilter(); - std::shared_ptr filter_; + std::shared_ptr filter_; bool is_dynamic_tile_mode_ = false; }; diff --git a/lib/ui/painting/matrix.cc b/lib/ui/painting/matrix.cc index 7b8e5ed98106b..02b4b101e092d 100644 --- a/lib/ui/painting/matrix.cc +++ b/lib/ui/painting/matrix.cc @@ -43,6 +43,18 @@ SkMatrix ToSkMatrix(const tonic::Float64List& matrix4) { return sk_matrix; } +DlMatrix ToDlMatrix(const tonic::Float64List& matrix4) { + FML_DCHECK(matrix4.data()); + // clang-format off + return DlMatrix::MakeColumn( + SafeNarrow(matrix4[ 0]), SafeNarrow(matrix4[ 1]), SafeNarrow(matrix4[ 2]), SafeNarrow(matrix4[ 3]), + SafeNarrow(matrix4[ 4]), SafeNarrow(matrix4[ 5]), SafeNarrow(matrix4[ 6]), SafeNarrow(matrix4[ 7]), + SafeNarrow(matrix4[ 8]), SafeNarrow(matrix4[ 9]), SafeNarrow(matrix4[10]), SafeNarrow(matrix4[11]), + SafeNarrow(matrix4[12]), SafeNarrow(matrix4[13]), SafeNarrow(matrix4[14]), SafeNarrow(matrix4[15]) + ); + // clang-format on +} + tonic::Float64List ToMatrix4(const SkMatrix& sk_matrix) { tonic::Float64List matrix4(Dart_NewTypedData(Dart_TypedData_kFloat64, 16)); for (int i = 0; i < 9; ++i) { diff --git a/lib/ui/painting/matrix.h b/lib/ui/painting/matrix.h index 94b618cd6ff73..2312a64ec920f 100644 --- a/lib/ui/painting/matrix.h +++ b/lib/ui/painting/matrix.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_LIB_UI_PAINTING_MATRIX_H_ #define FLUTTER_LIB_UI_PAINTING_MATRIX_H_ +#include "flutter/display_list/geometry/dl_geometry_types.h" + #include "third_party/skia/include/core/SkM44.h" #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/tonic/typed_data/typed_list.h" @@ -13,6 +15,7 @@ namespace flutter { SkM44 ToSkM44(const tonic::Float64List& matrix4); SkMatrix ToSkMatrix(const tonic::Float64List& matrix4); +DlMatrix ToDlMatrix(const tonic::Float64List& matrix4); tonic::Float64List ToMatrix4(const SkMatrix& sk_matrix); } // namespace flutter diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index dd351b5dfc605..7e0d3b4c410a0 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -76,7 +76,7 @@ void ShellTestExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::PushFilterToVisitedPlatformViews( - const std::shared_ptr& filter, + const std::shared_ptr& filter, const SkRect& filter_rect) { for (int64_t id : visited_platform_views_) { EmbeddedViewParams params = current_composition_params_[id]; diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index b000c239435fb..ef63189c92593 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -72,7 +72,7 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| void PushFilterToVisitedPlatformViews( - const std::shared_ptr& filter, + const std::shared_ptr& filter, const SkRect& filter_rect) override; // |ExternalViewEmbedder| diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 1875eac3aaef9..0719dee1e261e 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -21,6 +21,7 @@ #include "assets/asset_resolver.h" #include "assets/directory_asset_bundle.h" #include "common/graphics/persistent_cache.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" #include "flutter/flow/layers/backdrop_filter_layer.h" #include "flutter/flow/layers/clip_rect_layer.h" #include "flutter/flow/layers/display_list_layer.h" @@ -990,7 +991,7 @@ TEST_F(ShellTest, PushBackdropFilterToVisitedPlatformViews) { auto clip_rect_layer = std::make_shared( SkRect::MakeLTRB(0, 0, 30, 30), Clip::kHardEdge); transform_layer->Add(clip_rect_layer); - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + auto filter = DlBlurImageFilter::Make(5, 5, DlTileMode::kClamp); auto backdrop_filter_layer = std::make_shared(filter, DlBlendMode::kSrcOver); clip_rect_layer->Add(backdrop_filter_layer); diff --git a/shell/platform/darwin/ios/framework/Source/platform_views_controller.h b/shell/platform/darwin/ios/framework/Source/platform_views_controller.h index 623ab467c60aa..056586d429456 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_views_controller.h +++ b/shell/platform/darwin/ios/framework/Source/platform_views_controller.h @@ -125,7 +125,7 @@ class PlatformViewsController { long FindFirstResponderPlatformViewId(); /// @brief Pushes backdrop filter mutation to the mutator stack of each visited platform view. - void PushFilterToVisitedPlatformViews(const std::shared_ptr& filter, + void PushFilterToVisitedPlatformViews(const std::shared_ptr& filter, const SkRect& filter_rect); /// @brief Pushes the view id of a visted platform view to the list of visied platform views. diff --git a/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm b/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm index 383eb7f0c5587..b43c2e81869c5 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm +++ b/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm @@ -336,7 +336,7 @@ bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, } void PlatformViewsController::PushFilterToVisitedPlatformViews( - const std::shared_ptr& filter, + const std::shared_ptr& filter, const SkRect& filter_rect) { for (int64_t id : visited_platform_views_) { EmbeddedViewParams params = current_composition_params_[id]; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index a1ce91b637930..6983ac83f08cf 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -68,7 +68,7 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| void PushFilterToVisitedPlatformViews( - const std::shared_ptr& filter, + const std::shared_ptr& filter, const SkRect& filter_rect) override; // |ExternalViewEmbedder| diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index f8c2f47c7aefc..a2f5ff9c2b58e 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -108,7 +108,7 @@ // |ExternalViewEmbedder| void IOSExternalViewEmbedder::PushFilterToVisitedPlatformViews( - const std::shared_ptr& filter, + const std::shared_ptr& filter, const SkRect& filter_rect) { platform_views_controller_->PushFilterToVisitedPlatformViews(filter, filter_rect); } diff --git a/testing/display_list_testing.cc b/testing/display_list_testing.cc index 5f29f40816b56..9bf443192e22f 100644 --- a/testing/display_list_testing.cc +++ b/testing/display_list_testing.cc @@ -8,7 +8,7 @@ #include #include "flutter/display_list/display_list.h" -#include "flutter/display_list/effects/dl_image_filter.h" +#include "flutter/display_list/effects/dl_image_filters.h" namespace flutter::testing { @@ -385,6 +385,18 @@ std::ostream& operator<<(std::ostream& os, const DlImage* image) { return os << "isTextureBacked: " << image->isTextureBacked() << ")"; } +std::ostream& operator<<(std::ostream& os, + const flutter::DlImageFilter& filter) { + DisplayListStreamDispatcher(os, 0).out(filter); + return os; +} + +std::ostream& operator<<(std::ostream& os, + const flutter::DlColorFilter& filter) { + DisplayListStreamDispatcher(os, 0).out(filter); + return os; +} + } // namespace std namespace flutter::testing { @@ -611,7 +623,7 @@ void DisplayListStreamDispatcher::out(const DlImageFilter& filter) { case DlImageFilterType::kErode: { const DlErodeImageFilter* erode = filter.asErode(); FML_DCHECK(erode); - os_ << "DlDilateImageFilter(" << erode->radius_x() << ", " << erode->radius_y() << ")"; + os_ << "DlErodeImageFilter(" << erode->radius_x() << ", " << erode->radius_y() << ")"; break; } case DlImageFilterType::kMatrix: { @@ -663,7 +675,9 @@ void DisplayListStreamDispatcher::out(const DlImageFilter& filter) { case flutter::DlImageFilterType::kRuntimeEffect: { [[maybe_unused]] const DlRuntimeEffectImageFilter* runtime_effect = filter.asRuntimeEffectFilter(); FML_DCHECK(runtime_effect); - os_ << "DlRuntimeEffectImageFilter()"; + os_ << "DlRuntimeEffectImageFilter("; + os_ << runtime_effect->samplers().size() << " samplers, "; + os_ << runtime_effect->uniform_data()->size() << " uniform bytes)"; break; } } @@ -699,9 +713,9 @@ void DisplayListStreamDispatcher::saveLayer(const DlRect& bounds, os_ << "," << std::endl; indent(10); if (backdrop_id.has_value()) { - startl() << "backdrop: " << backdrop_id.value(); + startl() << "backdrop: " << backdrop_id.value() << ", "; } else { - startl() << "backdrop: (no id)"; + startl() << "backdrop: (no id), "; } out(backdrop); outdent(10); diff --git a/testing/display_list_testing.h b/testing/display_list_testing.h index 8ffc5c0b854fb..9a707bb862beb 100644 --- a/testing/display_list_testing.h +++ b/testing/display_list_testing.h @@ -79,6 +79,10 @@ extern std::ostream& operator<<(std::ostream& os, extern std::ostream& operator<<(std::ostream& os, const flutter::DisplayListOpCategory& category); extern std::ostream& operator<<(std::ostream& os, const flutter::DlPath& path); +extern std::ostream& operator<<(std::ostream& os, + const flutter::DlImageFilter& type); +extern std::ostream& operator<<(std::ostream& os, + const flutter::DlColorFilter& type); } // namespace std @@ -195,6 +199,11 @@ class DisplayListStreamDispatcher final : public DlOpReceiver { bool transparent_occluder, DlScalar dpr) override; + void out(const DlColorFilter& filter); + void out(const DlColorFilter* filter); + void out(const DlImageFilter& filter); + void out(const DlImageFilter* filter); + private: std::ostream& os_; int cur_indent_; @@ -209,11 +218,6 @@ class DisplayListStreamDispatcher final : public DlOpReceiver { std::ostream& out_array(std::string name, int count, const T array[]); std::ostream& startl(); - - void out(const DlColorFilter& filter); - void out(const DlColorFilter* filter); - void out(const DlImageFilter& filter); - void out(const DlImageFilter* filter); }; class DisplayListGeneralReceiver : public DlOpReceiver { From bea2a892f9f13c0a16016ade9dc4da7e893d152a Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 19 Nov 2024 15:33:28 -0800 Subject: [PATCH 2/4] workaround perspective math failures in ImageFilter bounds unit tests --- display_list/effects/dl_image_filter.cc | 42 +++++++++++++------ .../effects/dl_image_filter_unittests.cc | 28 ++++--------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/display_list/effects/dl_image_filter.cc b/display_list/effects/dl_image_filter.cc index c3fdac00602e4..663a8d152de00 100644 --- a/display_list/effects/dl_image_filter.cc +++ b/display_list/effects/dl_image_filter.cc @@ -46,12 +46,21 @@ DlIRect* DlImageFilter::inset_device_bounds(const DlIRect& input_bounds, DlIRect& output_bounds) { if (ctm.IsFinite() && ctm.IsInvertible()) { if (ctm.HasPerspective2D()) { - DlRect local_bounds = DlRect::Make(input_bounds) - .TransformAndClipBounds(ctm.Invert()) - .Expand(-radius_x, -radius_y); - output_bounds = - DlIRect::RoundOut(local_bounds.TransformAndClipBounds(ctm)); - return &output_bounds; + // Ideally this code would use Impeller classes to do the math, see: + // https://github.com/flutter/flutter/issues/159175 + SkMatrix sk_ctm = ToSkMatrix(ctm); + FML_DCHECK(sk_ctm.hasPerspective()); + SkIRect sk_input_bounds = + SkIRect::MakeLTRB(input_bounds.GetLeft(), input_bounds.GetTop(), + input_bounds.GetRight(), input_bounds.GetBottom()); + + SkMatrix inverse; + if (sk_ctm.invert(&inverse)) { + SkRect local_bounds = inverse.mapRect(SkRect::Make(sk_input_bounds)); + local_bounds.inset(radius_x, radius_y); + output_bounds = ToDlIRect(sk_ctm.mapRect(local_bounds).roundOut()); + return &output_bounds; + } } else { DlVector2 device_radius = map_vectors_affine(ctm, radius_x, radius_y); output_bounds = @@ -70,12 +79,21 @@ DlIRect* DlImageFilter::outset_device_bounds(const DlIRect& input_bounds, DlIRect& output_bounds) { if (ctm.IsFinite() && ctm.IsInvertible()) { if (ctm.HasPerspective2D()) { - DlRect local_bounds = DlRect::Make(input_bounds) - .TransformAndClipBounds(ctm.Invert()) - .Expand(radius_x, radius_y); - output_bounds = - DlIRect::RoundOut(local_bounds.TransformAndClipBounds(ctm)); - return &output_bounds; + // Ideally this code would use Impeller classes to do the math, see: + // https://github.com/flutter/flutter/issues/159175 + SkMatrix sk_ctm = ToSkMatrix(ctm); + FML_DCHECK(sk_ctm.hasPerspective()); + SkIRect sk_input_bounds = + SkIRect::MakeLTRB(input_bounds.GetLeft(), input_bounds.GetTop(), + input_bounds.GetRight(), input_bounds.GetBottom()); + + SkMatrix inverse; + if (sk_ctm.invert(&inverse)) { + SkRect local_bounds = inverse.mapRect(SkRect::Make(sk_input_bounds)); + local_bounds.outset(radius_x, radius_y); + output_bounds = ToDlIRect(sk_ctm.mapRect(local_bounds).roundOut()); + return &output_bounds; + } } else { DlVector2 device_radius = map_vectors_affine(ctm, radius_x, radius_y); output_bounds = diff --git a/display_list/effects/dl_image_filter_unittests.cc b/display_list/effects/dl_image_filter_unittests.cc index c44245d4eb499..4746690c8d599 100644 --- a/display_list/effects/dl_image_filter_unittests.cc +++ b/display_list/effects/dl_image_filter_unittests.cc @@ -156,29 +156,15 @@ static void TestBounds(const DlImageFilter& filter, ASSERT_FALSE(matrix.HasPerspective2D()) << matrix; TestBoundsWithMatrix(filter, matrix, sourceBounds, expectedLocalOutputQuad); + matrix.m[3] = 0.001f; + matrix.m[7] = 0.001f; + ASSERT_TRUE(matrix.IsInvertible()) << matrix; + ASSERT_TRUE(matrix.HasPerspective2D()) << matrix; + TestBoundsWithMatrix(filter, matrix, sourceBounds, + expectedLocalOutputQuad); } } } - - { - // Just test once with a reasonable perspective transform. Combining - // perspective with all of the abusively scaled and skewed transforms - // created in the loop above tends to lead to coordinates growing out - // of any reasonable scale. - DlMatrix matrix; - matrix = matrix.Scale({2.0f, 2.0f, 1}); - matrix = matrix.Translate({1000, 1000, 500}); - // matrix = DlMatrix::MakeSkew(0.125f, 0.125f) * matrix; - matrix = DlMatrix::MakeRotationX(DlDegrees(5)) * matrix; - // matrix = DlMatrix::MakeRotationY(DlDegrees(5)) * matrix; - // matrix = DlMatrix::MakeTranslation({0, 0, 5}); - matrix = DlMatrix::MakePerspective(DlDegrees(60), 0.5, -500, 1000) * matrix; - // matrix = DlMatrix::MakeLookAt({0, 0, -10}, {0, 0, 10}, {0, 1, 0}) - // * matrix; - ASSERT_TRUE(matrix.IsInvertible()) << matrix; - ASSERT_TRUE(matrix.HasPerspective2D()) << matrix; - TestBoundsWithMatrix(filter, matrix, sourceBounds, expectedLocalOutputQuad); - } } static void TestBounds(const DlImageFilter& filter, @@ -375,7 +361,7 @@ TEST(DisplayListImageFilter, ErodeNotEquals) { TEST(DisplayListImageFilter, ErodeBounds) { DlErodeImageFilter filter = DlErodeImageFilter(5, 10); - DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80).Shift(100, 100); + DlRect input_bounds = DlRect::MakeLTRB(20, 20, 80, 80); DlRect expected_output_bounds = input_bounds.Expand(-5, -10); TestBounds(filter, input_bounds, expected_output_bounds); } From 199970fd75a273c1ccea737fc7740a275216f4c7 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 19 Nov 2024 16:03:44 -0800 Subject: [PATCH 3/4] fix ios includes --- .../Source/FlutterPlatformViewsTest.mm | 30 +++++++++---------- .../Source/platform_views_controller.mm | 5 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index d6f52eddf9e37..443a06802f507 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -8,6 +8,7 @@ #include "fml/synchronization/count_down_latch.h" #include "shell/platform/darwin/ios/framework/Source/platform_views_controller.h" +#import "flutter/display_list/effects/dl_image_filters.h" #import "flutter/fml/thread.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h" @@ -347,7 +348,7 @@ - (void)testApplyBackdropFilter { SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale); stack.PushTransform(screenScaleMatrix); // Push a backdrop filter - auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); + auto filter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); auto embeddedViewParams = @@ -424,7 +425,7 @@ - (void)testApplyBackdropFilterWithCorrectFrame { SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale); stack.PushTransform(screenScaleMatrix); // Push a backdrop filter - auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); + auto filter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 8, screenScale * 8)); auto embeddedViewParams = @@ -502,7 +503,7 @@ - (void)testApplyMultipleBackdropFilters { stack.PushTransform(screenScaleMatrix); // Push backdrop filters for (int i = 0; i < 50; i++) { - auto filter = std::make_shared(i, 2, flutter::DlTileMode::kClamp); + auto filter = flutter::DlBlurImageFilter::Make(i, 2, flutter::DlTileMode::kClamp); stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); } @@ -579,7 +580,7 @@ - (void)testAddBackdropFilters { SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale); stack.PushTransform(screenScaleMatrix); // Push a backdrop filter - auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); + auto filter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); auto embeddedViewParams = @@ -700,7 +701,7 @@ - (void)testRemoveBackdropFilters { SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale); stack.PushTransform(screenScaleMatrix); // Push backdrop filters - auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); + auto filter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); for (int i = 0; i < 5; i++) { stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); } @@ -846,7 +847,7 @@ - (void)testEditBackdropFilters { SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale); stack.PushTransform(screenScaleMatrix); // Push backdrop filters - auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); + auto filter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); for (int i = 0; i < 5; i++) { stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); } @@ -886,8 +887,7 @@ - (void)testEditBackdropFilters { // Push backdrop filters for (int i = 0; i < 5; i++) { if (i == 3) { - auto filter2 = - std::make_shared(2, 5, flutter::DlTileMode::kClamp); + auto filter2 = flutter::DlBlurImageFilter::Make(2, 5, flutter::DlTileMode::kClamp); stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); @@ -943,8 +943,7 @@ - (void)testEditBackdropFilters { // Push backdrop filters for (int i = 0; i < 5; i++) { if (i == 0) { - auto filter2 = - std::make_shared(2, 5, flutter::DlTileMode::kClamp); + auto filter2 = flutter::DlBlurImageFilter::Make(2, 5, flutter::DlTileMode::kClamp); stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); continue; @@ -997,8 +996,7 @@ - (void)testEditBackdropFilters { // Push backdrop filters for (int i = 0; i < 5; i++) { if (i == 4) { - auto filter2 = - std::make_shared(2, 5, flutter::DlTileMode::kClamp); + auto filter2 = flutter::DlBlurImageFilter::Make(2, 5, flutter::DlTileMode::kClamp); stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); continue; @@ -1052,7 +1050,7 @@ - (void)testEditBackdropFilters { } // Push backdrop filters for (int i = 0; i < 5; i++) { - auto filter2 = std::make_shared(i, 2, flutter::DlTileMode::kClamp); + auto filter2 = flutter::DlBlurImageFilter::Make(i, 2, flutter::DlTileMode::kClamp); stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); } @@ -1136,7 +1134,7 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale); stack.PushTransform(screenScaleMatrix); // Push a dilate backdrop filter - auto dilateFilter = std::make_shared(5, 2); + auto dilateFilter = flutter::DlDilateImageFilter::Make(5, 2); stack.PushBackdropFilter(dilateFilter, SkRect::MakeEmpty()); auto embeddedViewParams = @@ -1168,7 +1166,7 @@ - (void)testApplyBackdropFilterNotDlBlurImageFilter { // Layer tree always pushes a screen scale factor to the stack stack2.PushTransform(screenScaleMatrix); // Push backdrop filters and dilate filter - auto blurFilter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); + auto blurFilter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); for (int i = 0; i < 5; i++) { if (i == 2) { @@ -1522,7 +1520,7 @@ - (void)testBackdropFilterCorrectlyPushedAndReset { flutterPlatformViewsController->BeginFrame(SkISize::Make(0, 0)); flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams)); flutterPlatformViewsController->PushVisitedPlatformView(2); - auto filter = std::make_shared(5, 2, flutter::DlTileMode::kClamp); + auto filter = flutter::DlBlurImageFilter::Make(5, 2, flutter::DlTileMode::kClamp); flutterPlatformViewsController->PushFilterToVisitedPlatformViews( filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10)); flutterPlatformViewsController->CompositeWithParams( diff --git a/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm b/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm index b43c2e81869c5..b95e8f509037f 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm +++ b/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm @@ -4,10 +4,11 @@ #import "shell/platform/darwin/ios/framework/Source/platform_views_controller.h" -#include "flow/surface_frame.h" +#include "flutter/display_list/effects/dl_blur_image_filter.h" +#include "flutter/flow/surface_frame.h" #include "flutter/flow/view_slicer.h" #include "flutter/fml/make_copyable.h" -#include "fml/synchronization/count_down_latch.h" +#include "flutter/fml/synchronization/count_down_latch.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" From f7fb6224a4815e15ce007dd17497b570e0749aed Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 19 Nov 2024 18:39:02 -0800 Subject: [PATCH 4/4] review feedback --- display_list/dl_builder.cc | 2 +- impeller/geometry/rect.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index 74c0fc274a14b..afce8d39130b2 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -726,7 +726,7 @@ void DisplayListBuilder::TransferLayerBounds(const SkRect& content_bounds) { parent_is_flooded = true; } else { global_bounds = DlRect::Make(global_ibounds); - auto clipped_bounds = global_bounds.Intersection(clip); + std::optional clipped_bounds = global_bounds.Intersection(clip); if (clipped_bounds.has_value()) { parent_layer().global_space_accumulator.accumulate( clipped_bounds.value()); diff --git a/impeller/geometry/rect.h b/impeller/geometry/rect.h index 32b43b9a82be2..860a8747ceb28 100644 --- a/impeller/geometry/rect.h +++ b/impeller/geometry/rect.h @@ -151,6 +151,8 @@ struct TRect { return TRect(0.0, 0.0, size.width, size.height); } + /// Construct a floating point rect |Rect| from another Rect of a + /// potentially different storage type (eg. |IRect|). template constexpr static std::enable_if_t, TRect> Make( const TRect& rect) {