1 /* 2 * Copyright (c) 2013, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/animation/AnimationTimeline.h" 33 34 #include "core/animation/Animation.h" 35 #include "core/animation/AnimationClock.h" 36 #include "core/animation/AnimationNode.h" 37 #include "core/animation/KeyframeEffectModel.h" 38 #include "core/dom/Document.h" 39 #include "core/dom/Element.h" 40 #include "core/dom/QualifiedName.h" 41 #include "platform/weborigin/KURL.h" 42 43 #include <gmock/gmock.h> 44 #include <gtest/gtest.h> 45 46 namespace WebCore { 47 48 class MockPlatformTiming : public AnimationTimeline::PlatformTiming { 49 public: 50 51 MOCK_METHOD1(wakeAfter, void(double)); 52 MOCK_METHOD0(cancelWake, void()); 53 MOCK_METHOD0(serviceOnNextFrame, void()); 54 55 /** 56 * AnimationTimelines should do one of the following things after servicing animations: 57 * - cancel the timer and not request to be woken again (expectNoMoreActions) 58 * - cancel the timer and request to be woken on the next frame (expectNextFrameAction) 59 * - cancel the timer and request to be woken at some point in the future (expectDelayedAction) 60 */ 61 62 void expectNoMoreActions() 63 { 64 EXPECT_CALL(*this, cancelWake()); 65 } 66 67 void expectNextFrameAction() 68 { 69 ::testing::Sequence sequence; 70 EXPECT_CALL(*this, cancelWake()).InSequence(sequence); 71 EXPECT_CALL(*this, serviceOnNextFrame()).InSequence(sequence); 72 } 73 74 void expectDelayedAction(double when) 75 { 76 ::testing::Sequence sequence; 77 EXPECT_CALL(*this, cancelWake()).InSequence(sequence); 78 EXPECT_CALL(*this, wakeAfter(when)).InSequence(sequence); 79 } 80 81 void trace(Visitor* visitor) 82 { 83 AnimationTimeline::PlatformTiming::trace(visitor); 84 } 85 }; 86 87 class AnimationAnimationTimelineTest : public ::testing::Test { 88 protected: 89 virtual void SetUp() 90 { 91 document = Document::create(); 92 document->animationClock().resetTimeForTesting(); 93 element = Element::create(QualifiedName::null() , document.get()); 94 platformTiming = new MockPlatformTiming; 95 timeline = AnimationTimeline::create(document.get(), adoptPtrWillBeNoop(platformTiming)); 96 ASSERT_EQ(0, timeline->currentTimeInternal()); 97 } 98 99 virtual void TearDown() 100 { 101 document.release(); 102 element.release(); 103 timeline.release(); 104 } 105 106 void updateClockAndService(double time) 107 { 108 document->animationClock().updateTime(time); 109 timeline->serviceAnimations(TimingUpdateForAnimationFrame); 110 } 111 112 RefPtrWillBePersistent<Document> document; 113 RefPtrWillBePersistent<Element> element; 114 RefPtrWillBePersistent<AnimationTimeline> timeline; 115 Timing timing; 116 MockPlatformTiming* platformTiming; 117 118 void wake() 119 { 120 timeline->wake(); 121 } 122 123 double minimumDelay() 124 { 125 return AnimationTimeline::s_minimumDelay; 126 } 127 }; 128 129 TEST_F(AnimationAnimationTimelineTest, HasStarted) 130 { 131 timeline = AnimationTimeline::create(document.get()); 132 } 133 134 TEST_F(AnimationAnimationTimelineTest, EmptyKeyframeAnimation) 135 { 136 RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()); 137 RefPtrWillBeRawPtr<Animation> anim = Animation::create(element.get(), effect, timing); 138 139 timeline->play(anim.get()); 140 141 platformTiming->expectNoMoreActions(); 142 updateClockAndService(0); 143 EXPECT_FLOAT_EQ(0, timeline->currentTimeInternal()); 144 EXPECT_FALSE(anim->isInEffect()); 145 146 platformTiming->expectNoMoreActions(); 147 updateClockAndService(100); 148 EXPECT_FLOAT_EQ(100, timeline->currentTimeInternal()); 149 } 150 151 TEST_F(AnimationAnimationTimelineTest, EmptyForwardsKeyframeAnimation) 152 { 153 RefPtrWillBeRawPtr<AnimatableValueKeyframeEffectModel> effect = AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()); 154 timing.fillMode = Timing::FillModeForwards; 155 RefPtrWillBeRawPtr<Animation> anim = Animation::create(element.get(), effect, timing); 156 157 timeline->play(anim.get()); 158 159 platformTiming->expectNoMoreActions(); 160 updateClockAndService(0); 161 EXPECT_FLOAT_EQ(0, timeline->currentTimeInternal()); 162 EXPECT_TRUE(anim->isInEffect()); 163 164 platformTiming->expectNoMoreActions(); 165 updateClockAndService(100); 166 EXPECT_FLOAT_EQ(100, timeline->currentTimeInternal()); 167 } 168 169 TEST_F(AnimationAnimationTimelineTest, ZeroTime) 170 { 171 timeline = AnimationTimeline::create(document.get()); 172 bool isNull; 173 174 document->animationClock().updateTime(100); 175 EXPECT_EQ(100, timeline->currentTimeInternal()); 176 EXPECT_EQ(100, timeline->currentTimeInternal(isNull)); 177 EXPECT_FALSE(isNull); 178 179 document->animationClock().updateTime(200); 180 EXPECT_EQ(200, timeline->currentTimeInternal()); 181 EXPECT_EQ(200, timeline->currentTimeInternal(isNull)); 182 EXPECT_FALSE(isNull); 183 } 184 185 TEST_F(AnimationAnimationTimelineTest, PauseForTesting) 186 { 187 float seekTime = 1; 188 timing.fillMode = Timing::FillModeForwards; 189 RefPtrWillBeRawPtr<Animation> anim1 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timing); 190 RefPtrWillBeRawPtr<Animation> anim2 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timing); 191 AnimationPlayer* player1 = timeline->play(anim1.get()); 192 AnimationPlayer* player2 = timeline->play(anim2.get()); 193 timeline->pauseAnimationsForTesting(seekTime); 194 195 EXPECT_FLOAT_EQ(seekTime, player1->currentTimeInternal()); 196 EXPECT_FLOAT_EQ(seekTime, player2->currentTimeInternal()); 197 } 198 199 TEST_F(AnimationAnimationTimelineTest, NumberOfActiveAnimations) 200 { 201 Timing timingForwardFill; 202 timingForwardFill.iterationDuration = 2; 203 timingForwardFill.fillMode = Timing::FillModeForwards; 204 205 Timing timingNoFill; 206 timingNoFill.iterationDuration = 2; 207 timingNoFill.fillMode = Timing::FillModeNone; 208 209 Timing timingBackwardFillDelay; 210 timingBackwardFillDelay.iterationDuration = 1; 211 timingBackwardFillDelay.fillMode = Timing::FillModeBackwards; 212 timingBackwardFillDelay.startDelay = 1; 213 214 Timing timingNoFillDelay; 215 timingNoFillDelay.iterationDuration = 1; 216 timingNoFillDelay.fillMode = Timing::FillModeNone; 217 timingNoFillDelay.startDelay = 1; 218 219 Timing timingAutoFill; 220 timingAutoFill.iterationDuration = 2; 221 222 RefPtrWillBeRawPtr<Animation> anim1 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingForwardFill); 223 RefPtrWillBeRawPtr<Animation> anim2 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingNoFill); 224 RefPtrWillBeRawPtr<Animation> anim3 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingBackwardFillDelay); 225 RefPtrWillBeRawPtr<Animation> anim4 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingNoFillDelay); 226 RefPtrWillBeRawPtr<Animation> anim5 = Animation::create(element.get(), AnimatableValueKeyframeEffectModel::create(AnimatableValueKeyframeVector()), timingAutoFill); 227 228 timeline->play(anim1.get()); 229 timeline->play(anim2.get()); 230 timeline->play(anim3.get()); 231 timeline->play(anim4.get()); 232 timeline->play(anim5.get()); 233 234 platformTiming->expectNextFrameAction(); 235 updateClockAndService(0); 236 EXPECT_EQ(5U, timeline->numberOfActiveAnimationsForTesting()); 237 platformTiming->expectNextFrameAction(); 238 updateClockAndService(0.5); 239 EXPECT_EQ(5U, timeline->numberOfActiveAnimationsForTesting()); 240 platformTiming->expectNextFrameAction(); 241 updateClockAndService(1.5); 242 EXPECT_EQ(5U, timeline->numberOfActiveAnimationsForTesting()); 243 platformTiming->expectNoMoreActions(); 244 updateClockAndService(3); 245 EXPECT_EQ(0U, timeline->numberOfActiveAnimationsForTesting()); 246 } 247 248 TEST_F(AnimationAnimationTimelineTest, DelayBeforeAnimationStart) 249 { 250 timing.iterationDuration = 2; 251 timing.startDelay = 5; 252 253 RefPtrWillBeRawPtr<Animation> anim = Animation::create(element.get(), nullptr, timing); 254 255 timeline->play(anim.get()); 256 257 // TODO: Put the player startTime in the future when we add the capability to change player startTime 258 platformTiming->expectDelayedAction(timing.startDelay - minimumDelay()); 259 updateClockAndService(0); 260 261 platformTiming->expectDelayedAction(timing.startDelay - minimumDelay() - 1.5); 262 updateClockAndService(1.5); 263 264 EXPECT_CALL(*platformTiming, serviceOnNextFrame()); 265 wake(); 266 267 platformTiming->expectNextFrameAction(); 268 updateClockAndService(4.98); 269 } 270 271 TEST_F(AnimationAnimationTimelineTest, PlayAfterDocumentDeref) 272 { 273 timing.iterationDuration = 2; 274 timing.startDelay = 5; 275 276 timeline = &document->timeline(); 277 element = nullptr; 278 document = nullptr; 279 280 RefPtrWillBeRawPtr<Animation> anim = Animation::create(0, nullptr, timing); 281 // Test passes if this does not crash. 282 timeline->play(anim.get()); 283 } 284 285 TEST_F(AnimationAnimationTimelineTest, UseAnimationPlayerAfterTimelineDeref) 286 { 287 RefPtrWillBeRawPtr<AnimationPlayer> player = timeline->createAnimationPlayer(0); 288 timeline.clear(); 289 // Test passes if this does not crash. 290 player->setStartTime(0); 291 } 292 293 } 294