| // 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 "gtest/gtest.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" | |
| #include "flutter/flow/layers/layer_state_stack.h" | |
| #include "flutter/testing/display_list_testing.h" | |
| namespace flutter { | |
| namespace testing { | |
| #ifndef NDEBUG | |
| TEST(LayerStateStack, AccessorsDieWithoutDelegate) { | |
| LayerStateStack state_stack; | |
| EXPECT_DEATH_IF_SUPPORTED(state_stack.device_cull_rect(), | |
| "LayerStateStack state queried without a delegate"); | |
| EXPECT_DEATH_IF_SUPPORTED(state_stack.local_cull_rect(), | |
| "LayerStateStack state queried without a delegate"); | |
| EXPECT_DEATH_IF_SUPPORTED(state_stack.transform_3x3(), | |
| "LayerStateStack state queried without a delegate"); | |
| EXPECT_DEATH_IF_SUPPORTED(state_stack.transform_4x4(), | |
| "LayerStateStack state queried without a delegate"); | |
| EXPECT_DEATH_IF_SUPPORTED(state_stack.content_culled({}), | |
| "LayerStateStack state queried without a delegate"); | |
| { | |
| // state_stack.set_preroll_delegate(kGiantRect, SkMatrix::I()); | |
| auto mutator = state_stack.save(); | |
| mutator.applyOpacity({}, 0.5); | |
| state_stack.clear_delegate(); | |
| auto restore = state_stack.applyState({}, 0); | |
| } | |
| } | |
| #endif | |
| TEST(LayerStateStack, Defaults) { | |
| LayerStateStack state_stack; | |
| ASSERT_EQ(state_stack.canvas_delegate(), nullptr); | |
| ASSERT_EQ(state_stack.checkerboard_func(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_bounds(), SkRect()); | |
| state_stack.set_preroll_delegate(kGiantRect, SkMatrix::I()); | |
| ASSERT_EQ(state_stack.device_cull_rect(), kGiantRect); | |
| ASSERT_EQ(state_stack.local_cull_rect(), kGiantRect); | |
| ASSERT_EQ(state_stack.transform_3x3(), SkMatrix::I()); | |
| ASSERT_EQ(state_stack.transform_4x4(), SkM44()); | |
| DlPaint dl_paint; | |
| state_stack.fill(dl_paint); | |
| ASSERT_EQ(dl_paint, DlPaint()); | |
| } | |
| TEST(LayerStateStack, SingularDelegate) { | |
| LayerStateStack state_stack; | |
| ASSERT_EQ(state_stack.canvas_delegate(), nullptr); | |
| // Two different DlCanvas implementators | |
| DisplayListBuilder builder; | |
| DisplayListBuilder builder2; | |
| DlCanvas& canvas = builder2; | |
| // no delegate -> builder delegate | |
| state_stack.set_delegate(&builder); | |
| ASSERT_EQ(state_stack.canvas_delegate(), &builder); | |
| // builder delegate -> DlCanvas delegate | |
| state_stack.set_delegate(&canvas); | |
| ASSERT_EQ(state_stack.canvas_delegate(), &canvas); | |
| // DlCanvas delegate -> builder delegate | |
| state_stack.set_delegate(&builder); | |
| ASSERT_EQ(state_stack.canvas_delegate(), &builder); | |
| // builder delegate -> no delegate | |
| state_stack.clear_delegate(); | |
| ASSERT_EQ(state_stack.canvas_delegate(), nullptr); | |
| // DlCanvas delegate -> no delegate | |
| state_stack.set_delegate(&canvas); | |
| state_stack.clear_delegate(); | |
| ASSERT_EQ(state_stack.canvas_delegate(), nullptr); | |
| } | |
| TEST(LayerStateStack, OldDelegateIsRolledBack) { | |
| LayerStateStack state_stack; | |
| DisplayListBuilder builder; | |
| DisplayListBuilder builder2; | |
| DlCanvas& canvas = builder2; | |
| ASSERT_TRUE(builder.GetTransform().isIdentity()); | |
| ASSERT_TRUE(canvas.GetTransform().isIdentity()); | |
| state_stack.set_delegate(&builder); | |
| ASSERT_TRUE(builder.GetTransform().isIdentity()); | |
| ASSERT_TRUE(canvas.GetTransform().isIdentity()); | |
| auto mutator = state_stack.save(); | |
| mutator.translate({10, 10}); | |
| ASSERT_EQ(builder.GetTransform(), SkMatrix::Translate(10, 10)); | |
| ASSERT_TRUE(canvas.GetTransform().isIdentity()); | |
| state_stack.set_delegate(&canvas); | |
| ASSERT_TRUE(builder.GetTransform().isIdentity()); | |
| ASSERT_EQ(canvas.GetTransform(), SkMatrix::Translate(10, 10)); | |
| state_stack.set_preroll_delegate(SkRect::MakeWH(100, 100)); | |
| ASSERT_TRUE(builder.GetTransform().isIdentity()); | |
| ASSERT_TRUE(canvas.GetTransform().isIdentity()); | |
| state_stack.set_delegate(&builder); | |
| state_stack.clear_delegate(); | |
| ASSERT_TRUE(builder.GetTransform().isIdentity()); | |
| ASSERT_TRUE(canvas.GetTransform().isIdentity()); | |
| state_stack.set_delegate(&canvas); | |
| state_stack.clear_delegate(); | |
| ASSERT_TRUE(builder.GetTransform().isIdentity()); | |
| ASSERT_TRUE(canvas.GetTransform().isIdentity()); | |
| } | |
| TEST(LayerStateStack, Opacity) { | |
| SkRect rect = {10, 10, 20, 20}; | |
| LayerStateStack state_stack; | |
| state_stack.set_preroll_delegate(SkRect::MakeLTRB(0, 0, 50, 50)); | |
| { | |
| auto mutator = state_stack.save(); | |
| mutator.applyOpacity(rect, 0.5f); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.5f); | |
| ASSERT_EQ(state_stack.outstanding_bounds(), rect); | |
| // Check nested opacities multiply with each other | |
| { | |
| auto mutator2 = state_stack.save(); | |
| mutator.applyOpacity(rect, 0.5f); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.25f); | |
| ASSERT_EQ(state_stack.outstanding_bounds(), rect); | |
| // Verify output with applyState that does not accept opacity | |
| { | |
| DisplayListBuilder builder; | |
| state_stack.set_delegate(&builder); | |
| { | |
| auto restore = state_stack.applyState(rect, 0); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| ASSERT_EQ(state_stack.outstanding_bounds(), SkRect()); | |
| DlPaint paint; | |
| state_stack.fill(paint); | |
| builder.DrawRect(rect, paint); | |
| } | |
| state_stack.clear_delegate(); | |
| DisplayListBuilder expected; | |
| DlPaint save_paint = | |
| DlPaint().setOpacity(state_stack.outstanding_opacity()); | |
| expected.SaveLayer(&rect, &save_paint); | |
| expected.DrawRect(rect, DlPaint()); | |
| expected.Restore(); | |
| ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), expected.Build())); | |
| } | |
| // Verify output with applyState that accepts opacity | |
| { | |
| DisplayListBuilder builder; | |
| state_stack.set_delegate(&builder); | |
| { | |
| auto restore = state_stack.applyState( | |
| rect, LayerStateStack::kCallerCanApplyOpacity); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.25f); | |
| ASSERT_EQ(state_stack.outstanding_bounds(), rect); | |
| DlPaint paint; | |
| state_stack.fill(paint); | |
| builder.DrawRect(rect, paint); | |
| } | |
| state_stack.clear_delegate(); | |
| DisplayListBuilder expected; | |
| expected.DrawRect(rect, DlPaint().setOpacity(0.25f)); | |
| ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), expected.Build())); | |
| } | |
| } | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.5f); | |
| ASSERT_EQ(state_stack.outstanding_bounds(), rect); | |
| } | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| ASSERT_EQ(state_stack.outstanding_bounds(), SkRect()); | |
| } | |
| TEST(LayerStateStack, ColorFilter) { | |
| SkRect rect = {10, 10, 20, 20}; | |
| std::shared_ptr<DlBlendColorFilter> outer_filter = | |
| std::make_shared<DlBlendColorFilter>(DlColor::kYellow(), | |
| DlBlendMode::kColorBurn); | |
| std::shared_ptr<DlBlendColorFilter> inner_filter = | |
| std::make_shared<DlBlendColorFilter>(DlColor::kRed(), | |
| DlBlendMode::kColorBurn); | |
| LayerStateStack state_stack; | |
| state_stack.set_preroll_delegate(SkRect::MakeLTRB(0, 0, 50, 50)); | |
| { | |
| auto mutator = state_stack.save(); | |
| mutator.applyColorFilter(rect, outer_filter); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), outer_filter); | |
| // Check nested color filters result in nested saveLayers | |
| { | |
| auto mutator2 = state_stack.save(); | |
| mutator.applyColorFilter(rect, inner_filter); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), inner_filter); | |
| // Verify output with applyState that does not accept color filters | |
| { | |
| DisplayListBuilder builder; | |
| state_stack.set_delegate(&builder); | |
| { | |
| auto restore = state_stack.applyState(rect, 0); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| DlPaint paint; | |
| state_stack.fill(paint); | |
| builder.DrawRect(rect, paint); | |
| } | |
| state_stack.clear_delegate(); | |
| DisplayListBuilder expected; | |
| DlPaint outer_save_paint = DlPaint().setColorFilter(outer_filter); | |
| DlPaint inner_save_paint = DlPaint().setColorFilter(inner_filter); | |
| expected.SaveLayer(&rect, &outer_save_paint); | |
| expected.SaveLayer(&rect, &inner_save_paint); | |
| expected.DrawRect(rect, DlPaint()); | |
| expected.Restore(); | |
| expected.Restore(); | |
| ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), expected.Build())); | |
| } | |
| // Verify output with applyState that accepts color filters | |
| { | |
| SkRect rect = {10, 10, 20, 20}; | |
| DisplayListBuilder builder; | |
| state_stack.set_delegate(&builder); | |
| { | |
| auto restore = state_stack.applyState( | |
| rect, LayerStateStack::kCallerCanApplyColorFilter); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), inner_filter); | |
| DlPaint paint; | |
| state_stack.fill(paint); | |
| builder.DrawRect(rect, paint); | |
| } | |
| state_stack.clear_delegate(); | |
| DisplayListBuilder expected; | |
| DlPaint save_paint = DlPaint().setColorFilter(outer_filter); | |
| DlPaint draw_paint = DlPaint().setColorFilter(inner_filter); | |
| expected.SaveLayer(&rect, &save_paint); | |
| expected.DrawRect(rect, draw_paint); | |
| ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), expected.Build())); | |
| } | |
| } | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), outer_filter); | |
| } | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| } | |
| TEST(LayerStateStack, ImageFilter) { | |
| SkRect rect = {10, 10, 20, 20}; | |
| std::shared_ptr<DlBlurImageFilter> outer_filter = | |
| std::make_shared<DlBlurImageFilter>(2.0f, 2.0f, DlTileMode::kClamp); | |
| std::shared_ptr<DlBlurImageFilter> inner_filter = | |
| std::make_shared<DlBlurImageFilter>(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); | |
| LayerStateStack state_stack; | |
| state_stack.set_preroll_delegate(SkRect::MakeLTRB(0, 0, 50, 50)); | |
| { | |
| auto mutator = state_stack.save(); | |
| mutator.applyImageFilter(outer_src_rect, outer_filter); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), outer_filter); | |
| // Check nested color filters result in nested saveLayers | |
| { | |
| auto mutator2 = state_stack.save(); | |
| mutator.applyImageFilter(rect, inner_filter); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), inner_filter); | |
| // Verify output with applyState that does not accept color filters | |
| { | |
| DisplayListBuilder builder; | |
| state_stack.set_delegate(&builder); | |
| { | |
| auto restore = state_stack.applyState(rect, 0); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| DlPaint paint; | |
| state_stack.fill(paint); | |
| builder.DrawRect(rect, paint); | |
| } | |
| state_stack.clear_delegate(); | |
| DisplayListBuilder expected; | |
| DlPaint outer_save_paint = DlPaint().setImageFilter(outer_filter); | |
| DlPaint inner_save_paint = DlPaint().setImageFilter(inner_filter); | |
| expected.SaveLayer(&outer_src_rect, &outer_save_paint); | |
| expected.SaveLayer(&inner_src_rect, &inner_save_paint); | |
| expected.DrawRect(rect, DlPaint()); | |
| expected.Restore(); | |
| expected.Restore(); | |
| ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), expected.Build())); | |
| } | |
| // Verify output with applyState that accepts color filters | |
| { | |
| SkRect rect = {10, 10, 20, 20}; | |
| DisplayListBuilder builder; | |
| state_stack.set_delegate(&builder); | |
| { | |
| auto restore = state_stack.applyState( | |
| rect, LayerStateStack::kCallerCanApplyImageFilter); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), inner_filter); | |
| DlPaint paint; | |
| state_stack.fill(paint); | |
| builder.DrawRect(rect, paint); | |
| } | |
| state_stack.clear_delegate(); | |
| DisplayListBuilder expected; | |
| DlPaint save_paint = DlPaint().setImageFilter(outer_filter); | |
| DlPaint draw_paint = DlPaint().setImageFilter(inner_filter); | |
| expected.SaveLayer(&outer_src_rect, &save_paint); | |
| expected.DrawRect(rect, draw_paint); | |
| ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), expected.Build())); | |
| } | |
| } | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), outer_filter); | |
| } | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| } | |
| TEST(LayerStateStack, OpacityAndColorFilterInteraction) { | |
| SkRect rect = {10, 10, 20, 20}; | |
| std::shared_ptr<DlBlendColorFilter> color_filter = | |
| std::make_shared<DlBlendColorFilter>(DlColor::kYellow(), | |
| DlBlendMode::kColorBurn); | |
| DisplayListBuilder builder; | |
| LayerStateStack state_stack; | |
| state_stack.set_delegate(&builder); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator1 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator1.applyOpacity(rect, 0.5f); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator2 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator2.applyColorFilter(rect, color_filter); | |
| // The opacity will have been resolved by a saveLayer | |
| ASSERT_EQ(builder.GetSaveCount(), 2); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), color_filter); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.5f); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| { | |
| auto mutator1 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator1.applyColorFilter(rect, color_filter); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator2 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator2.applyOpacity(rect, 0.5f); | |
| // color filter applied to opacity can be applied together | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), color_filter); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.5f); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), color_filter); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| } | |
| TEST(LayerStateStack, OpacityAndImageFilterInteraction) { | |
| SkRect rect = {10, 10, 20, 20}; | |
| std::shared_ptr<DlBlurImageFilter> image_filter = | |
| std::make_shared<DlBlurImageFilter>(2.0f, 2.0f, DlTileMode::kClamp); | |
| DisplayListBuilder builder; | |
| LayerStateStack state_stack; | |
| state_stack.set_delegate(&builder); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator1 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator1.applyOpacity(rect, 0.5f); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator2 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator2.applyImageFilter(rect, image_filter); | |
| // opacity applied to image filter can be applied together | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), image_filter); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.5f); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.5f); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| { | |
| auto mutator1 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator1.applyImageFilter(rect, image_filter); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator2 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator2.applyOpacity(rect, 0.5f); | |
| // The image filter will have been resolved by a saveLayer | |
| ASSERT_EQ(builder.GetSaveCount(), 2); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), 0.5f); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), image_filter); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_opacity(), SK_Scalar1); | |
| } | |
| TEST(LayerStateStack, ColorFilterAndImageFilterInteraction) { | |
| SkRect rect = {10, 10, 20, 20}; | |
| std::shared_ptr<DlBlendColorFilter> color_filter = | |
| std::make_shared<DlBlendColorFilter>(DlColor::kYellow(), | |
| DlBlendMode::kColorBurn); | |
| std::shared_ptr<DlBlurImageFilter> image_filter = | |
| std::make_shared<DlBlurImageFilter>(2.0f, 2.0f, DlTileMode::kClamp); | |
| DisplayListBuilder builder; | |
| LayerStateStack state_stack; | |
| state_stack.set_delegate(&builder); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator1 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator1.applyColorFilter(rect, color_filter); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator2 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator2.applyImageFilter(rect, image_filter); | |
| // color filter applied to image filter can be applied together | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), image_filter); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), color_filter); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), color_filter); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| { | |
| auto mutator1 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator1.applyImageFilter(rect, image_filter); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| { | |
| auto mutator2 = state_stack.save(); | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| mutator2.applyColorFilter(rect, color_filter); | |
| // The image filter will have been resolved by a saveLayer | |
| ASSERT_EQ(builder.GetSaveCount(), 2); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), color_filter); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), image_filter); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| } | |
| ASSERT_EQ(builder.GetSaveCount(), 1); | |
| ASSERT_EQ(state_stack.outstanding_image_filter(), nullptr); | |
| ASSERT_EQ(state_stack.outstanding_color_filter(), nullptr); | |
| } | |
| } // namespace testing | |
| } // namespace flutter |