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