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