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/ActiveAnimations.h" 35 #include "core/animation/AnimationClock.h" 36 #include "core/dom/Document.h" 37 #include "core/frame/FrameView.h" 38 #include "core/page/Page.h" 39 #include "platform/TraceEvent.h" 40 41 namespace WebCore { 42 43 // This value represents 1 frame at 30Hz plus a little bit of wiggle room. 44 // TODO: Plumb a nominal framerate through and derive this value from that. 45 const double AnimationTimeline::s_minimumDelay = 0.04; 46 47 48 PassRefPtrWillBeRawPtr<AnimationTimeline> AnimationTimeline::create(Document* document, PassOwnPtrWillBeRawPtr<PlatformTiming> timing) 49 { 50 return adoptRefWillBeNoop(new AnimationTimeline(document, timing)); 51 } 52 53 AnimationTimeline::AnimationTimeline(Document* document, PassOwnPtrWillBeRawPtr<PlatformTiming> timing) 54 : m_document(document) 55 { 56 if (!timing) 57 m_timing = adoptPtrWillBeNoop(new AnimationTimelineTiming(this)); 58 else 59 m_timing = timing; 60 61 ASSERT(document); 62 } 63 64 AnimationTimeline::~AnimationTimeline() 65 { 66 #if !ENABLE(OILPAN) 67 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<AnimationPlayer> >::iterator it = m_players.begin(); it != m_players.end(); ++it) 68 (*it)->timelineDestroyed(); 69 #endif 70 } 71 72 AnimationPlayer* AnimationTimeline::createAnimationPlayer(AnimationNode* child) 73 { 74 RefPtrWillBeRawPtr<AnimationPlayer> player = AnimationPlayer::create(m_document->contextDocument().get(), *this, child); 75 AnimationPlayer* result = player.get(); 76 m_players.add(result); 77 setOutdatedAnimationPlayer(result); 78 return result; 79 } 80 81 AnimationPlayer* AnimationTimeline::play(AnimationNode* child) 82 { 83 if (!m_document) 84 return 0; 85 AnimationPlayer* player = createAnimationPlayer(child); 86 m_document->compositorPendingAnimations().add(player); 87 return player; 88 } 89 90 void AnimationTimeline::wake() 91 { 92 m_timing->serviceOnNextFrame(); 93 } 94 95 void AnimationTimeline::serviceAnimations(TimingUpdateReason reason) 96 { 97 TRACE_EVENT0("webkit", "AnimationTimeline::serviceAnimations"); 98 99 m_timing->cancelWake(); 100 101 double timeToNextEffect = std::numeric_limits<double>::infinity(); 102 WillBeHeapVector<RawPtrWillBeMember<AnimationPlayer> > players; 103 for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it) 104 players.append(it->get()); 105 106 std::sort(players.begin(), players.end(), AnimationPlayer::hasLowerPriority); 107 108 for (size_t i = 0; i < players.size(); ++i) { 109 AnimationPlayer* player = players[i]; 110 if (player->update(reason)) 111 timeToNextEffect = std::min(timeToNextEffect, player->timeToEffectChange()); 112 else 113 m_playersNeedingUpdate.remove(player); 114 } 115 116 if (timeToNextEffect < s_minimumDelay) 117 m_timing->serviceOnNextFrame(); 118 else if (timeToNextEffect != std::numeric_limits<double>::infinity()) 119 m_timing->wakeAfter(timeToNextEffect - s_minimumDelay); 120 121 ASSERT(!hasOutdatedAnimationPlayer()); 122 } 123 124 void AnimationTimeline::AnimationTimelineTiming::wakeAfter(double duration) 125 { 126 m_timer.startOneShot(duration, FROM_HERE); 127 } 128 129 void AnimationTimeline::AnimationTimelineTiming::cancelWake() 130 { 131 m_timer.stop(); 132 } 133 134 void AnimationTimeline::AnimationTimelineTiming::serviceOnNextFrame() 135 { 136 if (m_timeline->m_document && m_timeline->m_document->view()) 137 m_timeline->m_document->view()->scheduleAnimation(); 138 } 139 140 void AnimationTimeline::AnimationTimelineTiming::trace(Visitor* visitor) 141 { 142 visitor->trace(m_timeline); 143 AnimationTimeline::PlatformTiming::trace(visitor); 144 } 145 146 double AnimationTimeline::currentTime(bool& isNull) 147 { 148 return currentTimeInternal(isNull) * 1000; 149 } 150 151 double AnimationTimeline::currentTimeInternal(bool& isNull) 152 { 153 if (!m_document) { 154 isNull = true; 155 return std::numeric_limits<double>::quiet_NaN(); 156 } 157 double result = m_document->animationClock().currentTime() - zeroTime(); 158 isNull = std::isnan(result); 159 return result; 160 } 161 162 double AnimationTimeline::currentTime() 163 { 164 return currentTimeInternal() * 1000; 165 } 166 167 double AnimationTimeline::currentTimeInternal() 168 { 169 bool isNull; 170 return currentTimeInternal(isNull); 171 } 172 173 double AnimationTimeline::effectiveTime() 174 { 175 double time = currentTimeInternal(); 176 return std::isnan(time) ? 0 : time; 177 } 178 179 void AnimationTimeline::pauseAnimationsForTesting(double pauseTime) 180 { 181 for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it) 182 (*it)->pauseForTesting(pauseTime); 183 serviceAnimations(TimingUpdateOnDemand); 184 } 185 186 bool AnimationTimeline::hasOutdatedAnimationPlayer() const 187 { 188 for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it) { 189 if ((*it)->outdated()) 190 return true; 191 } 192 return false; 193 } 194 195 void AnimationTimeline::setOutdatedAnimationPlayer(AnimationPlayer* player) 196 { 197 ASSERT(player->outdated()); 198 m_playersNeedingUpdate.add(player); 199 if (m_document && m_document->page() && !m_document->page()->animator().isServicingAnimations()) 200 m_timing->serviceOnNextFrame(); 201 } 202 203 size_t AnimationTimeline::numberOfActiveAnimationsForTesting() const 204 { 205 // Includes all players whose directly associated timed items 206 // are current or in effect. 207 size_t count = 0; 208 for (WillBeHeapHashSet<RefPtrWillBeMember<AnimationPlayer> >::iterator it = m_playersNeedingUpdate.begin(); it != m_playersNeedingUpdate.end(); ++it) { 209 const AnimationNode* animationNode = (*it)->source(); 210 if ((*it)->hasStartTime()) 211 count += (animationNode && (animationNode->isCurrent() || animationNode->isInEffect())); 212 } 213 return count; 214 } 215 216 #if !ENABLE(OILPAN) 217 void AnimationTimeline::detachFromDocument() 218 { 219 // FIXME: AnimationTimeline should keep Document alive. 220 m_document = nullptr; 221 } 222 #endif 223 224 void AnimationTimeline::trace(Visitor* visitor) 225 { 226 visitor->trace(m_document); 227 visitor->trace(m_timing); 228 visitor->trace(m_playersNeedingUpdate); 229 visitor->trace(m_players); 230 } 231 232 } // namespace 233