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/Animation.h"
     33 
     34 #include "bindings/core/v8/Dictionary.h"
     35 #include "bindings/core/v8/ExceptionState.h"
     36 #include "core/animation/ActiveAnimations.h"
     37 #include "core/animation/AnimationPlayer.h"
     38 #include "core/animation/AnimationTimeline.h"
     39 #include "core/animation/CompositorAnimations.h"
     40 #include "core/animation/Interpolation.h"
     41 #include "core/animation/KeyframeEffectModel.h"
     42 #include "core/dom/Element.h"
     43 #include "core/frame/UseCounter.h"
     44 #include "core/rendering/RenderLayer.h"
     45 
     46 namespace blink {
     47 
     48 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtrWillBeRawPtr<EventDelegate> eventDelegate)
     49 {
     50     return adoptRefWillBeNoop(new Animation(target, effect, timing, priority, eventDelegate));
     51 }
     52 
     53 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Dictionary& timingInputDictionary)
     54 {
     55     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
     56     return create(element, effect, TimingInput::convert(timingInputDictionary));
     57 }
     58 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, double duration)
     59 {
     60     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
     61     return create(element, effect, TimingInput::convert(duration));
     62 }
     63 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect)
     64 {
     65     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
     66     return create(element, effect, Timing());
     67 }
     68 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, const Dictionary& timingInputDictionary, ExceptionState& exceptionState)
     69 {
     70     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
     71     if (element)
     72         UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectObjectTiming);
     73     return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(timingInputDictionary));
     74 }
     75 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, double duration, ExceptionState& exceptionState)
     76 {
     77     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
     78     if (element)
     79         UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectDoubleTiming);
     80     return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(duration));
     81 }
     82 PassRefPtrWillBeRawPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
     83 {
     84     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
     85     if (element)
     86         UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectNoTiming);
     87     return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), Timing());
     88 }
     89 
     90 Animation::Animation(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtrWillBeRawPtr<EventDelegate> eventDelegate)
     91     : AnimationNode(timing, eventDelegate)
     92     , m_target(target)
     93     , m_effect(effect)
     94     , m_sampledEffect(nullptr)
     95     , m_priority(priority)
     96 {
     97 #if !ENABLE(OILPAN)
     98     if (m_target)
     99         m_target->ensureActiveAnimations().addAnimation(this);
    100 #endif
    101 }
    102 
    103 Animation::~Animation()
    104 {
    105 #if !ENABLE(OILPAN)
    106     if (m_target)
    107         m_target->activeAnimations()->notifyAnimationDestroyed(this);
    108 #endif
    109 }
    110 
    111 void Animation::attach(AnimationPlayer* player)
    112 {
    113     if (m_target) {
    114         m_target->ensureActiveAnimations().players().add(player);
    115         m_target->setNeedsAnimationStyleRecalc();
    116     }
    117     AnimationNode::attach(player);
    118 }
    119 
    120 void Animation::detach()
    121 {
    122     if (m_target)
    123         m_target->activeAnimations()->players().remove(player());
    124     if (m_sampledEffect)
    125         clearEffects();
    126     AnimationNode::detach();
    127 }
    128 
    129 void Animation::specifiedTimingChanged()
    130 {
    131     if (player()) {
    132         // FIXME: Needs to consider groups when added.
    133         ASSERT(player()->source() == this);
    134         player()->setCompositorPending(true);
    135     }
    136 }
    137 
    138 static AnimationStack& ensureAnimationStack(Element* element)
    139 {
    140     return element->ensureActiveAnimations().defaultStack();
    141 }
    142 
    143 void Animation::applyEffects()
    144 {
    145     ASSERT(isInEffect());
    146     ASSERT(player());
    147     if (!m_target || !m_effect)
    148         return;
    149 
    150     double iteration = currentIteration();
    151     ASSERT(iteration >= 0);
    152     // FIXME: Handle iteration values which overflow int.
    153     OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > interpolations = m_effect->sample(static_cast<int>(iteration), timeFraction(), iterationDuration());
    154     if (m_sampledEffect) {
    155         m_sampledEffect->setInterpolations(interpolations.release());
    156     } else if (!interpolations->isEmpty()) {
    157         OwnPtrWillBeRawPtr<SampledEffect> sampledEffect = SampledEffect::create(this, interpolations.release());
    158         m_sampledEffect = sampledEffect.get();
    159         ensureAnimationStack(m_target).add(sampledEffect.release());
    160     } else {
    161         return;
    162     }
    163 
    164     m_target->setNeedsAnimationStyleRecalc();
    165 }
    166 
    167 void Animation::clearEffects()
    168 {
    169     ASSERT(player());
    170     ASSERT(m_sampledEffect);
    171 
    172     m_sampledEffect->clear();
    173     m_sampledEffect = nullptr;
    174     cancelAnimationOnCompositor();
    175     m_target->setNeedsAnimationStyleRecalc();
    176     invalidate();
    177 }
    178 
    179 void Animation::updateChildrenAndEffects() const
    180 {
    181     if (!m_effect)
    182         return;
    183     if (isInEffect())
    184         const_cast<Animation*>(this)->applyEffects();
    185     else if (m_sampledEffect)
    186         const_cast<Animation*>(this)->clearEffects();
    187 }
    188 
    189 double Animation::calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const
    190 {
    191     const double start = startTimeInternal() + specifiedTiming().startDelay;
    192     const double end = start + activeDurationInternal();
    193 
    194     switch (phase()) {
    195     case PhaseNone:
    196         return std::numeric_limits<double>::infinity();
    197     case PhaseBefore:
    198         ASSERT(start >= localTime);
    199         return forwards
    200             ? start - localTime
    201             : std::numeric_limits<double>::infinity();
    202     case PhaseActive:
    203         if (forwards && hasActiveAnimationsOnCompositor()) {
    204             // Need service to apply fill / fire events.
    205             const double timeToEnd = end - localTime;
    206             if (hasEvents()) {
    207                 return std::min(timeToEnd, timeToNextIteration);
    208             } else {
    209                 return timeToEnd;
    210             }
    211         }
    212         return 0;
    213     case PhaseAfter:
    214         ASSERT(localTime >= end);
    215         // If this Animation is still in effect then it will need to update
    216         // when its parent goes out of effect. We have no way of knowing when
    217         // that will be, however, so the parent will need to supply it.
    218         return forwards
    219             ? std::numeric_limits<double>::infinity()
    220             : localTime - end;
    221     default:
    222         ASSERT_NOT_REACHED();
    223         return std::numeric_limits<double>::infinity();
    224     }
    225 }
    226 
    227 void Animation::notifySampledEffectRemovedFromAnimationStack()
    228 {
    229     ASSERT(m_sampledEffect);
    230     m_sampledEffect = nullptr;
    231 }
    232 
    233 #if !ENABLE(OILPAN)
    234 void Animation::notifyElementDestroyed()
    235 {
    236     // If our player is kept alive just by the sampledEffect, we might get our
    237     // destructor called when we call SampledEffect::clear(), so we need to
    238     // clear m_sampledEffect first.
    239     m_target = nullptr;
    240     clearEventDelegate();
    241     SampledEffect* sampledEffect = m_sampledEffect;
    242     m_sampledEffect = nullptr;
    243     if (sampledEffect)
    244         sampledEffect->clear();
    245 }
    246 #endif
    247 
    248 bool Animation::isCandidateForAnimationOnCompositor(double playerPlaybackRate) const
    249 {
    250     if (!effect() || !m_target)
    251         return false;
    252     return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *effect(), playerPlaybackRate);
    253 }
    254 
    255 bool Animation::maybeStartAnimationOnCompositor(double startTime, double currentTime)
    256 {
    257     return maybeStartAnimationOnCompositor(startTime, currentTime, 1);
    258 }
    259 
    260 bool Animation::maybeStartAnimationOnCompositor(double startTime, double currentTime, double playerPlaybackRate)
    261 {
    262     ASSERT(!hasActiveAnimationsOnCompositor());
    263     if (!isCandidateForAnimationOnCompositor(playerPlaybackRate))
    264         return false;
    265     if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target))
    266         return false;
    267     if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target, startTime, currentTime, specifiedTiming(), *effect(), m_compositorAnimationIds, playerPlaybackRate))
    268         return false;
    269     ASSERT(!m_compositorAnimationIds.isEmpty());
    270     return true;
    271 }
    272 
    273 bool Animation::hasActiveAnimationsOnCompositor() const
    274 {
    275     return !m_compositorAnimationIds.isEmpty();
    276 }
    277 
    278 bool Animation::hasActiveAnimationsOnCompositor(CSSPropertyID property) const
    279 {
    280     return hasActiveAnimationsOnCompositor() && affects(property);
    281 }
    282 
    283 bool Animation::affects(CSSPropertyID property) const
    284 {
    285     return m_effect && m_effect->affects(property);
    286 }
    287 
    288 void Animation::cancelAnimationOnCompositor()
    289 {
    290     // FIXME: cancelAnimationOnCompositor is called from withins style recalc.
    291     // This queries compositingState, which is not necessarily up to date.
    292     // https://code.google.com/p/chromium/issues/detail?id=339847
    293     DisableCompositingQueryAsserts disabler;
    294     if (!hasActiveAnimationsOnCompositor())
    295         return;
    296     if (!m_target || !m_target->renderer())
    297         return;
    298     for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
    299         CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target, m_compositorAnimationIds[i]);
    300     m_compositorAnimationIds.clear();
    301     player()->setCompositorPending(true);
    302 }
    303 
    304 void Animation::pauseAnimationForTestingOnCompositor(double pauseTime)
    305 {
    306     ASSERT(hasActiveAnimationsOnCompositor());
    307     if (!m_target || !m_target->renderer())
    308         return;
    309     for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
    310         CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(*m_target, m_compositorAnimationIds[i], pauseTime);
    311 }
    312 
    313 void Animation::trace(Visitor* visitor)
    314 {
    315     visitor->trace(m_target);
    316     visitor->trace(m_effect);
    317     visitor->trace(m_sampledEffect);
    318     AnimationNode::trace(visitor);
    319 }
    320 
    321 } // namespace blink
    322