Index: Source/core/svg/animation/SMILTimeContainer.cpp |
diff --git a/Source/core/svg/animation/SMILTimeContainer.cpp b/Source/core/svg/animation/SMILTimeContainer.cpp |
index c41555d4d18203e592dc1c81d5ce2f275f8c3608..936d795478328df13d2e1e0fdf8f7ef5b7692864 100644 |
--- a/Source/core/svg/animation/SMILTimeContainer.cpp |
+++ b/Source/core/svg/animation/SMILTimeContainer.cpp |
@@ -27,6 +27,7 @@ |
#include "core/svg/animation/SMILTimeContainer.h" |
#include "core/dom/ElementTraversal.h" |
+#include "core/frame/FrameView.h" |
#include "core/svg/SVGSVGElement.h" |
#include "core/svg/animation/SVGSMILElement.h" |
#include "wtf/CurrentTime.h" |
@@ -35,7 +36,8 @@ using namespace std; |
namespace WebCore { |
-static const double animationFrameDelay = 0.025; |
+// Blatantly copied from core/animation/DocumentTimeline.cpp. |
+static const double minimumDelay = 0.04; |
pdr.
2014/03/03 17:47:33
Can you use DocumentTimeline::s_minimumDelay direc
dstockwell
2014/03/04 01:19:04
I'm OK with this duplication for now, but this log
fs
2014/03/04 10:28:19
I suppose we can trade this two line hack for a on
|
SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) |
: m_beginTime(0) |
@@ -44,7 +46,9 @@ SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) |
, m_accumulatedActiveTime(0) |
, m_presetStartTime(0) |
, m_documentOrderIndexesDirty(false) |
- , m_timer(this, &SMILTimeContainer::timerFired) |
+ , m_framePending(false) |
+ , m_clockFrozen(false) |
pdr.
2014/03/03 17:47:33
I'm wary of adding more clock-related state to thi
fs
2014/03/04 10:28:19
I will try to formalize this somewhat - probably b
|
+ , m_wakeupTimer(this, &SMILTimeContainer::wakeupTimerFired) |
, m_ownerSVGElement(owner) |
#ifndef NDEBUG |
, m_preventScheduledAnimationsChanges(false) |
@@ -55,7 +59,7 @@ SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) |
SMILTimeContainer::~SMILTimeContainer() |
{ |
cancelAnimationFrame(); |
- ASSERT(!m_timer.isActive()); |
+ ASSERT(!m_wakeupTimer.isActive()); |
#ifndef NDEBUG |
ASSERT(!m_preventScheduledAnimationsChanges); |
#endif |
@@ -99,6 +103,11 @@ void SMILTimeContainer::unschedule(SVGSMILElement* animation, SVGElement* target |
scheduled->remove(idx); |
} |
+bool SMILTimeContainer::hasAnimations() const |
+{ |
+ return !m_scheduledAnimations.isEmpty(); |
+} |
+ |
void SMILTimeContainer::notifyIntervalsChanged() |
{ |
// Schedule updateAnimations() to be called asynchronously so multiple intervals |
@@ -108,7 +117,7 @@ void SMILTimeContainer::notifyIntervalsChanged() |
SMILTime SMILTimeContainer::elapsed() const |
{ |
- if (!m_beginTime) |
+ if (!m_beginTime || m_clockFrozen) |
return 0; |
if (isPaused()) |
@@ -135,12 +144,15 @@ void SMILTimeContainer::begin() |
// If 'm_presetStartTime' is set, the timeline was modified via setElapsed() before the document began. |
// In this case pass on 'seekToTime=true' to updateAnimations(). |
m_beginTime = now - m_presetStartTime; |
- updateAnimations(SMILTime(m_presetStartTime), m_presetStartTime ? true : false); |
+ bool hadPresetStartTime = m_presetStartTime ? true : false; |
+ updateAnimations(SMILTime(m_presetStartTime), hadPresetStartTime); |
m_presetStartTime = 0; |
if (m_pauseTime) { |
m_pauseTime = now; |
cancelAnimationFrame(); |
+ } else { |
+ m_clockFrozen = !hadPresetStartTime; |
} |
} |
@@ -154,6 +166,7 @@ void SMILTimeContainer::pause() |
cancelAnimationFrame(); |
} |
m_resumeTime = 0; |
+ m_clockFrozen = false; |
} |
void SMILTimeContainer::resume() |
@@ -163,6 +176,7 @@ void SMILTimeContainer::resume() |
m_pauseTime = 0; |
scheduleAnimationFrame(); |
+ m_clockFrozen = false; |
} |
void SMILTimeContainer::setElapsed(SMILTime time) |
@@ -173,6 +187,8 @@ void SMILTimeContainer::setElapsed(SMILTime time) |
return; |
} |
+ m_clockFrozen = false; |
+ |
if (m_beginTime) |
pdr.
2014/03/03 17:47:33
How did this if statement get here? :P
fs
2014/03/04 10:28:19
Magic? =P
Maybe it should've been some other cond
|
cancelAnimationFrame(); |
@@ -216,8 +232,11 @@ void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) |
if (!fireTime.isFinite()) |
return; |
- SMILTime delay = max(fireTime - elapsed(), SMILTime(animationFrameDelay)); |
- m_timer.startOneShot(delay.value()); |
+ SMILTime delay = fireTime - elapsed(); |
+ if (delay.value() < minimumDelay) |
+ serviceOnNextFrame(); |
+ else |
+ m_wakeupTimer.startOneShot(delay.value() - minimumDelay); |
} |
void SMILTimeContainer::scheduleAnimationFrame() |
@@ -225,18 +244,21 @@ void SMILTimeContainer::scheduleAnimationFrame() |
if (!isTimelineRunning()) |
return; |
- m_timer.startOneShot(0); |
+ // Could also schedule a wakeup at +0 seconds, but that could still |
+ // potentially race with the servicing of the next frame. |
+ serviceOnNextFrame(); |
} |
void SMILTimeContainer::cancelAnimationFrame() |
{ |
- m_timer.stop(); |
+ m_framePending = false; |
+ m_wakeupTimer.stop(); |
} |
-void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) |
+void SMILTimeContainer::wakeupTimerFired(Timer<SMILTimeContainer>*) |
{ |
ASSERT(isTimelineRunning()); |
- updateAnimations(elapsed()); |
+ serviceOnNextFrame(); |
} |
void SMILTimeContainer::updateDocumentOrderIndexes() |
@@ -266,6 +288,30 @@ struct PriorityCompare { |
SMILTime m_elapsed; |
}; |
+Document& SMILTimeContainer::document() const |
+{ |
+ ASSERT(m_ownerSVGElement); |
+ return m_ownerSVGElement->document(); |
+} |
+ |
+void SMILTimeContainer::serviceOnNextFrame() |
+{ |
+ if (document().view()) { |
+ document().view()->scheduleAnimation(); |
+ m_framePending = true; |
+ } |
+} |
+ |
+void SMILTimeContainer::serviceAnimations(double monotonicAnimationStartTime) |
dstockwell
2014/03/04 01:19:04
This patch just moves updates to be driven by the
fs
2014/03/04 10:28:19
Yes, I plan to that in follow up CLs. Had original
|
+{ |
+ if (!m_framePending) |
+ return; |
+ |
+ m_framePending = false; |
+ updateAnimations(elapsed()); |
+ m_clockFrozen = false; |
+} |
+ |
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) |
{ |
SMILTime earliestFireTime = SMILTime::unresolved(); |