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