Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / animation / AnimationPlayer.cpp
index 4835121..545a737 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "core/animation/Animation.h"
 #include "core/animation/DocumentTimeline.h"
+#include "core/events/AnimationPlayerEvent.h"
+#include "core/frame/UseCounter.h"
 
 namespace WebCore {
 
@@ -62,7 +64,8 @@ AnimationPlayer::AnimationPlayer(DocumentTimeline& timeline, TimedItem* content)
     , m_paused(false)
     , m_held(false)
     , m_isPausedForTesting(false)
-    , m_outdated(false)
+    , m_outdated(true)
+    , m_finished(false)
 {
     if (m_content) {
         if (m_content->player())
@@ -81,7 +84,7 @@ AnimationPlayer::~AnimationPlayer()
 
 double AnimationPlayer::sourceEnd() const
 {
-    return m_content ? m_content->endTime() : 0;
+    return m_content ? m_content->endTimeInternal() : 0;
 }
 
 bool AnimationPlayer::limited(double currentTime) const
@@ -116,6 +119,7 @@ void AnimationPlayer::updateTimingState(double newCurrentTime)
     } else {
         m_holdTime = nullValue();
         m_storedTimeLag = currentTimeWithoutLag() - newCurrentTime;
+        m_finished = false;
         setOutdated();
     }
 }
@@ -135,6 +139,11 @@ void AnimationPlayer::updateCurrentTimingState()
 
 double AnimationPlayer::currentTime()
 {
+    return currentTimeInternal() * 1000;
+}
+
+double AnimationPlayer::currentTimeInternal()
+{
     updateCurrentTimingState();
     if (m_held)
         return m_holdTime;
@@ -143,29 +152,51 @@ double AnimationPlayer::currentTime()
 
 void AnimationPlayer::setCurrentTime(double newCurrentTime)
 {
+    setCurrentTimeInternal(newCurrentTime / 1000);
+}
+
+void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime)
+{
     if (!std::isfinite(newCurrentTime))
         return;
     updateTimingState(newCurrentTime);
+    cancelAnimationOnCompositor();
+    schedulePendingAnimationOnCompositor();
 }
 
-void AnimationPlayer::setStartTime(double newStartTime)
+void AnimationPlayer::setStartTimeInternal(double newStartTime, bool isUpdateFromCompositor)
 {
+    ASSERT(!isUpdateFromCompositor || !hasStartTime());
+
     if (!std::isfinite(newStartTime))
         return;
+    if (newStartTime == m_startTime)
+        return;
     updateCurrentTimingState(); // Update the value of held
+    bool hadStartTime = hasStartTime();
+    double previousCurrentTime = currentTimeInternal();
     m_startTime = newStartTime;
     m_sortInfo.m_startTime = newStartTime;
-    if (m_held)
-        return;
     updateCurrentTimingState();
-    setOutdated();
+    if (previousCurrentTime != currentTimeInternal()) {
+        setOutdated();
+    } else if (!hadStartTime && m_timeline) {
+        // Even though this player is not outdated, time to effect change is
+        // infinity until start time is set.
+        m_timeline->wake();
+    }
+    if (!isUpdateFromCompositor) {
+        cancelAnimationOnCompositor();
+        schedulePendingAnimationOnCompositor();
+    }
 }
 
 void AnimationPlayer::setSource(TimedItem* newSource)
 {
     if (m_content == newSource)
         return;
-    double storedCurrentTime = currentTime();
+    cancelAnimationOnCompositor();
+    double storedCurrentTime = currentTimeInternal();
     if (m_content)
         m_content->detach();
     m_content = newSource;
@@ -176,6 +207,7 @@ void AnimationPlayer::setSource(TimedItem* newSource)
         newSource->attach(this);
     }
     updateTimingState(storedCurrentTime);
+    schedulePendingAnimationOnCompositor();
 }
 
 void AnimationPlayer::pause()
@@ -183,8 +215,7 @@ void AnimationPlayer::pause()
     if (m_paused)
         return;
     m_paused = true;
