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