Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / animation / Animation.cpp
index 8802516..fd325c1 100644 (file)
@@ -46,7 +46,7 @@
 
 namespace WebCore {
 
-PassRefPtr<Animation> Animation::create(PassRefPtr<Element> target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
+PassRefPtr<Animation> Animation::create(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
 {
     return adoptRef(new Animation(target, effect, timing, priority, eventDelegate));
 }
@@ -69,85 +69,105 @@ PassRefPtr<Animation> Animation::create(Element* element, PassRefPtrWillBeRawPtr
 PassRefPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, const Dictionary& timingInputDictionary, ExceptionState& exceptionState)
 {
     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
-    UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectObjectTiming);
+    if (element)
+        UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectObjectTiming);
     return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(timingInputDictionary));
 }
 PassRefPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, double duration, ExceptionState& exceptionState)
 {
     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
-    UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectDoubleTiming);
+    if (element)
+        UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectDoubleTiming);
     return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), TimingInput::convert(duration));
 }
 PassRefPtr<Animation> Animation::create(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
 {
     ASSERT(RuntimeEnabledFeatures::webAnimationsAPIEnabled());
-    UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectNoTiming);
+    if (element)
+        UseCounter::count(element->document(), UseCounter::AnimationConstructorKeyframeListEffectNoTiming);
     return create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), Timing());
 }
 
