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 
     32 #include "config.h"
     33 #include "core/animation/Player.h"
     34 
     35 #include "core/animation/Animation.h"
     36 #include "core/animation/DocumentTimeline.h"
     37 
     38 namespace WebCore {
     39 
     40 namespace {
     41 
     42 double effectiveTime(double time) { return isNull(time) ? 0 : time; }
     43 
     44 } // namespace
     45 
     46 PassRefPtr<Player> Player::create(DocumentTimeline& timeline, TimedItem* content)
     47 {
     48     return adoptRef(new Player(timeline, content));
     49 }
     50 
     51 Player::Player(DocumentTimeline& timeline, TimedItem* content)
     52     : m_pauseStartTime(nullValue())
     53     , m_playbackRate(1)
     54     , m_timeDrift(0)
     55     , m_startTime(nullValue())
     56     , m_content(content)
     57     , m_timeline(timeline)
     58     , m_isPausedForTesting(false)
     59 {
     60     if (m_content)
     61         m_content->attach(this);
     62 }
     63 
     64 Player::~Player()
     65 {
     66     if (m_content)
     67         m_content->detach();
     68 }
     69 
     70 void Player::setStartTime(double startTime)
     71 {
     72     ASSERT(!isNull(startTime));
     73     ASSERT(!hasStartTime());
     74     m_startTime = startTime;
     75     update();
     76 }
     77 
     78 double Player::currentTimeBeforeDrift() const
     79 {
     80     if (isNull(m_startTime))
     81         return 0;
     82     return (effectiveTime(m_timeline.currentTime()) - startTime()) * m_playbackRate;
     83 }
     84 
     85 bool Player::maybeStartAnimationOnCompositor()
     86 {
     87     // FIXME: Support starting compositor animations that have a fixed
     88     // start time.
     89     ASSERT(!hasStartTime());
     90     if (!m_content || !m_content->isAnimation())
     91         return false;
     92 
     93     return toAnimation(m_content.get())->maybeStartAnimationOnCompositor();
     94 }
     95 
     96 bool Player::hasActiveAnimationsOnCompositor()
     97 {
     98     if (!m_content || !m_content->isAnimation())
     99         return false;
    100     return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
    101 }
    102 
    103 void Player::cancelAnimationOnCompositor()
    104 {
    105     if (hasActiveAnimationsOnCompositor())
    106         toAnimation(m_content.get())->cancelAnimationOnCompositor();
    107 }
    108 
    109 double Player::pausedTimeDrift() const
    110 {
    111     ASSERT(pausedInternal());
    112     return currentTimeBeforeDrift() - m_pauseStartTime;
    113 }
    114 
    115 double Player::timeDrift() const
    116 {
    117     return pausedInternal() ? pausedTimeDrift() : m_timeDrift;
    118 }
    119 
    120 double Player::currentTime() const
    121 {
    122     return currentTimeBeforeDrift() - timeDrift();
    123 }
    124 
    125 bool Player::update(double* timeToEffectChange, bool* didTriggerStyleRecalc)
    126 {
    127     if (!m_content) {
    128         if (timeToEffectChange)
    129             *timeToEffectChange = std::numeric_limits<double>::infinity();
    130         if (didTriggerStyleRecalc)
    131             *didTriggerStyleRecalc = false;
    132         return false;
    133     }
    134 
    135     double inheritedTime = isNull(m_timeline.currentTime()) ? nullValue() : currentTime();
    136     bool didTriggerStyleRecalcLocal = m_content->updateInheritedTime(inheritedTime);
    137 
    138     if (timeToEffectChange)
    139         *timeToEffectChange = m_content->timeToEffectChange();
    140     if (didTriggerStyleRecalc)
    141         *didTriggerStyleRecalc = didTriggerStyleRecalcLocal;
    142     return m_content->isCurrent() || m_content->isInEffect();
    143 }
    144 
    145 void Player::cancel()
    146 {
    147     if (!m_content)
    148         return;
    149 
    150     ASSERT(m_content->player() == this);
    151     m_content->detach();
    152     m_content = 0;
    153 }
    154 
    155 void Player::setCurrentTime(double seekTime)
    156 {
    157     if (pausedInternal())
    158         m_pauseStartTime = seekTime;
    159     else
    160         m_timeDrift = currentTimeBeforeDrift() - seekTime;
    161 
    162     if (m_isPausedForTesting && hasActiveAnimationsOnCompositor())
    163         toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTime());
    164     update();
    165 }
    166 
    167 void Player::pauseForTesting()
    168 {
    169     RELEASE_ASSERT(!paused());
    170     if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor())
    171         toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTime());
    172     m_isPausedForTesting = true;
    173     setPausedImpl(true);
    174 }
    175 
    176 void Player::setPaused(bool newValue)
    177 {
    178     ASSERT(!m_isPausedForTesting);
    179     setPausedImpl(newValue);
    180 }
    181 
    182 void Player::setPausedImpl(bool newValue)
    183 {
    184     if (pausedInternal() == newValue)
    185         return;
    186 
    187     if (newValue) {
    188         // FIXME: resume compositor animation rather than pull back to main-thread
    189         cancelAnimationOnCompositor();
    190         m_pauseStartTime = currentTime();
    191     } else {
    192         m_timeDrift = pausedTimeDrift();
    193         m_pauseStartTime = nullValue();
    194     }
    195 }
    196 
    197 void Player::setPlaybackRate(double newRate)
    198 {
    199     double previousTime = currentTime();
    200     m_playbackRate = newRate;
    201     setCurrentTime(previousTime);
    202 }
    203 
    204 } // namespace
    205