Home | History | Annotate | Download | only in animation
      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 
     46 namespace blink {
     47 
     48 class RepeatEvent FINAL : public Event {
     49 public:
     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 
     64 protected:
     65     RepeatEvent(const AtomicString& type, bool canBubble, bool cancelable, int repeat = -1)
     66         : Event(type, canBubble, cancelable)
     67         , m_repeat(repeat)
     68     {
     69     }
     70 
     71 private:
     72     int m_repeat;
     73 };
     74 
     75 inline RepeatEvent* toRepeatEvent(Event* event)
     76 {
     77     ASSERT_WITH_SECURITY_IMPLICATION(!event || event->type() == "repeatn");
     78     return static_cast<RepeatEvent*>(event);
     79 }
     80 
     81 static SMILEventSender& smilEndEventSender()
     82 {
     83     DEFINE_STATIC_LOCAL(SMILEventSender, sender, (EventTypeNames::endEvent));
     84     return sender;
     85 }
     86 
     87 static SMILEventSender& smilBeginEventSender()
     88 {
     89     DEFINE_STATIC_LOCAL(SMILEventSender, sender, (EventTypeNames::beginEvent));
     90     return sender;
     91 }
     92 
     93 static SMILEventSender& smilRepeatEventSender()
     94 {
     95     DEFINE_STATIC_LOCAL(SMILEventSender, sender, (EventTypeNames::repeatEvent));
     96     return sender;
     97 }
     98 
     99 static 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.
    106 static const double invalidCachedTime = -1.;
    107 
    108 class ConditionEventListener FINAL : public EventListener {
    109 public:
    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 
    129 private:
    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 
    143 bool 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 
    150 void ConditionEventListener::handleEvent(ExecutionContext*, Event* event)
    151 {
    152     if (!m_animation)
    153         return;
    154     m_animation->handleConditionEvent(event, m_condition);
    155 }
    156 
    157 void SVGSMILElement::Condition::setEventListener(PassRefPtr<ConditionEventListener> eventListener)
    158 {
    159     m_eventListener = eventListener;
    160 }
    161 
    162 SVGSMILElement::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 
    172 SVGSMILElement::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 
    196 SVGSMILElement::~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 
    213 void SVGSMILElement::clearResourceAndEventBaseReferences()
    214 {
    215     removeAllOutgoingReferences();
    216 }
    217 
    218 void SVGSMILElement::clearConditions()
    219 {
    220     disconnectSyncBaseConditions();
    221     disconnectEventBaseConditions();
    222     m_conditions.clear();
    223 }
    224 
    225 void 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 
    267 static 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 
    287 static 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 
    295 void 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 
    310 Node::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 
    343 void 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 
    357 bool SVGSMILElement::hasValidAttributeName()
    358 {
    359     return attributeName() != anyQName();
    360 }
    361 
    362 SMILTime 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 
    382 SMILTime 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 
    418 static void sortTimeList(Vector<SMILTimeWithOrigin>& timeList)
    419 {
    420     std::sort(timeList.begin(), timeList.end());
    421 }
    422 
    423 bool 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 
    488 void 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 
    510 bool 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 
    528 void 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 
    557 void 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 
    591 inline 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 
    599 void 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 
    620 void 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 
    635 void 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 
    656 void 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 
    678 void 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 
    694 void 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 
    716 SMILTime SVGSMILElement::elapsed() const
    717 {
    718     return m_timeContainer ? m_timeContainer->elapsed() : 0;
    719 }
    720 
    721 bool SVGSMILElement::isFrozen() const
    722 {
    723     return m_activeState == Frozen;
    724 }
    725 
    726 SVGSMILElement::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 
    738 SVGSMILElement::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 
    745 SMILTime 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 
    754 SMILTime 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.
    765 SMILTime 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 
    786 SMILTime 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 
    795 SMILTime 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 
    804 SMILTime SVGSMILElement::simpleDuration() const
    805 {
    806     return std::min(dur(), SMILTime::indefinite());
    807 }
    808 
    809 void 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 
    816 void 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 
    823 inline bool compareTimes(const SMILTimeWithOrigin& left, const SMILTimeWithOrigin& right)
    824 {
    825     return left.time() < right.time();
    826 }
    827 
    828 SMILTime 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 
    866 SMILTime 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 
    882 SMILTime 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 
    905 SMILInterval 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 
    938 void 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 
    953 bool 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 
    968 SMILTime SVGSMILElement::nextProgressTime() const
    969 {
    970     return m_nextProgressTime;
    971 }
    972 
    973 void 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 
   1001 void 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 
   1022 SVGSMILElement::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 
   1048 void 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 
   1083 float 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 
   1115 SMILTime 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 
   1133 SVGSMILElement::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 
   1141 bool 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 
   1147 bool 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 
   1245 void 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 
   1264 void 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 
   1291 void SVGSMILElement::addSyncBaseDependent(SVGSMILElement* animation)
   1292 {
   1293     m_syncBaseDependents.add(animation);
   1294     if (m_interval.begin.isFinite())
   1295         animation->createInstanceTimesFromSyncbase(this);
   1296 }
   1297 
   1298 void SVGSMILElement::removeSyncBaseDependent(SVGSMILElement* animation)
   1299 {
   1300     m_syncBaseDependents.remove(animation);
   1301 }
   1302 
   1303 void 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 
   1317 void SVGSMILElement::beginByLinkActivation()
   1318 {
   1319     SMILTime elapsed = this->elapsed();
   1320     if (elapsed.isUnresolved())
   1321         return;
   1322     addBeginTime(elapsed, elapsed);
   1323 }
   1324 
   1325 void SVGSMILElement::endedActiveInterval()
   1326 {
   1327     clearTimesWithDynamicOrigins(m_beginTimes);
   1328     clearTimesWithDynamicOrigins(m_endTimes);
   1329 }
   1330 
   1331 void SVGSMILElement::dispatchRepeatEvents(unsigned count)
   1332 {
   1333     m_repeatEventCountList.append(count);
   1334     smilRepeatEventSender().dispatchEventSoon(this);
   1335     smilRepeatNEventSender().dispatchEventSoon(this);
   1336 }
   1337 
   1338 void 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 
   1351 SVGSMILElement::Condition::~Condition()
   1352 {
   1353 }
   1354 
   1355 void SVGSMILElement::Condition::trace(Visitor* visitor)
   1356 {
   1357     visitor->trace(m_syncBase);
   1358 }
   1359 
   1360 void 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