-Animation::Animation(PassRefPtr<Element> target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
+Animation::Animation(Element* target, PassRefPtrWillBeRawPtr<AnimationEffect> effect, const Timing& timing, Priority priority, PassOwnPtr<EventDelegate> eventDelegate)
     : TimedItem(timing, eventDelegate)
     , m_target(target)
     , m_effect(effect)
-    , m_activeInAnimationStack(false)
+    , m_sampledEffect(0)
     , m_priority(priority)
 {
+    if (m_target)
+        m_target->ensureActiveAnimations().addAnimation(this);
 }
 
-void Animation::didAttach()
+Animation::~Animation()
 {
     if (m_target)
-        m_target->ensureActiveAnimations().players().add(player());
+        m_target->activeAnimations()->notifyAnimationDestroyed(this);
+}
+
+void Animation::didAttach()
+{
+    if (m_target) {
+        m_target->ensureActiveAnimations().addPlayer(player());
+        m_target->setNeedsAnimationStyleRecalc();
+    }
 }
 
 void Animation::willDetach()
 {
     if (m_target)
-        m_target->activeAnimations()->players().remove(player());
-    if (m_activeInAnimationStack)
+        m_target->activeAnimations()->removePlayer(player());
+    if (m_sampledEffect)
         clearEffects();
 }
 
+void Animation::specifiedTimingChanged()
+{
+    cancelAnimationOnCompositor();
+    if (player()) {
+        // FIXME: Needs to consider groups when added.
+        ASSERT(player()->source() == this);
+        player()->schedulePendingAnimationOnCompositor();
+    }
+}
+
 static AnimationStack& ensureAnimationStack(Element* element)
 {
     return element->ensureActiveAnimations().defaultStack();
 }
 
-void Animation::applyEffects(bool previouslyInEffect)
+void Animation::applyEffects()
 {
     ASSERT(isInEffect());
+    ASSERT(player());
     if (!m_target || !m_effect)
         return;
 
-    if (player() && !previouslyInEffect) {
-        ensureAnimationStack(m_target.get()).add(this);
-        m_activeInAnimationStack = true;
-    }
-
     double iteration = currentIteration();
     ASSERT(iteration >= 0);
     // FIXME: Handle iteration values which overflow int.
-    m_activeInterpolations = m_effect->sample(static_cast<int>(iteration), timeFraction(), duration());
-    if (player())
-        m_target->setNeedsAnimationStyleRecalc();
+    OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation> > > interpolations = m_effect->sample(static_cast<int>(iteration), timeFraction(), iterationDuration());
+    if (m_sampledEffect) {
+        m_sampledEffect->setInterpolations(interpolations.release());
+    } else if (!interpolations->isEmpty()) {
+        OwnPtr<SampledEffect> sampledEffect = SampledEffect::create(this, interpolations.release());
+        m_sampledEffect = sampledEffect.get();
+        ensureAnimationStack(m_target).add(sampledEffect.release());
+    } else {
+        return;
+    }
+
+    m_target->setNeedsAnimationStyleRecalc();
 }
 
 void Animation::clearEffects()
 {
     ASSERT(player());
-    ASSERT(m_activeInAnimationStack);
-    ensureAnimationStack(m_target.get()).remove(this);
-
-    {
-        // FIXME: clearEffects is called from withins style recalc.
-        // This queries compositingState, which is not necessarily up to date.
-        // https://code.google.com/p/chromium/issues/detail?id=339847
-        DisableCompositingQueryAsserts disabler;
-        cancelAnimationOnCompositor();
-    }
+    ASSERT(m_sampledEffect);
 
-    m_activeInAnimationStack = false;
-    m_activeInterpolations.clear();
+    m_sampledEffect->clear();
+    m_sampledEffect = 0;
+    cancelAnimationOnCompositor();
     m_target->setNeedsAnimationStyleRecalc();
     invalidate();
 }
@@ -157,15 +177,15 @@ void Animation::updateChildrenAndEffects() const
     if (!m_effect)
         return;
     if (isInEffect())
-        const_cast<Animation*>(this)->applyEffects(m_activeInAnimationStack);
-    else if (m_activeInAnimationStack)
+        const_cast<Animation*>(this)->applyEffects();
+    else if (m_sampledEffect)
         const_cast<Animation*>(this)->clearEffects();
 }
 
 double Animation::calculateTimeToEffectChange(bool forwards, double localTime, double timeToNextIteration) const
 {
-    const double start = startTime() + specifiedTiming().startDelay;
-    const double end = start + activeDuration();
+    const double start = startTimeInternal() + specifiedTiming().startDelay;
+    const double end = start + activeDurationInternal();
 
     switch (phase()) {
     case PhaseBefore:
@@ -177,7 +197,12 @@ double Animation::calculateTimeToEffectChange(bool forwards, double localTime, d
         if (forwards && hasActiveAnimationsOnCompositor()) {
             ASSERT(specifiedTiming().playbackRate == 1);
             // Need service to apply fill / fire events.
-            return std::min(end - localTime, timeToNextIteration);
+            const double timeToEnd = end - localTime;
+            if (hasEvents()) {
+                return std::min(timeToEnd, timeToNextIteration);
+            } else {
+                return timeToEnd;
+            }
         }
         return 0;
     case PhaseAfter:
@@ -197,6 +222,25 @@ double Animation::calculateTimeToEffectChange(bool forwards, double localTime, d
     }
 }
 
+void Animation::notifySampledEffectRemovedFromAnimationStack()
+{
+    ASSERT(m_sampledEffect);
+    m_sampledEffect = 0;
+}
+
+void Animation::notifyElementDestroyed()
+{
+    // If our player is kept alive just by the sampledEffect, we might get our
+    // destructor called when we call SampledEffect::clear(), so we need to
+    // clear m_sampledEffect first.
+    m_target = 0;
+    clearEventDelegate();
+    SampledEffect* sampledEffect = m_sampledEffect;
+    m_sampledEffect = 0;
+    if (sampledEffect)
+        sampledEffect->clear();
+}
+
 bool Animation::isCandidateForAnimationOnCompositor() const
 {
     if (!effect() || !m_target)
@@ -204,14 +248,14 @@ bool Animation::isCandidateForAnimationOnCompositor() const
     return CompositorAnimations::instance()->isCandidateForAnimationOnCompositor(specifiedTiming(), *effect());
 }
 
-bool Animation::maybeStartAnimationOnCompositor()
+bool Animation::maybeStartAnimationOnCompositor(double startTime)
 {
     ASSERT(!hasActiveAnimationsOnCompositor());
     if (!isCandidateForAnimationOnCompositor())
         return false;
-    if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target.get()))
+    if (!CompositorAnimations::instance()->canStartAnimationOnCompositor(*m_target))
         return false;
-    if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target.get(), specifiedTiming(), *effect(), m_compositorAnimationIds))
+    if (!CompositorAnimations::instance()->startAnimationOnCompositor(*m_target, startTime, specifiedTiming(), *effect(), m_compositorAnimationIds))
         return false;
     ASSERT(!m_compositorAnimationIds.isEmpty());
     return true;
@@ -234,12 +278,16 @@ bool Animation::affects(CSSPropertyID property) const
 
 void Animation::cancelAnimationOnCompositor()
 {
+    // FIXME: cancelAnimationOnCompositor is called from withins style recalc.
+    // This queries compositingState, which is not necessarily up to date.
+    // https://code.google.com/p/chromium/issues/detail?id=339847
+    DisableCompositingQueryAsserts disabler;
     if (!hasActiveAnimationsOnCompositor())
         return;
     if (!m_target || !m_target->renderer())
         return;
     for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
-        CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target.get(), m_compositorAnimationIds[i]);
+        CompositorAnimations::instance()->cancelAnimationOnCompositor(*m_target, m_compositorAnimationIds[i]);
     m_compositorAnimationIds.clear();
 }
 
@@ -249,7 +297,7 @@ void Animation::pauseAnimationForTestingOnCompositor(double pauseTime)
     if (!m_target || !m_target->renderer())
         return;
     for (size_t i = 0; i < m_compositorAnimationIds.size(); ++i)
-        CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(*m_target.get(), m_compositorAnimationIds[i], pauseTime);
+        CompositorAnimations::instance()->pauseAnimationForTestingOnCompositor(*m_target, m_compositorAnimationIds[i], pauseTime);
 }
 
 } // namespace WebCore