-    updateTimingState(currentTime());
-    // FIXME: resume compositor animation rather than pull back to main-thread
+    updateTimingState(currentTimeInternal());
     cancelAnimationOnCompositor();
 }
 
@@ -193,19 +224,23 @@ void AnimationPlayer::unpause()
     if (!m_paused)
         return;
     m_paused = false;
-    updateTimingState(currentTime());
+    updateTimingState(currentTimeInternal());
+    schedulePendingAnimationOnCompositor();
 }
 
 void AnimationPlayer::play()
 {
+    cancelAnimationOnCompositor();
+    // Note, unpause schedules pending animation on compositor if necessary.
     unpause();
     if (!m_content)
         return;
-    double currentTime = this->currentTime();
+    double currentTime = this->currentTimeInternal();
     if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd()))
-        setCurrentTime(0);
+        setCurrentTimeInternal(0);
     else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd()))
-        setCurrentTime(sourceEnd());
+        setCurrentTimeInternal(sourceEnd());
+    m_finished = false;
 }
 
 void AnimationPlayer::reverse()
@@ -213,12 +248,14 @@ void AnimationPlayer::reverse()
     if (!m_playbackRate)
         return;
     if (m_content) {
-        if (m_playbackRate > 0 && currentTime() > sourceEnd())
-            setCurrentTime(sourceEnd());
-        else if (m_playbackRate < 0 && currentTime() < 0)
-            setCurrentTime(0);
+        if (m_playbackRate > 0 && currentTimeInternal() > sourceEnd())
+            setCurrentTimeInternal(sourceEnd());
+        else if (m_playbackRate < 0 && currentTimeInternal() < 0)
+            setCurrentTimeInternal(0);
     }
     setPlaybackRate(-m_playbackRate);
+    cancelAnimationOnCompositor();
+    // Note, unpause schedules pending animation on compositor if necessary.
     unpause();
 }
 
@@ -227,24 +264,43 @@ void AnimationPlayer::finish(ExceptionState& exceptionState)
     if (!m_playbackRate)
         return;
     if (m_playbackRate < 0) {
-        setCurrentTime(0);
+        setCurrentTimeInternal(0);
     } else {
         if (sourceEnd() == std::numeric_limits<double>::infinity()) {
             exceptionState.throwDOMException(InvalidStateError, "AnimationPlayer has source content whose end time is infinity.");
             return;
         }
-        setCurrentTime(sourceEnd());
+        setCurrentTimeInternal(sourceEnd());
     }
     ASSERT(finished());
+    cancelAnimationOnCompositor();
+}
+
+const AtomicString& AnimationPlayer::interfaceName() const
+{
+    return EventTargetNames::AnimationPlayer;
+}
+
+ExecutionContext* AnimationPlayer::executionContext() const
+{
+    if (m_timeline) {
+        if (Document* document = m_timeline->document())
+            return document->contextDocument().get();
+    }
+    return 0;
 }
 
 void AnimationPlayer::setPlaybackRate(double playbackRate)
 {
     if (!std::isfinite(playbackRate))
         return;
-    double storedCurrentTime = currentTime();
+    double storedCurrentTime = currentTimeInternal();
+    if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
+        m_finished = false;
     m_playbackRate = playbackRate;
     updateTimingState(storedCurrentTime);
+    cancelAnimationOnCompositor();
+    schedulePendingAnimationOnCompositor();
 }
 
 void AnimationPlayer::setOutdated()
@@ -254,21 +310,36 @@ void AnimationPlayer::setOutdated()
         m_timeline->setOutdatedAnimationPlayer(this);
 }
 
