[SVG] Handle endEvent for svg animations
Handled endEvent for svg animations according to http://www.w3.org/TR/SMIL3/smil-timing.html#q135
R=pdr@chromium.org, schenney@chromium.org, dschulze@chromium.org, fmalita@chromium.org
BUG=269648
Review URL: https://chromiumcodereview.appspot.com/22385010
git-svn-id: svn://svn.chromium.org/blink/trunk@157012 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/svg/animations/end-event-expected.svg b/LayoutTests/svg/animations/end-event-expected.svg
new file mode 100755
index 0000000..8830766
--- /dev/null
+++ b/LayoutTests/svg/animations/end-event-expected.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <rect x="100" y="0" width="50" height="50" fill="green" />
+</svg>
diff --git a/LayoutTests/svg/animations/end-event.svg b/LayoutTests/svg/animations/end-event.svg
new file mode 100755
index 0000000..5f322f3
--- /dev/null
+++ b/LayoutTests/svg/animations/end-event.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg onload="loaded()" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <rect x="0" y="0" width="50" height="50" fill="green">
+ <animate id="anim" attributeName="visibility" to="visible" begin="0s" end="2s" />
+ <set attributeName="x" to="100" begin="anim.endEvent" />
+ </rect>
+ <script>
+ if (window.testRunner)
+ testRunner.waitUntilDone();
+
+ function loaded() {
+ document.documentElement.setCurrentTime(2);
+
+ if (window.testRunner)
+ setTimeout(function() {testRunner.notifyDone();}, 100);
+ }
+ </script>
+</svg>
diff --git a/Source/core/svg/animation/SMILTimeContainer.cpp b/Source/core/svg/animation/SMILTimeContainer.cpp
index 5b6ccc9..2a5e8d8 100644
--- a/Source/core/svg/animation/SMILTimeContainer.cpp
+++ b/Source/core/svg/animation/SMILTimeContainer.cpp
@@ -273,6 +273,16 @@
GroupedAnimationsMap::iterator end = m_scheduledAnimations.end();
for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) {
AnimationsVector* scheduled = it->value.get();
+ unsigned size = scheduled->size();
+ for (unsigned n = 0; n < size; n++) {
+ SVGSMILElement* animation = scheduled->at(n);
+ if (!animation->hasConditionsConnected())
+ animation->connectConditions();
+ }
+ }
+
+ for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) {
+ AnimationsVector* scheduled = it->value.get();
// Sort according to priority. Elements with later begin time have higher priority.
// In case of a tie, document order decides.
diff --git a/Source/core/svg/animation/SVGSMILElement.cpp b/Source/core/svg/animation/SVGSMILElement.cpp
index c229f95..c79205e 100644
--- a/Source/core/svg/animation/SVGSMILElement.cpp
+++ b/Source/core/svg/animation/SVGSMILElement.cpp
@@ -31,6 +31,7 @@
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "core/dom/Document.h"
#include "core/dom/EventListener.h"
+#include "core/dom/EventSender.h"
#include "core/platform/FloatConversion.h"
#include "core/svg/SVGDocumentExtensions.h"
#include "core/svg/SVGSVGElement.h"
@@ -44,6 +45,12 @@
namespace WebCore {
+static SMILEventSender& smilEndEventSender()
+{
+ DEFINE_STATIC_LOCAL(SMILEventSender, sender, ("endEvent"));
+ return sender;
+}
+
// This is used for duration type time values that can't be negative.
static const double invalidCachedTime = -1.;
@@ -133,6 +140,7 @@
SVGSMILElement::~SVGSMILElement()
{
clearResourceReferences();
+ smilEndEventSender().cancelEvent(this);
disconnectConditions();
if (m_timeContainer && m_targetElement && hasValidAttributeName())
m_timeContainer->unschedule(this, m_targetElement, m_attributeName);
@@ -1051,9 +1059,6 @@
ASSERT(m_timeContainer);
ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
- if (!m_conditionsConnected)
- connectConditions();
-
if (!m_intervalBegin.isFinite()) {
ASSERT(m_activeState == Inactive);
m_nextProgressTime = SMILTime::unresolved();
@@ -1110,11 +1115,18 @@
}
if (oldActiveState == Active && m_activeState != Active) {
+ smilEndEventSender().dispatchEventSoon(this);
endedActiveInterval();
if (m_activeState != Frozen && this == resultElement)
clearAnimatedType(m_targetElement);
}
+ // Triggering all the pending events if the animation timeline is changed.
+ if (seekToTime) {
+ if (m_activeState == Inactive || m_activeState == Frozen)
+ smilEndEventSender().dispatchEventSoon(this);
+ }
+
m_nextProgressTime = calculateNextProgressTime(elapsed);
return animationIsContributing;
}
@@ -1191,4 +1203,11 @@
clearTimesWithDynamicOrigins(m_endTimes);
}
+void SVGSMILElement::dispatchPendingEvent(SMILEventSender* eventSender)
+{
+ ASSERT(eventSender == &smilEndEventSender());
+ const AtomicString& eventType = eventSender->eventType();
+ dispatchEvent(Event::create(eventType));
+}
+
}
diff --git a/Source/core/svg/animation/SVGSMILElement.h b/Source/core/svg/animation/SVGSMILElement.h
index 5d8c403..c6cbd1a 100644
--- a/Source/core/svg/animation/SVGSMILElement.h
+++ b/Source/core/svg/animation/SVGSMILElement.h
@@ -34,6 +34,10 @@
class ConditionEventListener;
class SMILTimeContainer;
+class SVGSMILElement;
+
+template<typename T> class EventSender;
+typedef EventSender<SVGSMILElement> SMILEventSender;
// This class implements SMIL interval timing model as needed for SVG animation.
class SVGSMILElement : public SVGElement {
@@ -109,6 +113,11 @@
virtual void clearAnimatedType(SVGElement* targetElement) = 0;
virtual void applyResultsToTarget() = 0;
+ void connectConditions();
+ bool hasConditionsConnected() const { return m_conditionsConnected; }
+
+ void dispatchPendingEvent(SMILEventSender*);
+
protected:
void addBeginTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
void addEndTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
@@ -167,7 +176,6 @@
void parseBeginOrEnd(const String&, BeginOrEnd beginOrEnd);
Element* eventBaseFor(const Condition&);
- void connectConditions();
void disconnectConditions();
// Event base timing