1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/views/animation/bounds_animator.h" 6 7 #include "testing/gtest/include/gtest/gtest.h" 8 #include "ui/gfx/animation/slide_animation.h" 9 #include "ui/gfx/animation/test_animation_delegate.h" 10 #include "ui/views/view.h" 11 12 using gfx::Animation; 13 using gfx::SlideAnimation; 14 using gfx::TestAnimationDelegate; 15 16 namespace views { 17 namespace { 18 19 class TestBoundsAnimator : public BoundsAnimator { 20 public: 21 explicit TestBoundsAnimator(View* view) : BoundsAnimator(view) { 22 } 23 24 protected: 25 virtual SlideAnimation* CreateAnimation() OVERRIDE { 26 SlideAnimation* animation = BoundsAnimator::CreateAnimation(); 27 animation->SetSlideDuration(10); 28 return animation; 29 } 30 31 private: 32 DISALLOW_COPY_AND_ASSIGN(TestBoundsAnimator); 33 }; 34 35 class OwnedDelegate : public gfx::AnimationDelegate { 36 public: 37 OwnedDelegate() {} 38 39 virtual ~OwnedDelegate() { 40 deleted_ = true; 41 } 42 43 static bool GetAndClearDeleted() { 44 bool value = deleted_; 45 deleted_ = false; 46 return value; 47 } 48 49 static bool GetAndClearCanceled() { 50 bool value = canceled_; 51 canceled_ = false; 52 return value; 53 } 54 55 // Overridden from gfx::AnimationDelegate: 56 virtual void AnimationCanceled(const Animation* animation) OVERRIDE { 57 canceled_ = true; 58 } 59 60 private: 61 static bool deleted_; 62 static bool canceled_; 63 64 DISALLOW_COPY_AND_ASSIGN(OwnedDelegate); 65 }; 66 67 // static 68 bool OwnedDelegate::deleted_ = false; 69 bool OwnedDelegate::canceled_ = false; 70 71 class TestView : public View { 72 public: 73 TestView() {} 74 75 virtual void SchedulePaintInRect(const gfx::Rect& r) OVERRIDE { 76 if (dirty_rect_.IsEmpty()) 77 dirty_rect_ = r; 78 else 79 dirty_rect_.Union(r); 80 } 81 82 const gfx::Rect& dirty_rect() const { return dirty_rect_; } 83 84 private: 85 gfx::Rect dirty_rect_; 86 87 DISALLOW_COPY_AND_ASSIGN(TestView); 88 }; 89 90 } // namespace 91 92 class BoundsAnimatorTest : public testing::Test { 93 public: 94 BoundsAnimatorTest() : child_(new TestView()), animator_(&parent_) { 95 parent_.AddChildView(child_); 96 } 97 98 TestView* parent() { return &parent_; } 99 TestView* child() { return child_; } 100 TestBoundsAnimator* animator() { return &animator_; } 101 102 private: 103 base::MessageLoopForUI message_loop_; 104 TestView parent_; 105 TestView* child_; // Owned by |parent_|. 106 TestBoundsAnimator animator_; 107 108 DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorTest); 109 }; 110 111 // Checks animate view to. 112 TEST_F(BoundsAnimatorTest, AnimateViewTo) { 113 gfx::Rect initial_bounds(0, 0, 10, 10); 114 child()->SetBoundsRect(initial_bounds); 115 gfx::Rect target_bounds(10, 10, 20, 20); 116 animator()->AnimateViewTo(child(), target_bounds); 117 animator()->SetAnimationDelegate( 118 child(), scoped_ptr<gfx::AnimationDelegate>(new TestAnimationDelegate())); 119 120 // The animator should be animating now. 121 EXPECT_TRUE(animator()->IsAnimating()); 122 123 // Run the message loop; the delegate exits the loop when the animation is 124 // done. 125 base::MessageLoop::current()->Run(); 126 127 // Make sure the bounds match of the view that was animated match. 128 EXPECT_EQ(target_bounds, child()->bounds()); 129 130 // The parent should have been told to repaint as the animation progressed. 131 // The resulting rect is the union of the original and target bounds. 132 EXPECT_EQ(gfx::UnionRects(target_bounds, initial_bounds), 133 parent()->dirty_rect()); 134 } 135 136 // Make sure an AnimationDelegate is deleted when canceled. 137 TEST_F(BoundsAnimatorTest, DeleteDelegateOnCancel) { 138 animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); 139 animator()->SetAnimationDelegate( 140 child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); 141 142 animator()->Cancel(); 143 144 // The animator should no longer be animating. 145 EXPECT_FALSE(animator()->IsAnimating()); 146 147 // The cancel should both cancel the delegate and delete it. 148 EXPECT_TRUE(OwnedDelegate::GetAndClearCanceled()); 149 EXPECT_TRUE(OwnedDelegate::GetAndClearDeleted()); 150 } 151 152 // Make sure an AnimationDelegate is deleted when another animation is 153 // scheduled. 154 TEST_F(BoundsAnimatorTest, DeleteDelegateOnNewAnimate) { 155 animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); 156 animator()->SetAnimationDelegate( 157 child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); 158 159 animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); 160 161 // Starting a new animation should both cancel the delegate and delete it. 162 EXPECT_TRUE(OwnedDelegate::GetAndClearDeleted()); 163 EXPECT_TRUE(OwnedDelegate::GetAndClearCanceled()); 164 } 165 166 // Makes sure StopAnimating works. 167 TEST_F(BoundsAnimatorTest, StopAnimating) { 168 scoped_ptr<OwnedDelegate> delegate(new OwnedDelegate()); 169 170 animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); 171 animator()->SetAnimationDelegate( 172 child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); 173 174 animator()->StopAnimatingView(child()); 175 176 // Shouldn't be animating now. 177 EXPECT_FALSE(animator()->IsAnimating()); 178 179 // Stopping should both cancel the delegate and delete it. 180 EXPECT_TRUE(OwnedDelegate::GetAndClearDeleted()); 181 EXPECT_TRUE(OwnedDelegate::GetAndClearCanceled()); 182 } 183 184 } // namespace views 185