Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / animation / SVGSMILElement.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "core/svg/animation/SVGSMILElement.h"
28
29 #include "SVGNames.h"
30 #include "XLinkNames.h"
31 #include "bindings/v8/ExceptionStatePlaceholder.h"
32 #include "bindings/v8/ScriptEventListener.h"
33 #include "core/dom/Document.h"
34 #include "core/events/EventListener.h"
35 #include "core/events/EventSender.h"
36 #include "core/svg/SVGDocumentExtensions.h"
37 #include "core/svg/SVGElementInstance.h"
38 #include "core/svg/SVGSVGElement.h"
39 #include "core/svg/SVGURIReference.h"
40 #include "core/svg/animation/SMILTimeContainer.h"
41 #include "platform/FloatConversion.h"
42 #include "wtf/MathExtras.h"
43 #include "wtf/StdLibExtras.h"
44 #include "wtf/Vector.h"
45
46 using namespace std;
47
48 namespace WebCore {
49
50 class RepeatEvent FINAL : public Event {
51 public:
52     static PassRefPtrWillBeRawPtr<RepeatEvent> create(const AtomicString& type, int repeat)
53     {
54         return adoptRefWillBeNoop(new RepeatEvent(type, false, false, repeat));
55     }
56
57     virtual ~RepeatEvent() { }
58
59     int repeat() const { return m_repeat; }
60
61     virtual void trace(Visitor* visitor) OVERRIDE
62     {
63         Event::trace(visitor);
64     }
65
66 protected:
67     RepeatEvent(const AtomicString& type, bool canBubble, bool cancelable, int repeat = -1)
68         : Event(type, canBubble, cancelable)
69         , m_repeat(repeat)
70     {
71     }
72
73 private:
74     int m_repeat;
75 };
76
77 inline RepeatEvent* toRepeatEvent(Event* event)
78 {
79     ASSERT_WITH_SECURITY_IMPLICATION(!event || event->type() == "repeatn");
80     return static_cast<RepeatEvent*>(event);
81 }
82
83 static SMILEventSender& smilEndEventSender()
84 {
85     DEFINE_STATIC_LOCAL(SMILEventSender, sender, ("endEvent"));
86     return sender;
87 }
88
89 static SMILEventSender& smilBeginEventSender()
90 {
91     DEFINE_STATIC_LOCAL(SMILEventSender, sender, ("beginEvent"));
92     return sender;
93 }
94
95 static SMILEventSender& smilRepeatEventSender()
96 {
97     DEFINE_STATIC_LOCAL(SMILEventSender, sender, ("repeatEvent"));
98     return sender;
99 }
100
101 static SMILEventSender& smilRepeatNEventSender()
102 {
103     DEFINE_STATIC_LOCAL(SMILEventSender, sender, ("repeatn"));
104     return sender;
105 }
106
107 // This is used for duration type time values that can't be negative.
108 static const double invalidCachedTime = -1.;
109
110 class ConditionEventListener FINAL : public EventListener {
111 public:
112     static PassRefPtr<ConditionEventListener> create(SVGSMILElement* animation, SVGSMILElement::Condition* condition)
113     {
114         return adoptRef(new ConditionEventListener(animation, condition));
115     }
116
117     static const ConditionEventListener* cast(const EventListener* listener)
118     {
119         return listener->type() == ConditionEventListenerType
120             ? static_cast<const ConditionEventListener*>(listener)
121             : 0;
122     }
123
124     virtual bool operator==(const EventListener& other) OVERRIDE;
125
126     void disconnectAnimation()
127     {
128         m_animation = 0;
129     }
130
131 private:
132     ConditionEventListener(SVGSMILElement* animation, SVGSMILElement::Condition* condition)
133         : EventListener(ConditionEventListenerType)
134         , m_animation(animation)
135         , m_condition(condition)
136     {
137     }
138
139     virtual void handleEvent(ExecutionContext*, Event*) OVERRIDE;
140
141     SVGSMILElement* m_animation;
142     SVGSMILElement::Condition* m_condition;
143 };
144
145 bool ConditionEventListener::operator==(const EventListener& listener)
146 {
147     if (const ConditionEventListener* conditionEventListener = ConditionEventListener::cast(&listener))
148         return m_animation == conditionEventListener->m_animation && m_condition == conditionEventListener->m_condition;
149     return false;
150 }
151
152 void ConditionEventListener::handleEvent(ExecutionContext*, Event* event)
153 {
154     if (!m_animation)
155         return;
156     m_animation->handleConditionEvent(event, m_condition);
157 }
158
159 SVGSMILElement::Condition::Condition(Type type, BeginOrEnd beginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeat)
160     : m_type(type)
161     , m_beginOrEnd(beginOrEnd)
162     , m_baseID(baseID)
163     , m_name(name)
164     , m_offset(offset)
165     , m_repeat(repeat)
166 {
167 }
168
169 SVGSMILElement::SVGSMILElement(const QualifiedName& tagName, Document& doc)
170     : SVGElement(tagName, doc)
171     , m_attributeName(anyQName())
172     , m_targetElement(nullptr)
173     , m_syncBaseConditionsConnected(false)
174     , m_hasEndEventConditions(false)
175     , m_isWaitingForFirstInterval(true)
176     , m_intervalBegin(SMILTime::unresolved())
177     , m_intervalEnd(SMILTime::unresolved())
178     , m_previousIntervalBegin(SMILTime::unresolved())
179     , m_activeState(Inactive)
180     , m_lastPercent(0)
181     , m_lastRepeat(0)
182     , m_nextProgressTime(0)
183     , m_documentOrderIndex(0)
184     , m_cachedDur(invalidCachedTime)
185     , m_cachedRepeatDur(invalidCachedTime)
186     , m_cachedRepeatCount(invalidCachedTime)
187     , m_cachedMin(invalidCachedTime)
188     , m_cachedMax(invalidCachedTime)
189 {
190     resolveFirstInterval();
191 }
192
193 SVGSMILElement::~SVGSMILElement()
194 {
195 #if !ENABLE(OILPAN)
196     clearResourceAndEventBaseReferences();
197 #endif
198     smilEndEventSender().cancelEvent(this);
199     smilBeginEventSender().cancelEvent(this);
200     smilRepeatEventSender().cancelEvent(this);
201     smilRepeatNEventSender().cancelEvent(this);
202 #if !ENABLE(OILPAN)
203     clearConditions();
204     if (m_timeContainer && m_targetElement && hasValidAttributeName())
205         m_timeContainer->unschedule(this, m_targetElement, m_attributeName);
206 #endif
207 }
208
209 void SVGSMILElement::clearResourceAndEventBaseReferences()
210 {
211     document().accessSVGExtensions().removeAllTargetReferencesForElement(this);
212 }
213
214 void SVGSMILElement::clearConditions()
215 {
216     disconnectSyncBaseConditions();
217     disconnectEventBaseConditions();
218     m_conditions.clear();
219 }
220
221 void SVGSMILElement::buildPendingResource()
222 {
223     clearResourceAndEventBaseReferences();
224
225     if (!inDocument()) {
226         // Reset the target element if we are no longer in the document.
227         setTargetElement(0);
228         return;
229     }
230
231     AtomicString id;
232     AtomicString href = getAttribute(XLinkNames::hrefAttr);
233     Element* target;
234     if (href.isEmpty())
235         target = parentNode() && parentNode()->isElementNode() ? toElement(parentNode()) : 0;
236     else
237         target = SVGURIReference::targetElementFromIRIString(href, treeScope(), &id);
238     SVGElement* svgTarget = target && target->isSVGElement() ? toSVGElement(target) : 0;
239
240     if (svgTarget && !svgTarget->inDocument())
241         svgTarget = 0;
242
243     if (svgTarget != targetElement())
244         setTargetElement(svgTarget);
245
246     if (!svgTarget) {
247         // Do not register as pending if we are already pending this resource.
248         if (document().accessSVGExtensions().isElementPendingResource(this, id))
249             return;
250
251         if (!id.isEmpty()) {
252             document().accessSVGExtensions().addPendingResource(id, this);
253             ASSERT(hasPendingResources());
254         }
255     } else {
256         // Register us with the target in the dependencies map. Any change of hrefElement
257         // that leads to relayout/repainting now informs us, so we can react to it.
258         document().accessSVGExtensions().addElementReferencingTarget(this, svgTarget);
259     }
260     connectEventBaseConditions();
261 }
262
263 static inline QualifiedName constructQualifiedName(const SVGElement* svgElement, const AtomicString& attributeName)
264 {
265     ASSERT(svgElement);
266     if (attributeName.isEmpty())
267         return anyQName();
268     if (!attributeName.contains(':'))
269         return QualifiedName(nullAtom, attributeName, nullAtom);
270
271     AtomicString prefix;
272     AtomicString localName;
273     if (!Document::parseQualifiedName(attributeName, prefix, localName, IGNORE_EXCEPTION))
274         return anyQName();
275
276     const AtomicString& namespaceURI = svgElement->lookupNamespaceURI(prefix);
277     if (namespaceURI.isEmpty())
278         return anyQName();
279
280     return QualifiedName(nullAtom, localName, namespaceURI);
281 }
282
283 static inline void clearTimesWithDynamicOrigins(Vector<SMILTimeWithOrigin>& timeList)
284 {
285     for (int i = timeList.size() - 1; i >= 0; --i) {
286         if (timeList[i].originIsScript())
287             timeList.remove(i);
288     }
289 }
290
291 void SVGSMILElement::reset()
292 {
293     clearAnimatedType(m_targetElement);
294
295     m_activeState = Inactive;
296     m_isWaitingForFirstInterval = true;
297     m_intervalBegin = SMILTime::unresolved();
298     m_intervalEnd = SMILTime::unresolved();
299     m_previousIntervalBegin = SMILTime::unresolved();
300     m_lastPercent = 0;
301     m_lastRepeat = 0;
302     m_nextProgressTime = 0;
303     resolveFirstInterval();
304 }
305
306 Node::InsertionNotificationRequest SVGSMILElement::insertedInto(ContainerNode* rootParent)
307 {
308     SVGElement::insertedInto(rootParent);
309
310     if (!rootParent->inDocument())
311         return InsertionDone;
312
313     setAttributeName(constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr)));
314     SVGSVGElement* owner = ownerSVGElement();
315     if (!owner)
316         return InsertionDone;
317
318     m_timeContainer = owner->timeContainer();
319     ASSERT(m_timeContainer);
320     m_timeContainer->setDocumentOrderIndexesDirty();
321
322     // "If no attribute is present, the default begin value (an offset-value of 0) must be evaluated."
323     if (!fastHasAttribute(SVGNames::beginAttr))
324         m_beginTimes.append(SMILTimeWithOrigin());
325
326     if (m_isWaitingForFirstInterval)
327         resolveFirstInterval();
328
329     if (m_timeContainer)
330         m_timeContainer->notifyIntervalsChanged();
331
332     buildPendingResource();
333
334     return InsertionDone;
335 }
336
337 void SVGSMILElement::removedFrom(ContainerNode* rootParent)
338 {
339     if (rootParent->inDocument()) {
340         clearResourceAndEventBaseReferences();
341         clearConditions();
342         setTargetElement(0);
343         setAttributeName(anyQName());
344         animationAttributeChanged();
345         m_timeContainer = nullptr;
346     }
347
348     SVGElement::removedFrom(rootParent);
349 }
350
351 bool SVGSMILElement::hasValidAttributeName()
352 {
353     return attributeName() != anyQName();
354 }
355
356 SMILTime SVGSMILElement::parseOffsetValue(const String& data)
357 {
358     bool ok;
359     double result = 0;
360     String parse = data.stripWhiteSpace();
361     if (parse.endsWith('h'))
362         result = parse.left(parse.length() - 1).toDouble(&ok) * 60 * 60;
363     else if (parse.endsWith("min"))
364         result = parse.left(parse.length() - 3).toDouble(&ok) * 60;
365     else if (parse.endsWith("ms"))
366         result = parse.left(parse.length() - 2).toDouble(&ok) / 1000;
367     else if (parse.endsWith('s'))
368         result = parse.left(parse.length() - 1).toDouble(&ok);
369     else
370         result = parse.toDouble(&ok);
371     if (!ok)
372         return SMILTime::unresolved();
373     return result;
374 }
375
376 SMILTime SVGSMILElement::parseClockValue(const String& data)
377 {
378     if (data.isNull())
379         return SMILTime::unresolved();
380
381     String parse = data.stripWhiteSpace();
382
383     DEFINE_STATIC_LOCAL(const AtomicString, indefiniteValue, ("indefinite", AtomicString::ConstructFromLiteral));
384     if (parse == indefiniteValue)
385         return SMILTime::indefinite();
386
387     double result = 0;
388     bool ok;
389     size_t doublePointOne = parse.find(':');
390     size_t doublePointTwo = parse.find(':', doublePointOne + 1);
391     if (doublePointOne == 2 && doublePointTwo == 5 && parse.length() >= 8) {
392         result += parse.substring(0, 2).toUIntStrict(&ok) * 60 * 60;
393         if (!ok)
394             return SMILTime::unresolved();
395         result += parse.substring(3, 2).toUIntStrict(&ok) * 60;
396         if (!ok)
397             return SMILTime::unresolved();
398         result += parse.substring(6).toDouble(&ok);
399     } else if (doublePointOne == 2 && doublePointTwo == kNotFound && parse.length() >= 5) {
400         result += parse.substring(0, 2).toUIntStrict(&ok) * 60;
401         if (!ok)
402             return SMILTime::unresolved();
403         result += parse.substring(3).toDouble(&ok);
404     } else
405         return parseOffsetValue(parse);
406
407     if (!ok)
408         return SMILTime::unresolved();
409     return result;
410 }
411
412 static void sortTimeList(Vector<SMILTimeWithOrigin>& timeList)
413 {
414     std::sort(timeList.begin(), timeList.end());
415 }
416
417 bool SVGSMILElement::parseCondition(const String& value, BeginOrEnd beginOrEnd)
418 {
419     String parseString = value.stripWhiteSpace();
420
421     double sign = 1.;
422     bool ok;
423     size_t pos = parseString.find('+');
424     if (pos == kNotFound) {
425         pos = parseString.find('-');
426         if (pos != kNotFound)
427             sign = -1.;
428     }
429     String conditionString;
430     SMILTime offset = 0;
431     if (pos == kNotFound)
432         conditionString = parseString;
433     else {
434         conditionString = parseString.left(pos).stripWhiteSpace();
435         String offsetString = parseString.substring(pos + 1).stripWhiteSpace();
436         offset = parseOffsetValue(offsetString);
437         if (offset.isUnresolved())
438             return false;
439         offset = offset * sign;
440     }
441     if (conditionString.isEmpty())
442         return false;
443     pos = conditionString.find('.');
444
445     String baseID;
446     String nameString;
447     if (pos == kNotFound)
448         nameString = conditionString;
449     else {
450         baseID = conditionString.left(pos);
451         nameString = conditionString.substring(pos + 1);
452     }
453     if (nameString.isEmpty())
454         return false;
455
456     Condition::Type type;
457     int repeat = -1;
458     if (nameString.startsWith("repeat(") && nameString.endsWith(')')) {
459         repeat = nameString.substring(7, nameString.length() - 8).toUIntStrict(&ok);
460         if (!ok)
461             return false;
462         nameString = "repeatn";
463         type = Condition::EventBase;
464     } else if (nameString == "begin" || nameString == "end") {
465         if (baseID.isEmpty())
466             return false;
467         type = Condition::Syncbase;
468     } else if (nameString.startsWith("accesskey(")) {
469         // FIXME: accesskey() support.
470         type = Condition::AccessKey;
471     } else
472         type = Condition::EventBase;
473
474     m_conditions.append(Condition(type, beginOrEnd, baseID, nameString, offset, repeat));
475
476     if (type == Condition::EventBase && beginOrEnd == End)
477         m_hasEndEventConditions = true;
478
479     return true;
480 }
481
482 void SVGSMILElement::parseBeginOrEnd(const String& parseString, BeginOrEnd beginOrEnd)
483 {
484     Vector<SMILTimeWithOrigin>& timeList = beginOrEnd == Begin ? m_beginTimes : m_endTimes;
485     if (beginOrEnd == End)
486         m_hasEndEventConditions = false;
487     HashSet<double> existing;
488     for (unsigned n = 0; n < timeList.size(); ++n)
489         existing.add(timeList[n].time().value());
490     Vector<String> splitString;
491     parseString.split(';', splitString);
492     for (unsigned n = 0; n < splitString.size(); ++n) {
493         SMILTime value = parseClockValue(splitString[n]);
494         if (value.isUnresolved())
495             parseCondition(splitString[n], beginOrEnd);
496         else if (!existing.contains(value.value()))
497             timeList.append(SMILTimeWithOrigin(value, SMILTimeWithOrigin::ParserOrigin));
498     }
499     sortTimeList(timeList);
500 }
501
502 bool SVGSMILElement::isSupportedAttribute(const QualifiedName& attrName)
503 {
504     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
505     if (supportedAttributes.isEmpty()) {
506         supportedAttributes.add(SVGNames::beginAttr);
507         supportedAttributes.add(SVGNames::endAttr);
508         supportedAttributes.add(SVGNames::durAttr);
509         supportedAttributes.add(SVGNames::repeatDurAttr);
510         supportedAttributes.add(SVGNames::repeatCountAttr);
511         supportedAttributes.add(SVGNames::minAttr);
512         supportedAttributes.add(SVGNames::maxAttr);
513         supportedAttributes.add(SVGNames::attributeNameAttr);
514         supportedAttributes.add(XLinkNames::hrefAttr);
515     }
516     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
517 }
518
519 void SVGSMILElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
520 {
521     if (name == SVGNames::beginAttr) {
522         if (!m_conditions.isEmpty()) {
523             clearConditions();
524             parseBeginOrEnd(fastGetAttribute(SVGNames::endAttr), End);
525         }
526         parseBeginOrEnd(value.string(), Begin);
527         if (inDocument())
528             connectSyncBaseConditions();
529     } else if (name == SVGNames::endAttr) {
530         if (!m_conditions.isEmpty()) {
531             clearConditions();
532             parseBeginOrEnd(fastGetAttribute(SVGNames::beginAttr), Begin);
533         }
534         parseBeginOrEnd(value.string(), End);
535         if (inDocument())
536             connectSyncBaseConditions();
537     } else if (name == SVGNames::onbeginAttr) {
538         setAttributeEventListener(EventTypeNames::beginEvent, createAttributeEventListener(this, name, value));
539     } else if (name == SVGNames::onendAttr) {
540         setAttributeEventListener(EventTypeNames::endEvent, createAttributeEventListener(this, name, value));
541     } else if (name == SVGNames::onrepeatAttr) {
542         setAttributeEventListener(EventTypeNames::repeatEvent, createAttributeEventListener(this, name, value));
543     } else
544         SVGElement::parseAttribute(name, value);
545 }
546
547 void SVGSMILElement::svgAttributeChanged(const QualifiedName& attrName)
548 {
549     if (!isSupportedAttribute(attrName)) {
550         SVGElement::svgAttributeChanged(attrName);
551         return;
552     }
553
554     if (attrName == SVGNames::durAttr)
555         m_cachedDur = invalidCachedTime;
556     else if (attrName == SVGNames::repeatDurAttr)
557         m_cachedRepeatDur = invalidCachedTime;
558     else if (attrName == SVGNames::repeatCountAttr)
559         m_cachedRepeatCount = invalidCachedTime;
560     else if (attrName == SVGNames::minAttr)
561         m_cachedMin = invalidCachedTime;
562     else if (attrName == SVGNames::maxAttr)
563         m_cachedMax = invalidCachedTime;
564     else if (attrName == SVGNames::attributeNameAttr)
565         setAttributeName(constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr)));
566     else if (attrName.matches(XLinkNames::hrefAttr)) {
567         SVGElement::InvalidationGuard invalidationGuard(this);
568         buildPendingResource();
569         if (m_targetElement)
570             clearAnimatedType(m_targetElement);
571     } else if (inDocument()) {
572         if (attrName == SVGNames::beginAttr)
573             beginListChanged(elapsed());
574         else if (attrName == SVGNames::endAttr)
575             endListChanged(elapsed());
576     }
577
578     animationAttributeChanged();
579 }
580
581 inline SVGElement* SVGSMILElement::eventBaseFor(const Condition& condition)
582 {
583     Element* eventBase = condition.m_baseID.isEmpty() ? targetElement() : treeScope().getElementById(AtomicString(condition.m_baseID));
584     if (eventBase && eventBase->isSVGElement())
585         return toSVGElement(eventBase);
586     return 0;
587 }
588
589 void SVGSMILElement::connectSyncBaseConditions()
590 {
591     if (m_syncBaseConditionsConnected)
592         disconnectSyncBaseConditions();
593     m_syncBaseConditionsConnected = true;
594     for (unsigned n = 0; n < m_conditions.size(); ++n) {
595         Condition& condition = m_conditions[n];
596         if (condition.m_type == Condition::Syncbase) {
597             ASSERT(!condition.m_baseID.isEmpty());
598             condition.m_syncbase = treeScope().getElementById(AtomicString(condition.m_baseID));
599             if (!condition.m_syncbase || !isSVGSMILElement(*condition.m_syncbase)) {
600                 condition.m_syncbase = nullptr;
601                 continue;
602             }
603             toSVGSMILElement(condition.m_syncbase.get())->addSyncBaseDependent(this);
604         }
605     }
606 }
607
608 void SVGSMILElement::disconnectSyncBaseConditions()
609 {
610     if (!m_syncBaseConditionsConnected)
611         return;
612     m_syncBaseConditionsConnected = false;
613     for (unsigned n = 0; n < m_conditions.size(); ++n) {
614         Condition& condition = m_conditions[n];
615         if (condition.m_type == Condition::Syncbase) {
616             if (condition.m_syncbase)
617                 toSVGSMILElement(condition.m_syncbase.get())->removeSyncBaseDependent(this);
618             condition.m_syncbase = nullptr;
619         }
620     }
621 }
622
623 void SVGSMILElement::connectEventBaseConditions()
624 {
625     disconnectEventBaseConditions();
626     for (unsigned n = 0; n < m_conditions.size(); ++n) {
627         Condition& condition = m_conditions[n];
628         if (condition.m_type == Condition::EventBase) {
629             ASSERT(!condition.m_syncbase);
630             SVGElement* eventBase = eventBaseFor(condition);
631             if (!eventBase) {
632                 if (!condition.m_baseID.isEmpty() && !document().accessSVGExtensions().isElementPendingResource(this, AtomicString(condition.m_baseID)))
633                     document().accessSVGExtensions().addPendingResource(AtomicString(condition.m_baseID), this);
634                 continue;
635             }
636             ASSERT(!condition.m_eventListener);
637             condition.m_eventListener = ConditionEventListener::create(this, &condition);
638             eventBase->addEventListener(AtomicString(condition.m_name), condition.m_eventListener, false);
639             document().accessSVGExtensions().addElementReferencingTarget(this, eventBase);
640         }
641     }
642 }
643
644 void SVGSMILElement::disconnectEventBaseConditions()
645 {
646     for (unsigned n = 0; n < m_conditions.size(); ++n) {
647         Condition& condition = m_conditions[n];
648         if (condition.m_type == Condition::EventBase) {
649             ASSERT(!condition.m_syncbase);
650             if (!condition.m_eventListener)
651                 continue;
652             // Note: It's a memory optimization to try to remove our condition
653             // event listener, but it's not guaranteed to work, since we have
654             // no guarantee that eventBaseFor() will be able to find our condition's
655             // original eventBase. So, we also have to disconnect ourselves from
656             // our condition event listener, in case it later fires.
657             SVGElement* eventBase = eventBaseFor(condition);
658             if (eventBase)
659                 eventBase->removeEventListener(AtomicString(condition.m_name), condition.m_eventListener.get(), false);
660             condition.m_eventListener->disconnectAnimation();
661             condition.m_eventListener = nullptr;
662         }
663     }
664 }
665
666 void SVGSMILElement::setAttributeName(const QualifiedName& attributeName)
667 {
668     if (m_timeContainer && m_targetElement && m_attributeName != attributeName) {
669         if (hasValidAttributeName())
670             m_timeContainer->unschedule(this, m_targetElement, m_attributeName);
671         m_attributeName = attributeName;
672         if (hasValidAttributeName())
673             m_timeContainer->schedule(this, m_targetElement, m_attributeName);
674     } else
675         m_attributeName = attributeName;
676
677     // Only clear the animated type, if we had a target before.
678     if (m_targetElement)
679         clearAnimatedType(m_targetElement);
680 }
681
682 void SVGSMILElement::setTargetElement(SVGElement* target)
683 {
684     if (m_timeContainer && hasValidAttributeName()) {
685         if (m_targetElement)
686             m_timeContainer->unschedule(this, m_targetElement, m_attributeName);
687         if (target)
688             m_timeContainer->schedule(this, target, m_attributeName);
689     }
690
691     if (m_targetElement) {
692         // Clear values that may depend on the previous target.
693         clearAnimatedType(m_targetElement);
694         disconnectSyncBaseConditions();
695     }
696
697     // If the animation state is not Inactive, always reset to a clear state before leaving the old target element.
698     if (m_activeState != Inactive)
699         endedActiveInterval();
700
701     m_targetElement = target;
702 }
703
704 SMILTime SVGSMILElement::elapsed() const
705 {
706     return m_timeContainer ? m_timeContainer->elapsed() : 0;
707 }
708
709 bool SVGSMILElement::isFrozen() const
710 {
711     return m_activeState == Frozen;
712 }
713
714 SVGSMILElement::Restart SVGSMILElement::restart() const
715 {
716     DEFINE_STATIC_LOCAL(const AtomicString, never, ("never", AtomicString::ConstructFromLiteral));
717     DEFINE_STATIC_LOCAL(const AtomicString, whenNotActive, ("whenNotActive", AtomicString::ConstructFromLiteral));
718     const AtomicString& value = fastGetAttribute(SVGNames::restartAttr);
719     if (value == never)
720         return RestartNever;
721     if (value == whenNotActive)
722         return RestartWhenNotActive;
723     return RestartAlways;
724 }
725
726 SVGSMILElement::FillMode SVGSMILElement::fill() const
727 {
728     DEFINE_STATIC_LOCAL(const AtomicString, freeze, ("freeze", AtomicString::ConstructFromLiteral));
729     const AtomicString& value = fastGetAttribute(SVGNames::fillAttr);
730     return value == freeze ? FillFreeze : FillRemove;
731 }
732
733 SMILTime SVGSMILElement::dur() const
734 {
735     if (m_cachedDur != invalidCachedTime)
736         return m_cachedDur;
737     const AtomicString& value = fastGetAttribute(SVGNames::durAttr);
738     SMILTime clockValue = parseClockValue(value);
739     return m_cachedDur = clockValue <= 0 ? SMILTime::unresolved() : clockValue;
740 }
741
742 SMILTime SVGSMILElement::repeatDur() const
743 {
744     if (m_cachedRepeatDur != invalidCachedTime)
745         return m_cachedRepeatDur;
746     const AtomicString& value = fastGetAttribute(SVGNames::repeatDurAttr);
747     SMILTime clockValue = parseClockValue(value);
748     m_cachedRepeatDur = clockValue <= 0 ? SMILTime::unresolved() : clockValue;
749     return m_cachedRepeatDur;
750 }
751
752 // So a count is not really a time but let just all pretend we did not notice.
753 SMILTime SVGSMILElement::repeatCount() const
754 {
755     if (m_cachedRepeatCount != invalidCachedTime)
756         return m_cachedRepeatCount;
757     SMILTime computedRepeatCount = SMILTime::unresolved();
758     const AtomicString& value = fastGetAttribute(SVGNames::repeatCountAttr);
759     if (!value.isNull()) {
760         DEFINE_STATIC_LOCAL(const AtomicString, indefiniteValue, ("indefinite", AtomicString::ConstructFromLiteral));
761         if (value == indefiniteValue) {
762             computedRepeatCount = SMILTime::indefinite();
763         } else {
764             bool ok;
765             double result = value.string().toDouble(&ok);
766             if (ok && result > 0)
767                 computedRepeatCount = result;
768         }
769     }
770     m_cachedRepeatCount = computedRepeatCount;
771     return m_cachedRepeatCount;
772 }
773
774 SMILTime SVGSMILElement::maxValue() const
775 {
776     if (m_cachedMax != invalidCachedTime)
777         return m_cachedMax;
778     const AtomicString& value = fastGetAttribute(SVGNames::maxAttr);
779     SMILTime result = parseClockValue(value);
780     return m_cachedMax = (result.isUnresolved() || result <= 0) ? SMILTime::indefinite() : result;
781 }
782
783 SMILTime SVGSMILElement::minValue() const
784 {
785     if (m_cachedMin != invalidCachedTime)
786         return m_cachedMin;
787     const AtomicString& value = fastGetAttribute(SVGNames::minAttr);
788     SMILTime result = parseClockValue(value);
789     return m_cachedMin = (result.isUnresolved() || result < 0) ? 0 : result;
790 }
791
792 SMILTime SVGSMILElement::simpleDuration() const
793 {
794     return min(dur(), SMILTime::indefinite());
795 }
796
797 void SVGSMILElement::addBeginTime(SMILTime eventTime, SMILTime beginTime, SMILTimeWithOrigin::Origin origin)
798 {
799     ASSERT(!std::isnan(beginTime.value()));
800     m_beginTimes.append(SMILTimeWithOrigin(beginTime, origin));
801     sortTimeList(m_beginTimes);
802     beginListChanged(eventTime);
803 }
804
805 void SVGSMILElement::addEndTime(SMILTime eventTime, SMILTime endTime, SMILTimeWithOrigin::Origin origin)
806 {
807     ASSERT(!std::isnan(endTime.value()));
808     m_endTimes.append(SMILTimeWithOrigin(endTime, origin));
809     sortTimeList(m_endTimes);
810     endListChanged(eventTime);
811 }
812
813 inline bool compareTimes(const SMILTimeWithOrigin& left, const SMILTimeWithOrigin& right)
814 {
815     return left.time() < right.time();
816 }
817
818 SMILTime SVGSMILElement::findInstanceTime(BeginOrEnd beginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const
819 {
820     const Vector<SMILTimeWithOrigin>& list = beginOrEnd == Begin ? m_beginTimes : m_endTimes;
821     int sizeOfList = list.size();
822
823     if (!sizeOfList)
824         return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite();
825
826     const SMILTimeWithOrigin dummyTimeWithOrigin(minimumTime, SMILTimeWithOrigin::ParserOrigin);
827     const SMILTimeWithOrigin* result = std::lower_bound(list.begin(), list.end(), dummyTimeWithOrigin, compareTimes);
828     int indexOfResult = result - list.begin();
829     if (indexOfResult == sizeOfList)
830         return SMILTime::unresolved();
831     const SMILTime& currentTime = list[indexOfResult].time();
832
833     // The special value "indefinite" does not yield an instance time in the begin list.
834     if (currentTime.isIndefinite() && beginOrEnd == Begin)
835         return SMILTime::unresolved();
836
837     if (currentTime > minimumTime)
838         return currentTime;
839
840     ASSERT(currentTime == minimumTime);
841     if (equalsMinimumOK)
842         return currentTime;
843
844     // If the equals is not accepted, return the next bigger item in the list.
845     SMILTime nextTime = currentTime;
846     while (indexOfResult < sizeOfList - 1) {
847         nextTime = list[indexOfResult + 1].time();
848         if (nextTime > minimumTime)
849             return nextTime;
850         ++indexOfResult;
851     }
852
853     return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite();
854 }
855
856 SMILTime SVGSMILElement::repeatingDuration() const
857 {
858     // Computing the active duration
859     // http://www.w3.org/TR/SMIL2/smil-timing.html#Timing-ComputingActiveDur
860     SMILTime repeatCount = this->repeatCount();
861     SMILTime repeatDur = this->repeatDur();
862     SMILTime simpleDuration = this->simpleDuration();
863     if (!simpleDuration || (repeatDur.isUnresolved() && repeatCount.isUnresolved()))
864         return simpleDuration;
865     SMILTime repeatCountDuration = simpleDuration * repeatCount;
866     return min(repeatCountDuration, min(repeatDur, SMILTime::indefinite()));
867 }
868
869 SMILTime SVGSMILElement::resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const
870 {
871     // Computing the active duration
872     // http://www.w3.org/TR/SMIL2/smil-timing.html#Timing-ComputingActiveDur
873     SMILTime preliminaryActiveDuration;
874     if (!resolvedEnd.isUnresolved() && dur().isUnresolved() && repeatDur().isUnresolved() && repeatCount().isUnresolved())
875         preliminaryActiveDuration = resolvedEnd - resolvedBegin;
876     else if (!resolvedEnd.isFinite())
877         preliminaryActiveDuration = repeatingDuration();
878     else
879         preliminaryActiveDuration = min(repeatingDuration(), resolvedEnd - resolvedBegin);
880
881     SMILTime minValue = this->minValue();
882     SMILTime maxValue = this->maxValue();
883     if (minValue > maxValue) {
884         // Ignore both.
885         // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#MinMax
886         minValue = 0;
887         maxValue = SMILTime::indefinite();
888     }
889     return resolvedBegin + min(maxValue, max(minValue, preliminaryActiveDuration));
890 }
891
892 void SVGSMILElement::resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const
893 {
894     // See the pseudocode in http://www.w3.org/TR/SMIL3/smil-timing.html#q90.
895     SMILTime beginAfter = first ? -numeric_limits<double>::infinity() : m_intervalEnd;
896     SMILTime lastIntervalTempEnd = numeric_limits<double>::infinity();
897     while (true) {
898         bool equalsMinimumOK = !first || m_intervalEnd > m_intervalBegin;
899         SMILTime tempBegin = findInstanceTime(Begin, beginAfter, equalsMinimumOK);
900         if (tempBegin.isUnresolved())
901             break;
902         SMILTime tempEnd;
903         if (m_endTimes.isEmpty())
904             tempEnd = resolveActiveEnd(tempBegin, SMILTime::indefinite());
905         else {
906             tempEnd = findInstanceTime(End, tempBegin, true);
907             if ((first && tempBegin == tempEnd && tempEnd == lastIntervalTempEnd) || (!first && tempEnd == m_intervalEnd))
908                 tempEnd = findInstanceTime(End, tempBegin, false);
909             if (tempEnd.isUnresolved()) {
910                 if (!m_endTimes.isEmpty() && !m_hasEndEventConditions)
911                     break;
912             }
913             tempEnd = resolveActiveEnd(tempBegin, tempEnd);
914         }
915         if (!first || (tempEnd > 0 || (!tempBegin.value() && !tempEnd.value()))) {
916             beginResult = tempBegin;
917             endResult = tempEnd;
918             return;
919         }
920
921         beginAfter = tempEnd;
922         lastIntervalTempEnd = tempEnd;
923     }
924     beginResult = SMILTime::unresolved();
925     endResult = SMILTime::unresolved();
926 }
927
928 void SVGSMILElement::resolveFirstInterval()
929 {
930     SMILTime begin;
931     SMILTime end;
932     resolveInterval(true, begin, end);
933     ASSERT(!begin.isIndefinite());
934
935     if (!begin.isUnresolved() && (begin != m_intervalBegin || end != m_intervalEnd)) {
936         m_intervalBegin = begin;
937         m_intervalEnd = end;
938         notifyDependentsIntervalChanged();
939         m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
940
941         if (m_timeContainer)
942             m_timeContainer->notifyIntervalsChanged();
943     }
944 }
945
946 bool SVGSMILElement::resolveNextInterval()
947 {
948     SMILTime begin;
949     SMILTime end;
950     resolveInterval(false, begin, end);
951     ASSERT(!begin.isIndefinite());
952
953     if (!begin.isUnresolved() && begin != m_intervalBegin) {
954         m_intervalBegin = begin;
955         m_intervalEnd = end;
956         notifyDependentsIntervalChanged();
957         m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
958         return true;
959     }
960
961     return false;
962 }
963
964 SMILTime SVGSMILElement::nextProgressTime() const
965 {
966     return m_nextProgressTime;
967 }
968
969 void SVGSMILElement::beginListChanged(SMILTime eventTime)
970 {
971     if (m_isWaitingForFirstInterval)
972         resolveFirstInterval();
973     else {
974         SMILTime newBegin = findInstanceTime(Begin, eventTime, true);
975         if (newBegin.isFinite() && (m_intervalEnd <= eventTime || newBegin < m_intervalBegin)) {
976             // Begin time changed, re-resolve the interval.
977             SMILTime oldBegin = m_intervalBegin;
978             m_intervalEnd = eventTime;
979             resolveInterval(false, m_intervalBegin, m_intervalEnd);
980             ASSERT(!m_intervalBegin.isUnresolved());
981             if (m_intervalBegin != oldBegin) {
982                 if (m_activeState == Active && m_intervalBegin > eventTime) {
983                     m_activeState = determineActiveState(eventTime);
984                     if (m_activeState != Active)
985                         endedActiveInterval();
986                 }
987                 notifyDependentsIntervalChanged();
988             }
989         }
990     }
991     m_nextProgressTime = elapsed();
992
993     if (m_timeContainer)
994         m_timeContainer->notifyIntervalsChanged();
995 }
996
997 void SVGSMILElement::endListChanged(SMILTime)
998 {
999     SMILTime elapsed = this->elapsed();
1000     if (m_isWaitingForFirstInterval)
1001         resolveFirstInterval();
1002     else if (elapsed < m_intervalEnd && m_intervalBegin.isFinite()) {
1003         SMILTime newEnd = findInstanceTime(End, m_intervalBegin, false);
1004         if (newEnd < m_intervalEnd) {
1005             newEnd = resolveActiveEnd(m_intervalBegin, newEnd);
1006             if (newEnd != m_intervalEnd) {
1007                 m_intervalEnd = newEnd;
1008                 notifyDependentsIntervalChanged();
1009             }
1010         }
1011     }
1012     m_nextProgressTime = elapsed;
1013
1014     if (m_timeContainer)
1015         m_timeContainer->notifyIntervalsChanged();
1016 }
1017
1018 SVGSMILElement::RestartedInterval SVGSMILElement::maybeRestartInterval(SMILTime elapsed)
1019 {
1020     ASSERT(!m_isWaitingForFirstInterval);
1021     ASSERT(elapsed >= m_intervalBegin);
1022
1023     Restart restart = this->restart();
1024     if (restart == RestartNever)
1025         return DidNotRestartInterval;
1026
1027     if (elapsed < m_intervalEnd) {
1028         if (restart != RestartAlways)
1029             return DidNotRestartInterval;
1030         SMILTime nextBegin = findInstanceTime(Begin, m_intervalBegin, false);
1031         if (nextBegin < m_intervalEnd) {
1032             m_intervalEnd = nextBegin;
1033             notifyDependentsIntervalChanged();
1034         }
1035     }
1036
1037     if (elapsed >= m_intervalEnd) {
1038         if (resolveNextInterval() && elapsed >= m_intervalBegin)
1039             return DidRestartInterval;
1040     }
1041     return DidNotRestartInterval;
1042 }
1043
1044 void SVGSMILElement::seekToIntervalCorrespondingToTime(SMILTime elapsed)
1045 {
1046     ASSERT(!m_isWaitingForFirstInterval);
1047     ASSERT(elapsed >= m_intervalBegin);
1048
1049     // Manually seek from interval to interval, just as if the animation would run regulary.
1050     while (true) {
1051         // Figure out the next value in the begin time list after the current interval begin.
1052         SMILTime nextBegin = findInstanceTime(Begin, m_intervalBegin, false);
1053
1054         // If the 'nextBegin' time is unresolved (eg. just one defined interval), we're done seeking.
1055         if (nextBegin.isUnresolved())
1056             return;
1057
1058         // If the 'nextBegin' time is larger than or equal to the current interval end time, we're done seeking.
1059         // If the 'elapsed' time is smaller than the next begin interval time, we're done seeking.
1060         if (nextBegin < m_intervalEnd && elapsed >= nextBegin) {
1061             // End current interval, and start a new interval from the 'nextBegin' time.
1062             m_intervalEnd = nextBegin;
1063             if (!resolveNextInterval())
1064                 break;
1065             continue;
1066         }
1067
1068         // If the desired 'elapsed' time is past the current interval, advance to the next.
1069         if (elapsed >= m_intervalEnd) {
1070             if (!resolveNextInterval())
1071                 break;
1072             continue;
1073         }
1074
1075         return;
1076     }
1077 }
1078
1079 float SVGSMILElement::calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const
1080 {
1081     SMILTime simpleDuration = this->simpleDuration();
1082     repeat = 0;
1083     if (simpleDuration.isIndefinite()) {
1084         repeat = 0;
1085         return 0.f;
1086     }
1087     if (!simpleDuration) {
1088         repeat = 0;
1089         return 1.f;
1090     }
1091     ASSERT(m_intervalBegin.isFinite());
1092     ASSERT(simpleDuration.isFinite());
1093     SMILTime activeTime = elapsed - m_intervalBegin;
1094     SMILTime repeatingDuration = this->repeatingDuration();
1095     if (elapsed >= m_intervalEnd || activeTime > repeatingDuration) {
1096         repeat = static_cast<unsigned>(repeatingDuration.value() / simpleDuration.value());
1097         if (!fmod(repeatingDuration.value(), simpleDuration.value()))
1098             repeat--;
1099
1100         double percent = (m_intervalEnd.value() - m_intervalBegin.value()) / simpleDuration.value();
1101         percent = percent - floor(percent);
1102         if (percent < numeric_limits<float>::epsilon() || 1 - percent < numeric_limits<float>::epsilon())
1103             return 1.0f;
1104         return narrowPrecisionToFloat(percent);
1105     }
1106     repeat = static_cast<unsigned>(activeTime.value() / simpleDuration.value());
1107     SMILTime simpleTime = fmod(activeTime.value(), simpleDuration.value());
1108     return narrowPrecisionToFloat(simpleTime.value() / simpleDuration.value());
1109 }
1110
1111 SMILTime SVGSMILElement::calculateNextProgressTime(SMILTime elapsed) const
1112 {
1113     if (m_activeState == Active) {
1114         // If duration is indefinite the value does not actually change over time. Same is true for <set>.
1115         SMILTime simpleDuration = this->simpleDuration();
1116         if (simpleDuration.isIndefinite() || isSVGSetElement(*this)) {
1117             SMILTime repeatingDurationEnd = m_intervalBegin + repeatingDuration();
1118             // We are supposed to do freeze semantics when repeating ends, even if the element is still active.
1119             // Take care that we get a timer callback at that point.
1120             if (elapsed < repeatingDurationEnd && repeatingDurationEnd < m_intervalEnd && repeatingDurationEnd.isFinite())
1121                 return repeatingDurationEnd;
1122             return m_intervalEnd;
1123         }
1124         return elapsed + 0.025;
1125     }
1126     return m_intervalBegin >= elapsed ? m_intervalBegin : SMILTime::unresolved();
1127 }
1128
1129 SVGSMILElement::ActiveState SVGSMILElement::determineActiveState(SMILTime elapsed) const
1130 {
1131     if (elapsed >= m_intervalBegin && elapsed < m_intervalEnd)
1132         return Active;
1133
1134     return fill() == FillFreeze ? Frozen : Inactive;
1135 }
1136
1137 bool SVGSMILElement::isContributing(SMILTime elapsed) const
1138 {
1139     // Animation does not contribute during the active time if it is past its repeating duration and has fill=remove.
1140     return (m_activeState == Active && (fill() == FillFreeze || elapsed <= m_intervalBegin + repeatingDuration())) || m_activeState == Frozen;
1141 }
1142
1143 bool SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement, bool seekToTime)
1144 {
1145     ASSERT(resultElement);
1146     ASSERT(m_timeContainer);
1147     ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
1148
1149     if (!m_syncBaseConditionsConnected)
1150         connectSyncBaseConditions();
1151
1152     if (!m_intervalBegin.isFinite()) {
1153         ASSERT(m_activeState == Inactive);
1154         m_nextProgressTime = SMILTime::unresolved();
1155         return false;
1156     }
1157
1158     if (elapsed < m_intervalBegin) {
1159         ASSERT(m_activeState != Active);
1160         if (m_activeState == Frozen) {
1161             if (this == resultElement)
1162                 resetAnimatedType();
1163             updateAnimation(m_lastPercent, m_lastRepeat, resultElement);
1164         }
1165         m_nextProgressTime = m_intervalBegin;
1166         return false;
1167     }
1168
1169     m_previousIntervalBegin = m_intervalBegin;
1170
1171     if (m_isWaitingForFirstInterval) {
1172         m_isWaitingForFirstInterval = false;
1173         resolveFirstInterval();
1174     }
1175
1176     // This call may obtain a new interval -- never call calculateAnimationPercentAndRepeat() before!
1177     if (seekToTime) {
1178         seekToIntervalCorrespondingToTime(elapsed);
1179         if (elapsed < m_intervalBegin) {
1180             // elapsed is not within an interval.
1181             m_nextProgressTime = m_intervalBegin;
1182             return false;
1183         }
1184     }
1185
1186     unsigned repeat = 0;
1187     float percent = calculateAnimationPercentAndRepeat(elapsed, repeat);
1188     RestartedInterval restartedInterval = maybeRestartInterval(elapsed);
1189
1190     ActiveState oldActiveState = m_activeState;
1191     m_activeState = determineActiveState(elapsed);
1192     bool animationIsContributing = isContributing(elapsed);
1193
1194     // Only reset the animated type to the base value once for the lowest priority animation that animates and contributes to a particular element/attribute pair.
1195     if (this == resultElement && animationIsContributing)
1196         resetAnimatedType();
1197
1198     if (animationIsContributing) {
1199         if (oldActiveState == Inactive || restartedInterval == DidRestartInterval) {
1200             smilBeginEventSender().dispatchEventSoon(this);
1201             startedActiveInterval();
1202         }
1203
1204         if (repeat && repeat != m_lastRepeat)
1205             dispatchRepeatEvents(repeat);
1206
1207         updateAnimation(percent, repeat, resultElement);
1208         m_lastPercent = percent;
1209         m_lastRepeat = repeat;
1210     }
1211
1212     if ((oldActiveState == Active && m_activeState != Active) || restartedInterval == DidRestartInterval) {
1213         smilEndEventSender().dispatchEventSoon(this);
1214         endedActiveInterval();
1215         if (!animationIsContributing && this == resultElement)
1216             clearAnimatedType(m_targetElement);
1217     }
1218
1219     // Triggering all the pending events if the animation timeline is changed.
1220     if (seekToTime) {
1221         if (m_activeState == Inactive)
1222             smilBeginEventSender().dispatchEventSoon(this);
1223
1224         if (repeat) {
1225             for (unsigned repeatEventCount = 1; repeatEventCount < repeat; repeatEventCount++)
1226                 dispatchRepeatEvents(repeatEventCount);
1227             if (m_activeState == Inactive)
1228                 dispatchRepeatEvents(repeat);
1229         }
1230
1231         if (m_activeState == Inactive || m_activeState == Frozen)
1232             smilEndEventSender().dispatchEventSoon(this);
1233     }
1234
1235     m_nextProgressTime = calculateNextProgressTime(elapsed);
1236     return animationIsContributing;
1237 }
1238
1239 void SVGSMILElement::notifyDependentsIntervalChanged()
1240 {
1241     ASSERT(m_intervalBegin.isFinite());
1242     DEFINE_STATIC_LOCAL(HashSet<SVGSMILElement*>, loopBreaker, ());
1243     if (!loopBreaker.add(this).isNewEntry)
1244         return;
1245
1246     TimeDependentSet::iterator end = m_syncBaseDependents.end();
1247     for (TimeDependentSet::iterator it = m_syncBaseDependents.begin(); it != end; ++it) {
1248         SVGSMILElement* dependent = *it;
1249         dependent->createInstanceTimesFromSyncbase(this);
1250     }
1251
1252     loopBreaker.remove(this);
1253 }
1254
1255 void SVGSMILElement::createInstanceTimesFromSyncbase(SVGSMILElement* syncbase)
1256 {
1257     // FIXME: To be really correct, this should handle updating exising interval by changing
1258     // the associated times instead of creating new ones.
1259     for (unsigned n = 0; n < m_conditions.size(); ++n) {
1260         Condition& condition = m_conditions[n];
1261         if (condition.m_type == Condition::Syncbase && condition.m_syncbase == syncbase) {
1262             ASSERT(condition.m_name == "begin" || condition.m_name == "end");
1263             // No nested time containers in SVG, no need for crazy time space conversions. Phew!
1264             SMILTime time = 0;
1265             if (condition.m_name == "begin")
1266                 time = syncbase->m_intervalBegin + condition.m_offset;
1267             else
1268                 time = syncbase->m_intervalEnd + condition.m_offset;
1269             if (!time.isFinite())
1270                 continue;
1271             if (condition.m_beginOrEnd == Begin)
1272                 addBeginTime(elapsed(), time);
1273             else
1274                 addEndTime(elapsed(), time);
1275         }
1276     }
1277 }
1278
1279 void SVGSMILElement::addSyncBaseDependent(SVGSMILElement* animation)
1280 {
1281     m_syncBaseDependents.add(animation);
1282     if (m_intervalBegin.isFinite())
1283         animation->createInstanceTimesFromSyncbase(this);
1284 }
1285
1286 void SVGSMILElement::removeSyncBaseDependent(SVGSMILElement* animation)
1287 {
1288     m_syncBaseDependents.remove(animation);
1289 }
1290
1291 void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition)
1292 {
1293     if (event->type() == "repeatn" && toRepeatEvent(event)->repeat() != condition->m_repeat)
1294         return;
1295
1296     SMILTime elapsed = this->elapsed();
1297     if (condition->m_beginOrEnd == Begin)
1298         addBeginTime(elapsed, elapsed + condition->m_offset);
1299     else
1300         addEndTime(elapsed, elapsed + condition->m_offset);
1301 }
1302
1303 void SVGSMILElement::beginByLinkActivation()
1304 {
1305     SMILTime elapsed = this->elapsed();
1306     addBeginTime(elapsed, elapsed);
1307 }
1308
1309 void SVGSMILElement::endedActiveInterval()
1310 {
1311     clearTimesWithDynamicOrigins(m_beginTimes);
1312     clearTimesWithDynamicOrigins(m_endTimes);
1313 }
1314
1315 void SVGSMILElement::dispatchRepeatEvents(unsigned count)
1316 {
1317     m_repeatEventCountList.append(count);
1318     smilRepeatEventSender().dispatchEventSoon(this);
1319     smilRepeatNEventSender().dispatchEventSoon(this);
1320 }
1321
1322 void SVGSMILElement::dispatchPendingEvent(SMILEventSender* eventSender)
1323 {
1324     ASSERT(eventSender == &smilEndEventSender() || eventSender == &smilBeginEventSender() || eventSender == &smilRepeatEventSender() || eventSender == &smilRepeatNEventSender());
1325     const AtomicString& eventType = eventSender->eventType();
1326     if (eventType == "repeatn") {
1327         unsigned repeatEventCount = m_repeatEventCountList.first();
1328         m_repeatEventCountList.remove(0);
1329         dispatchEvent(RepeatEvent::create(eventType, repeatEventCount));
1330     } else {
1331         dispatchEvent(Event::create(eventType));
1332     }
1333 }
1334
1335 void SVGSMILElement::trace(Visitor* visitor)
1336 {
1337     visitor->trace(m_targetElement);
1338     SVGElement::trace(visitor);
1339 }
1340
1341 }