Home | History | Annotate | Download | only in animation
      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/AnimationPlayer.h"
     33 
     34 #include "core/animation/Animation.h"
     35 #include "core/animation/AnimationTimeline.h"
     36 #include "core/dom/Document.h"
     37 #include "core/events/AnimationPlayerEvent.h"
     38 #include "core/frame/UseCounter.h"
     39 
     40 namespace WebCore {
     41 
     42 namespace {
     43 
     44 static unsigned nextSequenceNumber()
     45 {
     46     static unsigned next = 0;
     47     return ++next;
     48 }
     49 
     50 }
     51 
     52 PassRefPtrWillBeRawPtr<AnimationPlayer> AnimationPlayer::create(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
     53 {
     54     RefPtrWillBeRawPtr<AnimationPlayer> player = adoptRefWillBeRefCountedGarbageCollected(new AnimationPlayer(executionContext, timeline, content));
     55     player->suspendIfNeeded();
     56     return player.release();
     57 }
     58 
     59 AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
     60     : ActiveDOMObject(executionContext)
     61     , m_playbackRate(1)
     62     , m_startTime(nullValue())
     63     , m_holdTime(nullValue())
     64     , m_storedTimeLag(0)
     65     , m_sortInfo(nextSequenceNumber(), timeline.effectiveTime())
     66     , m_content(content)
     67     , m_timeline(&timeline)
     68     , m_paused(false)
     69     , m_held(false)
     70     , m_isPausedForTesting(false)
     71     , m_outdated(true)
     72     , m_finished(false)
     73 {
     74     if (m_content) {
     75         if (m_content->player())
     76             m_content->player()->cancel();
     77         m_content->attach(this);
     78     }
     79 }
     80 
     81 AnimationPlayer::~AnimationPlayer()
     82 {
     83 #if !ENABLE(OILPAN)
     84     if (m_content)
     85         m_content->detach();
     86     if (m_timeline)
     87         m_timeline->playerDestroyed(this);
     88 #endif
     89 }
     90 
     91 double AnimationPlayer::sourceEnd() const
     92 {
     93     return m_content ? m_content->endTimeInternal() : 0;
     94 }
     95 
     96 bool AnimationPlayer::limited(double currentTime) const
     97 {
     98     return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd());
     99 }
    100 
    101 double AnimationPlayer::currentTimeWithoutLag() const
    102 {
    103     if (isNull(m_startTime) || !m_timeline)
    104         return 0;
    105     return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
    106 }
    107 
    108 double AnimationPlayer::currentTimeWithLag() const
    109 {
    110     ASSERT(!m_held);
    111     double time = currentTimeWithoutLag();
    112     return std::isinf(time) ? time : time - m_storedTimeLag;
    113 }
    114 
    115 void AnimationPlayer::updateTimingState(double newCurrentTime)
    116 {
    117     ASSERT(!isNull(newCurrentTime));
    118     bool oldHeld = m_held;
    119     m_held = m_paused || !m_playbackRate || limited(newCurrentTime);
    120     if (m_held) {
    121         if (!oldHeld || m_holdTime != newCurrentTime)
    122             setOutdated();
    123         m_holdTime = newCurrentTime;
    124         m_storedTimeLag = nullValue();
    125     } else {
    126         m_holdTime = nullValue();
    127         m_storedTimeLag = currentTimeWithoutLag() - newCurrentTime;
    128         m_finished = false;
    129         setOutdated();
    130     }
    131 }
    132 
    133 void AnimationPlayer::updateCurrentTimingState()
    134 {
    135     if (m_held) {
    136         updateTimingState(m_holdTime);
    137         return;
    138     }
    139     if (!limited(currentTimeWithLag()))
    140         return;
    141     m_held = true;
    142     m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
    143     m_storedTimeLag = nullValue();
    144 }
    145 
    146 double AnimationPlayer::currentTime()
    147 {
    148     return currentTimeInternal() * 1000;
    149 }
    150 
    151 double AnimationPlayer::currentTimeInternal()
    152 {
    153     updateCurrentTimingState();
    154     if (m_held)
    155         return m_holdTime;
    156     return currentTimeWithLag();
    157 }
    158 
    159 void AnimationPlayer::setCurrentTime(double newCurrentTime)
    160 {
    161     setCurrentTimeInternal(newCurrentTime / 1000);
    162 }
    163 
    164 void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime)
    165 {
    166     if (!std::isfinite(newCurrentTime))
    167         return;
    168     updateTimingState(newCurrentTime);
    169     cancelAnimationOnCompositor();
    170     schedulePendingAnimationOnCompositor();
    171 }
    172 
    173 void AnimationPlayer::setStartTimeInternal(double newStartTime, bool isUpdateFromCompositor)
    174 {
    175     ASSERT(!isUpdateFromCompositor || !hasStartTime());
    176 
    177     if (!std::isfinite(newStartTime))
    178         return;
    179     if (newStartTime == m_startTime)
    180         return;
    181     updateCurrentTimingState(); // Update the value of held
    182     bool hadStartTime = hasStartTime();
    183     double previousCurrentTime = currentTimeInternal();
    184     m_startTime = newStartTime;
    185     m_sortInfo.m_startTime = newStartTime;
    186     updateCurrentTimingState();
    187     if (previousCurrentTime != currentTimeInternal()) {
    188         setOutdated();
    189     } else if (!hadStartTime && m_timeline) {
    190         // Even though this player is not outdated, time to effect change is
    191         // infinity until start time is set.
    192         m_timeline->wake();
    193     }
    194     if (!isUpdateFromCompositor) {
    195         cancelAnimationOnCompositor();
    196         schedulePendingAnimationOnCompositor();
    197     }
    198 }
    199 
    200 void AnimationPlayer::setSource(AnimationNode* newSource)
    201 {
    202     if (m_content == newSource)
    203         return;
    204     cancelAnimationOnCompositor();
    205     double storedCurrentTime = currentTimeInternal();
    206     if (m_content)
    207         m_content->detach();
    208     m_content = newSource;
    209     if (newSource) {
    210         // FIXME: This logic needs to be updated once groups are implemented
    211         if (newSource->player())
    212             newSource->player()->cancel();
    213         newSource->attach(this);
    214     }
    215     updateTimingState(storedCurrentTime);
    216     schedulePendingAnimationOnCompositor();
    217 }
    218 
    219 void AnimationPlayer::pause()
    220 {
    221     if (m_paused)
    222         return;
    223     m_paused = true;
    224     updateTimingState(currentTimeInternal());
    225     cancelAnimationOnCompositor();
    226 }
    227 
    228 void AnimationPlayer::unpause()
    229 {
    230     if (!m_paused)
    231         return;
    232     m_paused = false;
    233     updateTimingState(currentTimeInternal());
    234     schedulePendingAnimationOnCompositor();
    235 }
    236 
    237 void AnimationPlayer::play()
    238 {
    239     cancelAnimationOnCompositor();
    240     // Note, unpause schedules pending animation on compositor if necessary.
    241     unpause();
    242     if (!m_content)
    243         return;
    244     double currentTime = this->currentTimeInternal();
    245     if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd()))
    246         setCurrentTimeInternal(0);
    247     else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd()))
    248         setCurrentTimeInternal(sourceEnd());
    249     m_finished = false;
    250 }
    251 
    252 void AnimationPlayer::reverse()
    253 {
    254     if (!m_playbackRate)
    255         return;
    256     if (m_content) {
    257         if (m_playbackRate > 0 && currentTimeInternal() > sourceEnd())
    258             setCurrentTimeInternal(sourceEnd());
    259         else if (m_playbackRate < 0 && currentTimeInternal() < 0)
    260             setCurrentTimeInternal(0);
    261     }
    262     setPlaybackRate(-m_playbackRate);
    263     cancelAnimationOnCompositor();
    264     // Note, unpause schedules pending animation on compositor if necessary.
    265     unpause();
    266 }
    267 
    268 void AnimationPlayer::finish(ExceptionState& exceptionState)
    269 {
    270     if (!m_playbackRate)
    271         return;
    272     if (m_playbackRate < 0) {
    273         setCurrentTimeInternal(0);
    274     } else {
    275         if (sourceEnd() == std::numeric_limits<double>::infinity()) {
    276             exceptionState.throwDOMException(InvalidStateError, "AnimationPlayer has source content whose end time is infinity.");
    277             return;
    278         }
    279         setCurrentTimeInternal(sourceEnd());
    280     }
    281     ASSERT(finished());
    282     cancelAnimationOnCompositor();
    283 }
    284 
    285 const AtomicString& AnimationPlayer::interfaceName() const
    286 {
    287     return EventTargetNames::AnimationPlayer;
    288 }
    289 
    290 ExecutionContext* AnimationPlayer::executionContext() const
    291 {
    292     return ActiveDOMObject::executionContext();
    293 }
    294 
    295 bool AnimationPlayer::hasPendingActivity() const
    296 {
    297     return m_pendingFinishedEvent || (!m_finished && hasEventListeners(EventTypeNames::finish));
    298 }
    299 
    300 void AnimationPlayer::stop()
    301 {
    302     m_finished = true;
    303     m_pendingFinishedEvent = nullptr;
    304 }
    305 
    306 bool AnimationPlayer::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
    307 {
    308     if (m_pendingFinishedEvent == event)
    309         m_pendingFinishedEvent = nullptr;
    310     return EventTargetWithInlineData::dispatchEvent(event);
    311 }
    312 
    313 void AnimationPlayer::setPlaybackRate(double playbackRate)
    314 {
    315     if (!std::isfinite(playbackRate))
    316         return;
    317     double storedCurrentTime = currentTimeInternal();
    318     if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
    319         m_finished = false;
    320     m_playbackRate = playbackRate;
    321     updateTimingState(storedCurrentTime);
    322     cancelAnimationOnCompositor();
    323     schedulePendingAnimationOnCompositor();
    324 }
    325 
    326 void AnimationPlayer::setOutdated()
    327 {
    328     m_outdated = true;
    329     if (m_timeline)
    330         m_timeline->setOutdatedAnimationPlayer(this);
    331 }
    332 
    333 bool AnimationPlayer::canStartAnimationOnCompositor()
    334 {
    335     // FIXME: Need compositor support for playback rate != 1.
    336     if (playbackRate() != 1)
    337         return false;
    338 
    339     return m_timeline && m_content && m_content->isAnimation() && !m_held;
    340 }
    341 
    342 bool AnimationPlayer::maybeStartAnimationOnCompositor()
    343 {
    344     if (!canStartAnimationOnCompositor())
    345         return false;
    346 
    347     return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(timeline()->zeroTime() + startTimeInternal() + timeLagInternal());
    348 }
    349 
    350 void AnimationPlayer::schedulePendingAnimationOnCompositor()
    351 {
    352     ASSERT(!hasActiveAnimationsOnCompositor());
    353 
    354     if (canStartAnimationOnCompositor())
    355         timeline()->document()->compositorPendingAnimations().add(this);
    356 }
    357 
    358 bool AnimationPlayer::hasActiveAnimationsOnCompositor()
    359 {
    360     if (!m_content || !m_content->isAnimation())
    361         return false;
    362 
    363     return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
    364 }
    365 
    366 void AnimationPlayer::cancelAnimationOnCompositor()
    367 {
    368     if (hasActiveAnimationsOnCompositor())
    369         toAnimation(m_content.get())->cancelAnimationOnCompositor();
    370 }
    371 
    372 bool AnimationPlayer::update(TimingUpdateReason reason)
    373 {
    374     m_outdated = false;
    375 
    376     if (!m_timeline)
    377         return false;
    378 
    379     if (m_content) {
    380         double inheritedTime = isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
    381         m_content->updateInheritedTime(inheritedTime, reason);
    382     }
    383 
    384     if (finished() && !m_finished) {
    385         if (reason == TimingUpdateForAnimationFrame && hasStartTime()) {
    386             const AtomicString& eventType = EventTypeNames::finish;
    387             if (executionContext() && hasEventListeners(eventType)) {
    388                 m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, currentTime(), timeline()->currentTime());
    389                 m_pendingFinishedEvent->setTarget(this);
    390                 m_pendingFinishedEvent->setCurrentTarget(this);
    391                 m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent);
    392             }
    393             m_finished = true;
    394         }
    395     }
    396     ASSERT(!m_outdated);
    397     return !m_finished || !finished();
    398 }
    399 
    400 double AnimationPlayer::timeToEffectChange()
    401 {
    402     ASSERT(!m_outdated);
    403     if (m_held || !hasStartTime())
    404         return std::numeric_limits<double>::infinity();
    405     if (!m_content)
    406         return -currentTimeInternal() / m_playbackRate;
    407     if (m_playbackRate > 0)
    408         return m_content->timeToForwardsEffectChange() / m_playbackRate;
    409     return m_content->timeToReverseEffectChange() / -m_playbackRate;
    410 }
    411 
    412 void AnimationPlayer::cancel()
    413 {
    414     setSource(0);
    415 }
    416 
    417 bool AnimationPlayer::SortInfo::operator<(const SortInfo& other) const
    418 {
    419     ASSERT(!std::isnan(m_startTime) && !std::isnan(other.m_startTime));
    420     if (m_startTime < other.m_startTime)
    421         return true;
    422     if (m_startTime > other.m_startTime)
    423         return false;
    424     return m_sequenceNumber < other.m_sequenceNumber;
    425 }
    426 
    427 #if !ENABLE(OILPAN)
    428 bool AnimationPlayer::canFree() const
    429 {
    430     ASSERT(m_content);
    431     return hasOneRef() && m_content->isAnimation() && m_content->hasOneRef();
    432 }
    433 #endif
    434 
    435 bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
    436 {
    437     if (eventType == EventTypeNames::finish)
    438         UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishEvent);
    439     return EventTargetWithInlineData::addEventListener(eventType, listener, useCapture);
    440 }
    441 
    442 void AnimationPlayer::pauseForTesting(double pauseTime)
    443 {
    444     RELEASE_ASSERT(!paused());
    445     updateTimingState(pauseTime);
    446     if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor())
    447         toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
    448     m_isPausedForTesting = true;
    449     pause();
    450 }
    451 
    452 void AnimationPlayer::trace(Visitor* visitor)
    453 {
    454     visitor->trace(m_content);
    455     visitor->trace(m_timeline);
    456     visitor->trace(m_pendingFinishedEvent);
    457     EventTargetWithInlineData::trace(visitor);
    458 }
    459 
    460 } // namespace
    461