+bool AnimationPlayer::canStartAnimationOnCompositor()
+{
+    // FIXME: Need compositor support for playback rate != 1.
+    if (playbackRate() != 1)
+        return false;
+
+    return m_timeline && m_content && m_content->isAnimation() && !m_held;
+}
+
 bool AnimationPlayer::maybeStartAnimationOnCompositor()
 {
-    // FIXME: Support starting compositor animations that have a fixed
-    // start time.
-    ASSERT(!hasStartTime());
-    if (!m_content || !m_content->isAnimation() || paused())
+    if (!canStartAnimationOnCompositor())
         return false;
 
-    return toAnimation(m_content.get())->maybeStartAnimationOnCompositor();
+    return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(timeline()->zeroTime() + startTimeInternal() + timeLagInternal());
+}
+
+void AnimationPlayer::schedulePendingAnimationOnCompositor()
+{
+    ASSERT(!hasActiveAnimationsOnCompositor());
+
+    if (canStartAnimationOnCompositor())
+        timeline()->document()->compositorPendingAnimations().add(this);
 }
 
 bool AnimationPlayer::hasActiveAnimationsOnCompositor()
 {
     if (!m_content || !m_content->isAnimation())
         return false;
+
     return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
 }
 
@@ -278,38 +349,49 @@ void AnimationPlayer::cancelAnimationOnCompositor()
         toAnimation(m_content.get())->cancelAnimationOnCompositor();
 }
 
-bool AnimationPlayer::update()
+bool AnimationPlayer::update(TimingUpdateReason reason)
 {
     m_outdated = false;
 
-    if (!m_timeline || !m_content)
+    if (!m_timeline)
         return false;
 
-    double inheritedTime = isNull(m_timeline->currentTime()) ? nullValue() : currentTime();
-    m_content->updateInheritedTime(inheritedTime);
+    if (m_content) {
+        double inheritedTime = isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
+        m_content->updateInheritedTime(inheritedTime, reason);
+    }
 
+    if (finished() && !m_finished) {
+        if (reason == TimingUpdateForAnimationFrame && hasStartTime()) {
+            const AtomicString& eventType = EventTypeNames::finish;
+            if (executionContext() && hasEventListeners(eventType)) {
+                RefPtrWillBeRawPtr<AnimationPlayerEvent> event = AnimationPlayerEvent::create(eventType, currentTime(), timeline()->currentTime());
+                event->setTarget(this);
+                event->setCurrentTarget(this);
+                m_timeline->document()->enqueueAnimationFrameEvent(event.release());
+            }
+            m_finished = true;
+        }
+    }
     ASSERT(!m_outdated);
-    return m_content->isCurrent() || m_content->isInEffect();
+    return !m_finished || !finished();
 }
 
 double AnimationPlayer::timeToEffectChange()
 {
     ASSERT(!m_outdated);
-    if (!m_content || !m_playbackRate)
+    if (m_held || !hasStartTime())
         return std::numeric_limits<double>::infinity();
+    if (!m_content)
+        return -currentTimeInternal() / m_playbackRate;
     if (m_playbackRate > 0)
         return m_content->timeToForwardsEffectChange() / m_playbackRate;
-    return m_content->timeToReverseEffectChange() / std::abs(m_playbackRate);
+    return m_content->timeToReverseEffectChange() / -m_playbackRate;
 }
 
 void AnimationPlayer::cancel()
 {
-    if (!m_content)
-        return;
-
-    ASSERT(m_content->player() == this);
-    m_content->detach();
-    m_content = nullptr;
+    setSource(0);
 }
 
 bool AnimationPlayer::SortInfo::operator<(const SortInfo& other) const
@@ -322,12 +404,25 @@ bool AnimationPlayer::SortInfo::operator<(const SortInfo& other) const
     return m_sequenceNumber < other.m_sequenceNumber;
 }
 
+bool AnimationPlayer::canFree() const
+{
+    ASSERT(m_content);
+    return hasOneRef() && m_content->isAnimation() && m_content->hasOneRef();
+}
+
+bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+    if (eventType == EventTypeNames::finish)
+        UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishEvent);
+    return EventTargetWithInlineData::addEventListener(eventType, listener, useCapture);
+}
+
 void AnimationPlayer::pauseForTesting(double pauseTime)
 {
     RELEASE_ASSERT(!paused());
     updateTimingState(pauseTime);
     if (!m_isPausedForTesting && hasActiveAnimationsOnCompositor())
-        toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTime());
+        toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
     m_isPausedForTesting = true;
     pause();
 }