summaryrefslogtreecommitdiff
path: root/chromium/ui/compositor/layer_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/compositor/layer_unittest.cc')
-rw-r--r--chromium/ui/compositor/layer_unittest.cc131
1 files changed, 106 insertions, 25 deletions
diff --git a/chromium/ui/compositor/layer_unittest.cc b/chromium/ui/compositor/layer_unittest.cc
index d97c7e846af..77945544e9f 100644
--- a/chromium/ui/compositor/layer_unittest.cc
+++ b/chromium/ui/compositor/layer_unittest.cc
@@ -790,7 +790,7 @@ TEST_F(LayerWithDelegateTest, Cloning) {
layer->SetFillsBoundsOpaquely(false);
// Color and opaqueness targets should be preserved during cloning, even after
// switching away from solid color content.
- layer->SwitchCCLayerForTest();
+ ASSERT_TRUE(layer->SwitchCCLayerForTest());
clone = layer->Clone();
@@ -1971,7 +1971,7 @@ namespace {
class SchedulePaintLayerDelegate : public LayerDelegate {
public:
- SchedulePaintLayerDelegate() : paint_count_(0), layer_(NULL) {}
+ SchedulePaintLayerDelegate() : paint_count_(0), layer_(nullptr) {}
~SchedulePaintLayerDelegate() override {}
@@ -2427,7 +2427,7 @@ TEST_P(LayerWithRealCompositorTest, SwitchCCLayerAnimations) {
l1->SetOpacity(0.5f);
// Change l1's cc::Layer.
- l1->SwitchCCLayerForTest();
+ ASSERT_TRUE(l1->SwitchCCLayerForTest());
// Ensure that the opacity animation completed.
EXPECT_FLOAT_EQ(l1->opacity(), 0.5f);
@@ -2449,7 +2449,7 @@ TEST_P(LayerWithRealCompositorTest, SwitchCCLayerSolidColorNotAnimating) {
EXPECT_EQ(transparent, root->GetTargetColor());
// Changing the underlying layer should not affect targets.
- root->SwitchCCLayerForTest();
+ ASSERT_TRUE(root->SwitchCCLayerForTest());
EXPECT_FALSE(root->fills_bounds_opaquely());
EXPECT_FALSE(
@@ -2487,7 +2487,7 @@ TEST_P(LayerWithRealCompositorTest, SwitchCCLayerSolidColorWhileAnimating) {
EXPECT_EQ(transparent, root->GetTargetColor());
// Changing the underlying layer should not affect targets.
- root->SwitchCCLayerForTest();
+ ASSERT_TRUE(root->SwitchCCLayerForTest());
EXPECT_TRUE(root->fills_bounds_opaquely());
EXPECT_TRUE(
@@ -2515,7 +2515,7 @@ TEST_P(LayerWithRealCompositorTest, SwitchCCLayerCacheRenderSurface) {
l1->AddCacheRenderSurfaceRequest();
// Change l1's cc::Layer.
- l1->SwitchCCLayerForTest();
+ ASSERT_TRUE(l1->SwitchCCLayerForTest());
// Ensure that the cache_render_surface flag is maintained.
EXPECT_TRUE(l1->cc_layer_for_testing()->cache_render_surface());
@@ -2532,7 +2532,7 @@ TEST_P(LayerWithRealCompositorTest, SwitchCCLayerTrilinearFiltering) {
l1->AddTrilinearFilteringRequest();
// Change l1's cc::Layer.
- l1->SwitchCCLayerForTest();
+ ASSERT_TRUE(l1->SwitchCCLayerForTest());
// Ensure that the trilinear_filtering flag is maintained.
EXPECT_TRUE(l1->cc_layer_for_testing()->trilinear_filtering());
@@ -2550,12 +2550,38 @@ TEST_P(LayerWithRealCompositorTest, SwitchCCLayerMasksToBounds) {
EXPECT_TRUE(l1->cc_layer_for_testing()->masks_to_bounds());
// Change l1's cc::Layer.
- l1->SwitchCCLayerForTest();
+ ASSERT_TRUE(l1->SwitchCCLayerForTest());
// Ensure that the trilinear_filtering flag is maintained.
EXPECT_TRUE(l1->cc_layer_for_testing()->masks_to_bounds());
}
+// Tests that no crash happens when switching cc layer with an animation
+// observer that deletes the layer itself.
+TEST_P(LayerWithRealCompositorTest, SwitchCCLayerDeleteLayer) {
+ std::unique_ptr<Layer> root(CreateLayer(LAYER_TEXTURED));
+ std::unique_ptr<Layer> l1(CreateLayer(LAYER_TEXTURED));
+ GetCompositor()->SetRootLayer(root.get());
+ root->Add(l1.get());
+
+ TestCallbackAnimationObserver animation_observer;
+ animation_observer.SetCallback(
+ base::BindLambdaForTesting([&]() { l1.reset(); }));
+
+ auto long_duration_animation =
+ std::make_unique<ui::ScopedAnimationDurationScaleMode>(
+ ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
+ {
+ ui::ScopedLayerAnimationSettings animation(l1->GetAnimator());
+ animation.AddObserver(&animation_observer);
+ animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
+ l1->SetOpacity(0.f);
+ }
+
+ // Fails but no crash.
+ EXPECT_FALSE(l1->SwitchCCLayerForTest());
+}
+
// Triggerring a OnDeviceScaleFactorChanged while a layer is undergoing
// transform animation, may cause a crash. This is because an animation observer
// may mutate the tree, e.g. deleting a layer, changing ancestor z-order etc,
@@ -2604,9 +2630,6 @@ TEST_P(LayerWithRealCompositorTest, TreeMutationDuringScaleFactorChange) {
root->Add(layer_to_delete.get());
layer_to_delete->Add(child.get());
- long_duration_animation =
- std::make_unique<ui::ScopedAnimationDurationScaleMode>(
- ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
{
ui::ScopedLayerAnimationSettings animation(layer_to_delete->GetAnimator());
animation.AddObserver(&animation_observer);
@@ -2629,9 +2652,6 @@ TEST_P(LayerWithRealCompositorTest, TreeMutationDuringScaleFactorChange) {
layer_to_delete->Add(child.get());
layer_to_delete->Add(child2.get());
- long_duration_animation =
- std::make_unique<ui::ScopedAnimationDurationScaleMode>(
- ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
{
ui::ScopedLayerAnimationSettings animation(child->GetAnimator());
animation.AddObserver(&animation_observer);
@@ -2666,6 +2686,60 @@ TEST_P(LayerWithRealCompositorTest, TreeMutationDuringScaleFactorChange) {
root->OnDeviceScaleFactorChanged(1.5f);
}
+// Tests that no crash when parent/child layer is released by an animation
+// observer of the child layer bounds animation.
+TEST_P(LayerWithRealCompositorTest, ParentOrChildGoneDuringRemove) {
+ std::unique_ptr<Layer> root = CreateLayer(LAYER_SOLID_COLOR);
+ GetCompositor()->SetRootLayer(root.get());
+ root->SetBounds(gfx::Rect(0, 0, 100, 100));
+
+ // Actions to taken on animation ends.
+ enum class Action {
+ kReleaseParent,
+ kReleaseChild,
+ };
+
+ for (auto action : {Action::kReleaseParent, Action::kReleaseChild}) {
+ SCOPED_TRACE(::testing::Message() << "action=" << static_cast<int>(action));
+
+ std::unique_ptr<Layer> parent = CreateLayer(LAYER_SOLID_COLOR);
+ parent->SetBounds(gfx::Rect(0, 0, 100, 100));
+
+ std::unique_ptr<Layer> child = CreateLayer(LAYER_SOLID_COLOR);
+ child->SetBounds(gfx::Rect(0, 0, 100, 100));
+ parent->Add(child.get());
+
+ root->Add(parent.get());
+
+ // An animation observer that takes action on animation ends.
+ TestCallbackAnimationObserver animation_observer;
+ animation_observer.SetCallback(base::BindLambdaForTesting([&]() {
+ switch (action) {
+ case Action::kReleaseParent:
+ parent.reset();
+ break;
+ case Action::kReleaseChild:
+ child.reset();
+ break;
+ }
+ }));
+
+ // Schedule a bounds animation on |child|.
+ auto long_duration_animation =
+ std::make_unique<ui::ScopedAnimationDurationScaleMode>(
+ ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
+ {
+ ui::ScopedLayerAnimationSettings animation(child->GetAnimator());
+ animation.AddObserver(&animation_observer);
+ animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
+ child->SetBounds(gfx::Rect(10, 20, 100, 100));
+ }
+
+ // No crash should happen when removing |child| with a bounds animation.
+ parent->Remove(child.get());
+ }
+}
+
// Tests that the animators in the layer tree is added to the
// animator-collection when the root-layer is set to the compositor.
TEST_F(LayerWithDelegateTest, RootLayerAnimatorsInCompositor) {
@@ -2910,7 +2984,7 @@ TEST(LayerDelegateTest, OnLayerTransformed) {
layer->SetTransform(target_transform1);
}
gfx::Transform target_transform2;
- target_transform2.Skew(10.0f, 5.0f);
+ target_transform2.Skew(15.0f, 5.0f);
EXPECT_CALL(delegate,
OnLayerTransformed(target_transform1,
PropertyChangeReason::NOT_FROM_ANIMATION))
@@ -2923,6 +2997,18 @@ TEST(LayerDelegateTest, OnLayerTransformed) {
layer->SetTransform(target_transform2);
}
+// Verify that LayerDelegate::OnLayerTransformed() is not called when the
+// transform isn't actually changed.
+TEST(LayerDelegateTest, OnLayerTransformedNotCalledWhenUnchanged) {
+ auto layer = std::make_unique<Layer>(LAYER_TEXTURED);
+ testing::StrictMock<TestLayerDelegate> delegate;
+ layer->set_delegate(&delegate);
+
+ gfx::Transform target_transform;
+ EXPECT_CALL(delegate, OnLayerTransformed).Times(0);
+ layer->SetTransform(target_transform);
+}
+
// Verify that LayerDelegate::OnLayerTransformed() is called at every step of a
// non-threaded transform transition.
TEST(LayerDelegateTest, OnLayerTransformedNonThreadedAnimation) {
@@ -2996,8 +3082,8 @@ TEST(LayerDelegateTest, OnLayerTransformedNonThreadedAnimation) {
testing::Mock::VerifyAndClear(&delegate);
}
-// Verify that LayerDelegate::OnLayerTransformed() is called at the beginning
-// and at the end of a threaded transform transition.
+// Verify that LayerDelegate::OnLayerTransformed() is called at the end of a
+// threaded transform transition.
TEST(LayerDelegateTest, OnLayerTransformedThreadedAnimation) {
ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
ScopedAnimationDurationScaleMode::NORMAL_DURATION);
@@ -3019,17 +3105,12 @@ TEST(LayerDelegateTest, OnLayerTransformedThreadedAnimation) {
target_transform, base::TimeDelta::FromSeconds(1));
ASSERT_TRUE(element->IsThreaded(layer.get()));
LayerAnimationElement* element_raw = element.get();
+ // At the beginning, setting the transform actually does not change, so
+ // OnLayerTransformed isn't called.
EXPECT_CALL(delegate,
OnLayerTransformed(gfx::Transform(),
PropertyChangeReason::FROM_ANIMATION))
- .WillOnce(testing::Invoke([&](const gfx::Transform& old_transform,
- PropertyChangeReason) {
- // Verify that |layer->transform()| returns the correct value when the
- // delegate is notified.
- EXPECT_EQ(layer->transform(), initial_transform);
- EXPECT_TRUE(
- animator->IsAnimatingProperty(LayerAnimationElement::TRANSFORM));
- }));
+ .Times(0);
animator->StartAnimation(new LayerAnimationSequence(std::move(element)));
testing::Mock::VerifyAndClear(&delegate);
test_controller.StartThreadedAnimationsIfNeeded();