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