2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "core/animation/Animation.h"
34 #include "bindings/v8/Dictionary.h"
35 #include "bindings/v8/ExceptionState.h"
36 #include "core/animation/ActiveAnimations.h"
37 #include "core/animation/AnimationHelpers.h"
38 #include "core/animation/AnimationPlayer.h"
39 #include "core/animation/CompositorAnimations.h"
40 #include "core/animation/DocumentTimeline.h"
41 #include "core/animation/Interpolation.h"
42 #include "core/animation/KeyframeEffectModel.h"
43 #include "core/dom/Element.h"
44 #include "core/frame/UseCounter.h"
45 #include "core/rendering/RenderLayer.h"
49 PassRefPtr<Animation> Animation::create(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
51 return adoptRef(new Animation(target, effect, timing, priority, eventDelegate));
54 PassRefPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Dictionary& timingInputDictionary)
56 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
57 return create(element, effect, TimingInput::convert(timingInputDictionary));
59 PassRefPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect, double duration)
61 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
62 return create(element, effect, TimingInput::convert(duration));
64 PassRefPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr<AnimationEffect> effect)
66 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
67 return create(element, effect, Timing());
69 PassRefPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, const Dictionary& timingInputDictionary, ExceptionState& exceptionState)
71 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
73 UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectObjectTiming);
74 return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(timingInputDictionary));
76 PassRefPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, double duration, ExceptionState& exceptionState)
78 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
80 UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectDoubleTiming);
81 return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(duration));
83 PassRefPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
85 ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
87 UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectNoTiming);
88 return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), Timing());
91 Animation::Animation(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
92 : TimedItem(timing, eventDelegate)
96 , m_priority(priority)
99 m_target->ensureActiveAnimations().addAnimation(this);
102 Animation::~Animation()
105 m_target->activeAnimations()->notifyAnimationDestroyed(this);
108 void Animation::didAttach()
111 m_target->ensureActiveAnimations().addPlayer(player());
112 m_target->setNeedsAnimationStyleRecalc();
116 void Animation::willDetach()
119 m_target->activeAnimations()->removePlayer(player());
124 void Animation::specifiedTimingChanged()
126 cancelAnimationOnCompositor();
128 // FIXME: Needs to consider groups when added.
129 ASSERT(player()->source() == this);
130 player()->schedulePendingAnimationOnCompositor();
134 static AnimationStack& ensureAnimationStack(Element* element)
136 return element->ensureActiveAnimations().defaultStack();
139 void Animation::applyEffects()
141 ASSERT(isInEffect());
143 if (!m_target || !m_effect)
146 double iteration = currentIteration();
147 ASSERT(iteration >= 0);
148 // FIXME: Handle iteration values which overflow int.
149 OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > interpolations = m_effect->sample(static_cast<int>(iteration), timeFraction(), iterationDuration());
150 if (m_sampledEffect) {
151 m_sampledEffect->setInterpolations(interpolations.release());
152 } else if (!interpolations->isEmpty()) {
153 OwnPtr<SampledEffect> sampledEffect = SampledEffect::create(this, interpolations.release());
154 m_sampledEffect = sampledEffect.get();
155 ensureAnimationStack(m_target).add(sampledEffect.release());
160 m_target->setNeedsAnimationStyleRecalc();
163 void Animation::clearEffects()
166 ASSERT(m_sampledEffect);
168 m_sampledEffect->clear();
170 cancelAnimationOnCompositor();
171 m_target->setNeedsAnimationStyleRecalc();
175 void Animation::updateChildrenAndEffects() const
180 const_cast<Animation*>(this)->applyEffects();
181 else if (m_sampledEffect)
182 const_cast<Animation*>(this)->clearEffects();
185 double Animation::calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const
187 const double start = startTimeInternal() + specifiedTiming().startDelay;
188 const double end = start + activeDurationInternal();
192 ASSERT(start >= localTime);
195 : std::numeric_limits<double>::infinity();
197 if (forwards && hasActiveAnimationsOnCompositor()) {
198 ASSERT(specifiedTiming().playbackRate == 1);
199 // Need service to apply fill / fire events.
200 const double timeToEnd = end - localTime;
202 return std::min(timeToEnd, timeToNextIteration);
209 ASSERT(localTime >= end);
210 // If this Animation is still in effect then it will need to update
211 // when its parent goes out of effect. We have no way of knowing when
212 // that will be, however, so the parent will need to supply it.
214 ? std::numeric_limits<double>::infinity()
217 ASSERT(player() && player()->timeline() && !player()->timeline()->hasStarted());
218 return std::numeric_limits<double>::infinity();
220 ASSERT_NOT_REACHED();
221 return std::numeric_limits<double>::infinity();
225 void Animation::notifySampledEffectRemovedFromAnimationStack()
227 ASSERT(m_sampledEffect);
231 void Animation::notifyElementDestroyed()
233 // If our player is kept alive just by the sampledEffect, we might get our
234 // destructor called when we call SampledEffect::clear(), so we need to
235 // clear m_sampledEffect first.
237 clearEventDelegate();
238 SampledEffect* sampledEffect = m_sampledEffect;
241 sampledEffect->clear();
244 bool Animation::isCandidateForAnimationOnCompositor() const
246 if (!effect() || !m_target)
248 return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *effect());
251 bool Animation::maybeStartAnimationOnCompositor(double startTime)
253 ASSERT(!hasActiveAnimationsOnCompositor());
254 if (!isCandidateForAnimationOnCompositor())
256 if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target))
258 if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target, startTime, specifiedTiming(), *effect(), m_compositorAnimationIds))
260 ASSERT(!m_compositorAnimationIds.isEmpty());
264 bool Animation::hasActiveAnimationsOnCompositor() const
266 return !m_compositorAnimationIds.isEmpty();
269 bool Animation::hasActiveAnimationsOnCompositor(CSSPropertyID property) const
271 return hasActiveAnimationsOnCompositor() && affects(property);
274 bool Animation::affects(CSSPropertyID property) const
276 return m_effect && m_effect->affects(property);
279 void Animation::cancelAnimationOnCompositor()
281 // FIXME: cancelAnimationOnCompositor is called from withins style recalc.
282 // This queries compositingState, which is not necessarily up to date.
283 // https://code.google.com/p/chromium/issues/detail?id=339847
284 DisableCompositingQueryAsserts disabler;
285 if (!hasActiveAnimationsOnCompositor())
287 if (!m_target || !m_target->renderer())
289 for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
290 CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target, m_compositorAnimationIds[i]);
291 m_compositorAnimationIds.clear();
294 void Animation::pauseAnimationForTestingOnCompositor(double pauseTime)
296 ASSERT(hasActiveAnimationsOnCompositor());
297 if (!m_target || !m_target->renderer())
299 for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
300 CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(*m_target, m_compositorAnimationIds[i], pauseTime);
303 } // namespace WebCore