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 
     28 #if ENABLE(SVG_ANIMATION)
     29 #include "SVGSMILElement.h"
     30 
     31 #include "CSSPropertyNames.h"
     32 #include "Document.h"
     33 #include "Event.h"
     34 #include "EventListener.h"
     35 #include "FloatConversion.h"
     36 #include "FrameView.h"
     37 #include "HTMLNames.h"
     38 #include "MappedAttribute.h"
     39 #include "SMILTimeContainer.h"
     40 #include "SVGNames.h"
     41 #include "SVGParserUtilities.h"
     42 #include "SVGSVGElement.h"
     43 #include "SVGURIReference.h"
     44 #include "XLinkNames.h"
     45 #include <math.h>
     46 #include <wtf/MathExtras.h>
     47 #include <wtf/StdLibExtras.h>
     48 #include <wtf/Vector.h>
     49 
     50 using namespace std;
     51 
     52 namespace WebCore {
     53 
     54 // This is used for duration type time values that can't be negative.
     55 static const double invalidCachedTime = -1.;
     56 
     57 class ConditionEventListener : public EventListener {
     58 public:
     59     static PassRefPtr<ConditionEventListener> create(SVGSMILElement* animation, Element* eventBase, SVGSMILElement::Condition* condition)
     60     {
     61         return adoptRef(new ConditionEventListener(animation, eventBase, condition));
     62     }
     63 
     64     static const ConditionEventListener* cast(const EventListener* listener)
     65     {
     66         return listener->type() == ConditionEventListenerType
     67             ? static_cast<const ConditionEventListener*>(listener)
     68             : 0;
     69     }
     70 
     71     virtual bool operator==(const EventListener& other);
     72 
     73     void unregister()
     74     {
     75         // If this has only one ref then the event base is dead already and we don't need to remove ourself.
     76         if (!hasOneRef())
     77             m_eventBase->removeEventListener(m_condition->m_name, this, false);
     78     }
     79 
     80 private:
     81     ConditionEventListener(SVGSMILElement* animation, Element* eventBase, SVGSMILElement::Condition* condition)
     82         : EventListener(ConditionEventListenerType)
     83         , m_animation(animation)
     84         , m_condition(condition)
     85         , m_eventBase(eventBase)
     86     {
     87         m_eventBase->addEventListener(m_condition->m_name, this, false);
     88     }
     89 
     90     virtual void handleEvent(ScriptExecutionContext*, Event*);
     91 
     92     SVGSMILElement* m_animation;
     93     SVGSMILElement::Condition* m_condition;
     94     Element* m_eventBase;
     95 };
     96 
     97 bool ConditionEventListener::operator==(const EventListener& listener)
     98 {
     99     if (const ConditionEventListener* conditionEventListener = ConditionEventListener::cast(&listener))
    100         return m_animation == conditionEventListener->m_animation
    101                && m_condition == conditionEventListener->m_condition
    102                && m_eventBase == conditionEventListener->m_eventBase;
    103     return false;
    104 }
    105 
    106 void ConditionEventListener::handleEvent(ScriptExecutionContext*, Event* event)
    107 {
    108     m_animation->handleConditionEvent(event, m_condition);
    109 }
    110 
    111 SVGSMILElement::Condition::Condition(Type type, BeginOrEnd beginOrEnd, const String& baseID, const String& name, SMILTime offset, int repeats)
    112     : m_type(type)
    113     , m_beginOrEnd(beginOrEnd)
    114     , m_baseID(baseID)
    115     , m_name(name)
    116     , m_offset(offset)
    117     , m_repeats(repeats)
    118 {
    119 }
    120 
    121 SVGSMILElement::SVGSMILElement(const QualifiedName& tagName, Document* doc)
    122     : SVGElement(tagName, doc)
    123     , m_conditionsConnected(false)
    124     , m_hasEndEventConditions(false)
    125     , m_intervalBegin(SMILTime::unresolved())
    126     , m_intervalEnd(SMILTime::unresolved())
    127     , m_previousIntervalBegin(SMILTime::unresolved())
    128     , m_isWaitingForFirstInterval(true)
    129     , m_activeState(Inactive)
    130     , m_lastPercent(0)
    131     , m_lastRepeat(0)
    132     , m_nextProgressTime(0)
    133     , m_documentOrderIndex(0)
    134     , m_cachedDur(invalidCachedTime)
    135     , m_cachedRepeatDur(invalidCachedTime)
    136     , m_cachedRepeatCount(invalidCachedTime)
    137     , m_cachedMin(invalidCachedTime)
    138     , m_cachedMax(invalidCachedTime)
    139 {
    140 }
    141 
    142 SVGSMILElement::~SVGSMILElement()
    143 {
    144     disconnectConditions();
    145     if (m_timeContainer)
    146         m_timeContainer->unschedule(this);
    147 }
    148 
    149 void SVGSMILElement::insertedIntoDocument()
    150 {
    151     SVGElement::insertedIntoDocument();
    152 #ifndef NDEBUG
    153     // Verify we are not in <use> instance tree.
    154     for (Node* n = this; n; n = n->parent())
    155         ASSERT(!n->isShadowNode());
    156 #endif
    157     SVGSVGElement* owner = ownerSVGElement();
    158     if (!owner)
    159         return;
    160     m_timeContainer = owner->timeContainer();
    161     ASSERT(m_timeContainer);
    162     m_timeContainer->setDocumentOrderIndexesDirty();
    163     reschedule();
    164 }
    165 
    166 void SVGSMILElement::removedFromDocument()
    167 {
    168     if (m_timeContainer) {
    169         m_timeContainer->unschedule(this);
    170         m_timeContainer = 0;
    171     }
    172     // Calling disconnectConditions() may kill us if there are syncbase conditions.
    173     // OK, but we don't want to die inside the call.
    174     RefPtr<SVGSMILElement> keepAlive(this);
    175     disconnectConditions();
    176     SVGElement::removedFromDocument();
    177 }
    178 
    179 void SVGSMILElement::finishParsingChildren()
    180 {
    181     SVGElement::finishParsingChildren();
    182 
    183     // "If no attribute is present, the default begin value (an offset-value of 0) must be evaluated."
    184     if (!hasAttribute(SVGNames::beginAttr))
    185         m_beginTimes.append(0);
    186 
    187     if (m_isWaitingForFirstInterval) {
    188         resolveFirstInterval();
    189         reschedule();
    190     }
    191 }
    192 
    193 SMILTime SVGSMILElement::parseOffsetValue(const String& data)
    194 {
    195     bool ok;
    196     double result = 0;
    197     String parse = data.stripWhiteSpace();
    198     if (parse.endsWith("h"))
    199         result = parse.left(parse.length() - 1).toDouble(&ok) * 60 * 60;
    200     else if (parse.endsWith("min"))
    201         result = parse.left(parse.length() - 3).toDouble(&ok) * 60;
    202     else if (parse.endsWith("ms"))
    203         result = parse.left(parse.length() - 2).toDouble(&ok) / 1000;
    204     else if (parse.endsWith("s"))
    205         result = parse.left(parse.length() - 1).toDouble(&ok);
    206     else
    207         result = parse.toDouble(&ok);
    208     if (!ok)
    209         return SMILTime::unresolved();
    210     return result;
    211 }
    212 
    213 SMILTime SVGSMILElement::parseClockValue(const String& data)
    214 {
    215     if (data.isNull())
    216         return SMILTime::unresolved();
    217 
    218     String parse = data.stripWhiteSpace();
    219 
    220     DEFINE_STATIC_LOCAL(const AtomicString, indefiniteValue, ("indefinite"));
    221     if (parse == indefiniteValue)
    222         return SMILTime::indefinite();
    223 
    224     double result = 0;
    225     bool ok;
    226     int doublePointOne = parse.find(':');
    227     int doublePointTwo = parse.find(':', doublePointOne + 1);
    228     if (doublePointOne == 2 && doublePointTwo == 5 && parse.length() >= 8) {
    229         result += parse.substring(0, 2).toUIntStrict(&ok) * 60 * 60;
    230         if (!ok)
    231             return SMILTime::unresolved();
    232         result += parse.substring(3, 2).toUIntStrict(&ok) * 60;
    233         if (!ok)
    234             return SMILTime::unresolved();
    235         result += parse.substring(6).toDouble(&ok);
    236     } else if (doublePointOne == 2 && doublePointTwo == -1 && parse.length() >= 5) {
    237         result += parse.substring(0, 2).toUIntStrict(&ok) * 60;
    238         if (!ok)
    239             return SMILTime::unresolved();
    240         result += parse.substring(3).toDouble(&ok);
    241     } else
    242         return parseOffsetValue(parse);
    243 
    244     if (!ok)
    245         return SMILTime::unresolved();
    246     return result;
    247 }
    248 
    249 static void sortTimeList(Vector<SMILTime>& timeList)
    250 {
    251     std::sort(timeList.begin(), timeList.end());
    252 }
    253 
    254 bool SVGSMILElement::parseCondition(const String& value, BeginOrEnd beginOrEnd)
    255 {
    256     String parseString = value.stripWhiteSpace();
    257 
    258     double sign = 1.;
    259     bool ok;
    260     int pos = parseString.find('+');
    261     if (pos == -1) {
    262         pos = parseString.find('-');
    263         if (pos != -1)
    264             sign = -1.;
    265     }
    266     String conditionString;
    267     SMILTime offset = 0;
    268     if (pos == -1)
    269         conditionString = parseString;
    270     else {
    271         conditionString = parseString.left(pos).stripWhiteSpace();
    272         String offsetString = parseString.substring(pos + 1).stripWhiteSpace();
    273         offset = parseOffsetValue(offsetString);
    274         if (offset.isUnresolved())
    275             return false;
    276         offset = offset * sign;
    277     }
    278     if (conditionString.isEmpty())
    279         return false;
    280     pos = conditionString.find('.');
    281 
    282     String baseID;
    283     String nameString;
    284     if (pos == -1)
    285         nameString = conditionString;
    286     else {
    287         baseID = conditionString.left(pos);
    288         nameString = conditionString.substring(pos + 1);
    289     }
    290     if (nameString.isEmpty())
    291         return false;
    292 
    293     Condition::Type type;
    294     int repeats = -1;
    295     if (nameString.startsWith("repeat(") && nameString.endsWith(")")) {
    296         // FIXME: For repeat events we just need to add the data carrying TimeEvent class and
    297         // fire the events at appropiate times.
    298         repeats = nameString.substring(7, nameString.length() - 8).toUIntStrict(&ok);
    299         if (!ok)
    300             return false;
    301         nameString = "repeat";
    302         type = Condition::EventBase;
    303     } else if (nameString == "begin" || nameString == "end") {
    304         if (baseID.isEmpty())
    305             return false;
    306         type = Condition::Syncbase;
    307     } else if (nameString.startsWith("accesskey(")) {
    308         // FIXME: accesskey() support.
    309         type = Condition::AccessKey;
    310     } else
    311         type = Condition::EventBase;
    312 
    313     m_conditions.append(Condition(type, beginOrEnd, baseID, nameString, offset, repeats));
    314 
    315     if (type == Condition::EventBase && beginOrEnd == End)
    316         m_hasEndEventConditions = true;
    317 
    318     return true;
    319 }
    320 
    321 bool SVGSMILElement::isSMILElement(Node* node)
    322 {
    323     if (!node)
    324         return false;
    325     return node->hasTagName(SVGNames::setTag) || node->hasTagName(SVGNames::animateTag) || node->hasTagName(SVGNames::animateMotionTag)
    326             || node->hasTagName(SVGNames::animateTransformTag) || node->hasTagName(SVGNames::animateColorTag);
    327 }
    328 
    329 void SVGSMILElement::parseBeginOrEnd(const String& parseString, BeginOrEnd beginOrEnd)
    330 {
    331     Vector<SMILTime>& timeList = beginOrEnd == Begin ? m_beginTimes : m_endTimes;
    332     if (beginOrEnd == End)
    333         m_hasEndEventConditions = false;
    334     HashSet<double> existing;
    335     for (unsigned n = 0; n < timeList.size(); ++n)
    336         existing.add(timeList[n].value());
    337     Vector<String> splitString;
    338     parseString.split(';', splitString);
    339     for (unsigned n = 0; n < splitString.size(); ++n) {
    340         SMILTime value = parseClockValue(splitString[n]);
    341         if (value.isUnresolved())
    342             parseCondition(splitString[n], beginOrEnd);
    343         else if (!existing.contains(value.value()))
    344             timeList.append(value);
    345     }
    346     sortTimeList(timeList);
    347 }
    348 
    349 void SVGSMILElement::parseMappedAttribute(MappedAttribute* attr)
    350 {
    351     if (attr->name() == SVGNames::beginAttr) {
    352         if (!m_conditions.isEmpty()) {
    353             disconnectConditions();
    354             m_conditions.clear();
    355             parseBeginOrEnd(getAttribute(SVGNames::endAttr), End);
    356         }
    357         parseBeginOrEnd(attr->value().string(), Begin);
    358         if (inDocument())
    359             connectConditions();
    360     } else if (attr->name() == SVGNames::endAttr) {
    361         if (!m_conditions.isEmpty()) {
    362             disconnectConditions();
    363             m_conditions.clear();
    364             parseBeginOrEnd(getAttribute(SVGNames::beginAttr), Begin);
    365         }
    366         parseBeginOrEnd(attr->value().string(), End);
    367         if (inDocument())
    368             connectConditions();
    369     } else
    370         SVGElement::parseMappedAttribute(attr);
    371 }
    372 
    373 void SVGSMILElement::attributeChanged(Attribute* attr, bool preserveDecls)
    374 {
    375     SVGElement::attributeChanged(attr, preserveDecls);
    376 
    377     const QualifiedName& attrName = attr->name();
    378     if (attrName == SVGNames::durAttr)
    379         m_cachedDur = invalidCachedTime;
    380     else if (attrName == SVGNames::repeatDurAttr)
    381         m_cachedRepeatDur = invalidCachedTime;
    382     else if (attrName == SVGNames::repeatCountAttr)
    383         m_cachedRepeatCount = invalidCachedTime;
    384     else if (attrName == SVGNames::minAttr)
    385         m_cachedMin = invalidCachedTime;
    386     else if (attrName == SVGNames::maxAttr)
    387         m_cachedMax = invalidCachedTime;
    388 
    389     if (inDocument()) {
    390         if (attrName == SVGNames::beginAttr)
    391             beginListChanged();
    392         else if (attrName == SVGNames::endAttr)
    393             endListChanged();
    394     }
    395 }
    396 
    397 void SVGSMILElement::connectConditions()
    398 {
    399     if (m_conditionsConnected)
    400         disconnectConditions();
    401     m_conditionsConnected = true;
    402     for (unsigned n = 0; n < m_conditions.size(); ++n) {
    403         Condition& condition = m_conditions[n];
    404         if (condition.m_type == Condition::EventBase) {
    405             ASSERT(!condition.m_syncbase);
    406             Element* eventBase = condition.m_baseID.isEmpty() ? targetElement() : document()->getElementById(condition.m_baseID);
    407             if (!eventBase)
    408                 continue;
    409             ASSERT(!condition.m_eventListener);
    410             condition.m_eventListener = ConditionEventListener::create(this, eventBase, &condition);
    411         } else if (condition.m_type == Condition::Syncbase) {
    412             ASSERT(!condition.m_baseID.isEmpty());
    413             condition.m_syncbase = document()->getElementById(condition.m_baseID);
    414             if (!isSMILElement(condition.m_syncbase.get())) {
    415                 condition.m_syncbase = 0;
    416                 continue;
    417             }
    418             SVGSMILElement* syncbase = static_cast<SVGSMILElement*>(condition.m_syncbase.get());
    419             syncbase->addTimeDependent(this);
    420         }
    421     }
    422 }
    423 
    424 void SVGSMILElement::disconnectConditions()
    425 {
    426     if (!m_conditionsConnected)
    427         return;
    428     m_conditionsConnected = false;
    429     for (unsigned n = 0; n < m_conditions.size(); ++n) {
    430         Condition& condition = m_conditions[n];
    431         if (condition.m_type == Condition::EventBase) {
    432             ASSERT(!condition.m_syncbase);
    433             if (condition.m_eventListener) {
    434                 condition.m_eventListener->unregister();
    435                 condition.m_eventListener = 0;
    436             }
    437         } else if (condition.m_type == Condition::Syncbase) {
    438             if (condition.m_syncbase) {
    439                 ASSERT(isSMILElement(condition.m_syncbase.get()));
    440                 static_cast<SVGSMILElement*>(condition.m_syncbase.get())->removeTimeDependent(this);
    441             }
    442         }
    443         condition.m_syncbase = 0;
    444     }
    445 }
    446 
    447 void SVGSMILElement::reschedule()
    448 {
    449     if (m_timeContainer)
    450         m_timeContainer->schedule(this);
    451 }
    452 
    453 SVGElement* SVGSMILElement::targetElement() const
    454 {
    455     String href = xlinkHref();
    456     Node* target = href.isEmpty() ? parentNode() : document()->getElementById(SVGURIReference::getTarget(href));
    457     if (target && target->isSVGElement())
    458         return static_cast<SVGElement*>(target);
    459     return 0;
    460 }
    461 
    462 String SVGSMILElement::attributeName() const
    463 {
    464     return getAttribute(SVGNames::attributeNameAttr).string().stripWhiteSpace();
    465 }
    466 
    467 SMILTime SVGSMILElement::elapsed() const
    468 {
    469     return m_timeContainer ? m_timeContainer->elapsed() : 0;
    470 }
    471 
    472 bool SVGSMILElement::isInactive() const
    473 {
    474      return m_activeState == Inactive;
    475 }
    476 
    477 bool SVGSMILElement::isFrozen() const
    478 {
    479     return m_activeState == Frozen;
    480 }
    481 
    482 SVGSMILElement::Restart SVGSMILElement::restart() const
    483 {
    484     DEFINE_STATIC_LOCAL(const AtomicString, never, ("never"));
    485     DEFINE_STATIC_LOCAL(const AtomicString, whenNotActive, ("whenNotActive"));
    486     const AtomicString& value = getAttribute(SVGNames::restartAttr);
    487     if (value == never)
    488         return RestartNever;
    489     if (value == whenNotActive)
    490         return RestartWhenNotActive;
    491     return RestartAlways;
    492 }
    493 
    494 SVGSMILElement::FillMode SVGSMILElement::fill() const
    495 {
    496     DEFINE_STATIC_LOCAL(const AtomicString, freeze, ("freeze"));
    497     const AtomicString& value = getAttribute(SVGNames::fillAttr);
    498     return value == freeze ? FillFreeze : FillRemove;
    499 }
    500 
    501 String SVGSMILElement::xlinkHref() const
    502 {
    503     return getAttribute(XLinkNames::hrefAttr);
    504 }
    505 
    506 SMILTime SVGSMILElement::dur() const
    507 {
    508     if (m_cachedDur != invalidCachedTime)
    509         return m_cachedDur;
    510     const AtomicString& value = getAttribute(SVGNames::durAttr);
    511     SMILTime clockValue = parseClockValue(value);
    512     return m_cachedDur = clockValue <= 0 ? SMILTime::unresolved() : clockValue;
    513 }
    514 
    515 SMILTime SVGSMILElement::repeatDur() const
    516 {
    517     if (m_cachedRepeatDur != invalidCachedTime)
    518         return m_cachedRepeatDur;
    519     const AtomicString& value = getAttribute(SVGNames::repeatDurAttr);
    520     SMILTime clockValue = parseClockValue(value);
    521     return m_cachedRepeatDur = clockValue < 0 ? SMILTime::unresolved() : clockValue;
    522 }
    523 
    524 // So a count is not really a time but let just all pretend we did not notice.
    525 SMILTime SVGSMILElement::repeatCount() const
    526 {
    527     if (m_cachedRepeatCount != invalidCachedTime)
    528         return m_cachedRepeatCount;
    529     const AtomicString& value = getAttribute(SVGNames::repeatCountAttr);
    530     if (value.isNull())
    531         return SMILTime::unresolved();
    532 
    533     DEFINE_STATIC_LOCAL(const AtomicString, indefiniteValue, ("indefinite"));
    534     if (value == indefiniteValue)
    535         return SMILTime::indefinite();
    536     bool ok;
    537     double result = value.string().toDouble(&ok);
    538     return m_cachedRepeatCount = ok && result > 0 ? result : SMILTime::unresolved();
    539 }
    540 
    541 SMILTime SVGSMILElement::maxValue() const
    542 {
    543     if (m_cachedMax != invalidCachedTime)
    544         return m_cachedMax;
    545     const AtomicString& value = getAttribute(SVGNames::maxAttr);
    546     SMILTime result = parseClockValue(value);
    547     return m_cachedMax = (result.isUnresolved() || result < 0) ? SMILTime::indefinite() : result;
    548 }
    549 
    550 SMILTime SVGSMILElement::minValue() const
    551 {
    552     if (m_cachedMin != invalidCachedTime)
    553         return m_cachedMin;
    554     const AtomicString& value = getAttribute(SVGNames::minAttr);
    555     SMILTime result = parseClockValue(value);
    556     return m_cachedMin = (result.isUnresolved() || result < 0) ? 0 : result;
    557 }
    558 
    559 SMILTime SVGSMILElement::simpleDuration() const
    560 {
    561     return min(dur(), SMILTime::indefinite());
    562 }
    563 
    564 void SVGSMILElement::addBeginTime(SMILTime time)
    565 {
    566     m_beginTimes.append(time);
    567     sortTimeList(m_beginTimes);
    568     beginListChanged();
    569 }
    570 
    571 void SVGSMILElement::addEndTime(SMILTime time)
    572 {
    573     m_endTimes.append(time);
    574     sortTimeList(m_endTimes);
    575     endListChanged();
    576 }
    577 
    578 SMILTime SVGSMILElement::findInstanceTime(BeginOrEnd beginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const
    579 {
    580     // FIXME: This searches from the beginning which is inefficient. The list is usually not long
    581     // (one entry in common cases) but you can construct a case where it does grow.
    582     const Vector<SMILTime>& list = beginOrEnd == Begin ? m_beginTimes : m_endTimes;
    583     for (unsigned n = 0; n < list.size(); ++n) {
    584         SMILTime time = list[n];
    585         ASSERT(!time.isUnresolved());
    586         if (time.isIndefinite() && beginOrEnd == Begin) {
    587             // "The special value "indefinite" does not yield an instance time in the begin list."
    588             continue;
    589         }
    590         if (equalsMinimumOK) {
    591             if (time >= minimumTime)
    592                 return time;
    593         } else if (time > minimumTime)
    594             return time;
    595     }
    596     return SMILTime::unresolved();
    597 }
    598 
    599 SMILTime SVGSMILElement::repeatingDuration() const
    600 {
    601     // Computing the active duration
    602     // http://www.w3.org/TR/SMIL2/smil-timing.html#Timing-ComputingActiveDur
    603     SMILTime repeatCount = this->repeatCount();
    604     SMILTime repeatDur = this->repeatDur();
    605     SMILTime simpleDuration = this->simpleDuration();
    606     if (simpleDuration == 0 || (repeatDur.isUnresolved() && repeatCount.isUnresolved()))
    607         return simpleDuration;
    608     SMILTime repeatCountDuration = simpleDuration * repeatCount;
    609     return min(repeatCountDuration, min(repeatDur, SMILTime::indefinite()));
    610 }
    611 
    612 SMILTime SVGSMILElement::resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const
    613 {
    614     // Computing the active duration
    615     // http://www.w3.org/TR/SMIL2/smil-timing.html#Timing-ComputingActiveDur
    616     SMILTime preliminaryActiveDuration;
    617     if (!resolvedEnd.isUnresolved() && dur().isUnresolved() && repeatDur().isUnresolved() && repeatCount().isUnresolved())
    618         preliminaryActiveDuration = resolvedEnd - resolvedBegin;
    619     else if (!resolvedEnd.isFinite())
    620         preliminaryActiveDuration = repeatingDuration();
    621     else
    622         preliminaryActiveDuration = min(repeatingDuration(), resolvedEnd - resolvedBegin);
    623 
    624     SMILTime minValue = this->minValue();
    625     SMILTime maxValue = this->maxValue();
    626     if (minValue > maxValue) {
    627         // Ignore both.
    628         // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#MinMax
    629         minValue = 0;
    630         maxValue = SMILTime::indefinite();
    631     }
    632     return resolvedBegin + min(maxValue, max(minValue, preliminaryActiveDuration));
    633 }
    634 
    635 void SVGSMILElement::resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const
    636 {
    637     // See the pseudocode in
    638     // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LifeCycle
    639     SMILTime beginAfter = first ? -numeric_limits<double>::infinity() : m_intervalEnd;
    640     SMILTime lastIntervalTempEnd = numeric_limits<double>::infinity();
    641     while (true) {
    642         SMILTime tempBegin = findInstanceTime(Begin, beginAfter, true);
    643         if (tempBegin.isUnresolved())
    644             break;
    645         SMILTime tempEnd;
    646         if (m_endTimes.isEmpty())
    647             tempEnd = resolveActiveEnd(tempBegin, SMILTime::indefinite());
    648         else {
    649             tempEnd = findInstanceTime(End, tempBegin, true);
    650             if ((first && tempBegin == tempEnd && tempEnd == lastIntervalTempEnd) || (!first && tempEnd == m_intervalEnd))
    651                 tempEnd = findInstanceTime(End, tempBegin, false);
    652             if (tempEnd.isUnresolved()) {
    653                 if (!m_endTimes.isEmpty() && !m_hasEndEventConditions)
    654                     break;
    655             }
    656             tempEnd = resolveActiveEnd(tempBegin, tempEnd);
    657         }
    658         if (tempEnd > 0 || !first) {
    659             beginResult = tempBegin;
    660             endResult = tempEnd;
    661             return;
    662         } else if (restart() == RestartNever)
    663             break;
    664         else
    665             beginAfter = tempEnd;
    666         lastIntervalTempEnd = tempEnd;
    667     }
    668     beginResult = SMILTime::unresolved();
    669     endResult = SMILTime::unresolved();
    670 }
    671 
    672 void SVGSMILElement::resolveFirstInterval()
    673 {
    674     SMILTime begin;
    675     SMILTime end;
    676     resolveInterval(true, begin, end);
    677     ASSERT(!begin.isIndefinite());
    678 
    679     if (!begin.isUnresolved() && (begin != m_intervalBegin || end != m_intervalEnd)) {
    680         bool wasUnresolved = m_intervalBegin.isUnresolved();
    681         m_intervalBegin = begin;
    682         m_intervalEnd = end;
    683         notifyDependentsIntervalChanged(wasUnresolved ? NewInterval : ExistingInterval);
    684         m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
    685         reschedule();
    686     }
    687 }
    688 
    689 void SVGSMILElement::resolveNextInterval()
    690 {
    691     SMILTime begin;
    692     SMILTime end;
    693     resolveInterval(false, begin, end);
    694     ASSERT(!begin.isIndefinite());
    695 
    696     if (!begin.isUnresolved() && begin != m_intervalBegin) {
    697         m_intervalBegin = begin;
    698         m_intervalEnd = end;
    699         notifyDependentsIntervalChanged(NewInterval);
    700         m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
    701     }
    702 }
    703 
    704 SMILTime SVGSMILElement::nextProgressTime() const
    705 {
    706     return m_nextProgressTime;
    707 }
    708 
    709 void SVGSMILElement::beginListChanged()
    710 {
    711     SMILTime elapsed = this->elapsed();
    712     if (m_isWaitingForFirstInterval)
    713         resolveFirstInterval();
    714     else if (elapsed < m_intervalBegin) {
    715         SMILTime newBegin = findInstanceTime(Begin, elapsed, false);
    716         if (newBegin < m_intervalBegin) {
    717             // Begin time changed, re-resolve the interval.
    718             SMILTime oldBegin = m_intervalBegin;
    719             m_intervalBegin = elapsed;
    720             resolveInterval(false, m_intervalBegin, m_intervalEnd);
    721             ASSERT(!m_intervalBegin.isUnresolved());
    722             if (m_intervalBegin != oldBegin)
    723                 notifyDependentsIntervalChanged(ExistingInterval);
    724         }
    725     }
    726     m_nextProgressTime = elapsed;
    727     reschedule();
    728 }
    729 
    730 void SVGSMILElement::endListChanged()
    731 {
    732     SMILTime elapsed = this->elapsed();
    733     if (m_isWaitingForFirstInterval)
    734         resolveFirstInterval();
    735     else if (elapsed < m_intervalEnd && m_intervalBegin.isFinite()) {
    736         SMILTime newEnd = findInstanceTime(End, m_intervalBegin, false);
    737         if (newEnd < m_intervalEnd) {
    738             newEnd = resolveActiveEnd(m_intervalBegin, newEnd);
    739             if (newEnd != m_intervalEnd) {
    740                 m_intervalEnd = newEnd;
    741                 notifyDependentsIntervalChanged(ExistingInterval);
    742             }
    743         }
    744     }
    745     m_nextProgressTime = elapsed;
    746     reschedule();
    747 }
    748 
    749 void SVGSMILElement::checkRestart(SMILTime elapsed)
    750 {
    751     ASSERT(!m_isWaitingForFirstInterval);
    752     ASSERT(elapsed >= m_intervalBegin);
    753 
    754     Restart restart = this->restart();
    755     if (restart == RestartNever)
    756         return;
    757 
    758     if (elapsed < m_intervalEnd) {
    759         if (restart != RestartAlways)
    760             return;
    761         SMILTime nextBegin = findInstanceTime(Begin, m_intervalBegin, false);
    762         if (nextBegin < m_intervalEnd) {
    763             m_intervalEnd = nextBegin;
    764             notifyDependentsIntervalChanged(ExistingInterval);
    765         }
    766     }
    767     if (elapsed >= m_intervalEnd)
    768         resolveNextInterval();
    769 }
    770 
    771 float SVGSMILElement::calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const
    772 {
    773     SMILTime simpleDuration = this->simpleDuration();
    774     repeat = 0;
    775     if (simpleDuration.isIndefinite()) {
    776         repeat = 0;
    777         return 0.f;
    778     }
    779     if (simpleDuration == 0) {
    780         repeat = 0;
    781         return 1.f;
    782     }
    783     ASSERT(m_intervalBegin.isFinite());
    784     ASSERT(simpleDuration.isFinite());
    785     SMILTime activeTime = elapsed - m_intervalBegin;
    786     SMILTime repeatingDuration = this->repeatingDuration();
    787     if (elapsed >= m_intervalEnd || activeTime > repeatingDuration) {
    788         repeat = static_cast<unsigned>(repeatingDuration.value() / simpleDuration.value());
    789         if (fmod(repeatingDuration.value(), simpleDuration.value() == 0.))
    790             repeat--;
    791         return 1.f;
    792     }
    793     repeat = static_cast<unsigned>(activeTime.value() / simpleDuration.value());
    794     SMILTime simpleTime = fmod(activeTime.value(), simpleDuration.value());
    795     return narrowPrecisionToFloat(simpleTime.value() / simpleDuration.value());
    796 }
    797 
    798 SMILTime SVGSMILElement::calculateNextProgressTime(SMILTime elapsed) const
    799 {
    800     if (m_activeState == Active) {
    801         // If duration is indefinite the value does not actually change over time. Same is true for <set>.
    802         SMILTime simpleDuration = this->simpleDuration();
    803         if (simpleDuration.isIndefinite() || hasTagName(SVGNames::setTag)) {
    804             SMILTime repeatCount = this->repeatCount();
    805             SMILTime repeatingDurationEnd = m_intervalBegin + repeatingDuration();
    806             // We are supposed to do freeze semantics when repeating ends, even if the element is still active.
    807             // Take care that we get a timer callback at that point.
    808             if (elapsed < repeatingDurationEnd && repeatingDurationEnd < m_intervalEnd && repeatingDurationEnd.isFinite())
    809                 return repeatingDurationEnd;
    810             return m_intervalEnd;
    811         }
    812         return elapsed + 0.025;
    813     }
    814     return m_intervalBegin >= elapsed ? m_intervalBegin : SMILTime::unresolved();
    815 }
    816 
    817 SVGSMILElement::ActiveState SVGSMILElement::determineActiveState(SMILTime elapsed) const
    818 {
    819     if (elapsed >= m_intervalBegin && elapsed < m_intervalEnd)
    820         return Active;
    821 
    822     if (m_activeState == Active)
    823         return fill() == FillFreeze ? Frozen : Inactive;
    824 
    825     return m_activeState;
    826 }
    827 
    828 bool SVGSMILElement::isContributing(SMILTime elapsed) const
    829 {
    830     // Animation does not contribute during the active time if it is past its repeating duration and has fill=remove.
    831     return (m_activeState == Active && (fill() == FillFreeze || elapsed <= m_intervalBegin + repeatingDuration())) || m_activeState == Frozen;
    832 }
    833 
    834 void SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement)
    835 {
    836     ASSERT(m_timeContainer);
    837     ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
    838 
    839     if (!m_conditionsConnected)
    840         connectConditions();
    841 
    842     if (!m_intervalBegin.isFinite()) {
    843         ASSERT(m_activeState == Inactive);
    844         m_nextProgressTime = SMILTime::unresolved();
    845         return;
    846     }
    847 
    848     if (elapsed < m_intervalBegin) {
    849         ASSERT(m_activeState != Active);
    850         if (m_activeState == Frozen && resultElement)
    851             updateAnimation(m_lastPercent, m_lastRepeat, resultElement);
    852         m_nextProgressTime = m_intervalBegin;
    853         return;
    854     }
    855 
    856     m_previousIntervalBegin = m_intervalBegin;
    857 
    858     if (m_activeState == Inactive) {
    859         m_isWaitingForFirstInterval = false;
    860         m_activeState = Active;
    861         startedActiveInterval();
    862     }
    863 
    864     unsigned repeat;
    865     float percent = calculateAnimationPercentAndRepeat(elapsed, repeat);
    866 
    867     checkRestart(elapsed);
    868 
    869     ActiveState oldActiveState = m_activeState;
    870     m_activeState = determineActiveState(elapsed);
    871 
    872     if (isContributing(elapsed)) {
    873         if (resultElement)
    874             updateAnimation(percent, repeat, resultElement);
    875         m_lastPercent = percent;
    876         m_lastRepeat = repeat;
    877     }
    878 
    879     if (oldActiveState == Active && m_activeState != Active)
    880         endedActiveInterval();
    881 
    882     m_nextProgressTime = calculateNextProgressTime(elapsed);
    883 }
    884 
    885 void SVGSMILElement::notifyDependentsIntervalChanged(NewOrExistingInterval newOrExisting)
    886 {
    887     ASSERT(m_intervalBegin.isFinite());
    888     DEFINE_STATIC_LOCAL(HashSet<SVGSMILElement*>, loopBreaker, ());
    889     if (loopBreaker.contains(this))
    890         return;
    891     loopBreaker.add(this);
    892 
    893     TimeDependentSet::iterator end = m_timeDependents.end();
    894     for (TimeDependentSet::iterator it = m_timeDependents.begin(); it != end; ++it) {
    895         SVGSMILElement* dependent = *it;
    896         dependent->createInstanceTimesFromSyncbase(this, newOrExisting);
    897     }
    898 
    899     loopBreaker.remove(this);
    900 }
    901 
    902 void SVGSMILElement::createInstanceTimesFromSyncbase(SVGSMILElement* syncbase, NewOrExistingInterval)
    903 {
    904     // FIXME: To be really correct, this should handle updating exising interval by changing
    905     // the associated times instead of creating new ones.
    906     for (unsigned n = 0; n < m_conditions.size(); ++n) {
    907         Condition& condition = m_conditions[n];
    908         if (condition.m_type == Condition::Syncbase && condition.m_syncbase == syncbase) {
    909             ASSERT(condition.m_name == "begin" || condition.m_name == "end");
    910             // No nested time containers in SVG, no need for crazy time space conversions. Phew!
    911             SMILTime time = 0;
    912             if (condition.m_name == "begin")
    913                 time = syncbase->m_intervalBegin + condition.m_offset;
    914             else
    915                 time = syncbase->m_intervalEnd + condition.m_offset;
    916             ASSERT(time.isFinite());
    917             if (condition.m_beginOrEnd == Begin)
    918                 addBeginTime(time);
    919             else
    920                 addEndTime(time);
    921         }
    922     }
    923 }
    924 
    925 void SVGSMILElement::addTimeDependent(SVGSMILElement* animation)
    926 {
    927     m_timeDependents.add(animation);
    928     if (m_intervalBegin.isFinite())
    929         animation->createInstanceTimesFromSyncbase(this, NewInterval);
    930 }
    931 
    932 void SVGSMILElement::removeTimeDependent(SVGSMILElement* animation)
    933 {
    934     m_timeDependents.remove(animation);
    935 }
    936 
    937 void SVGSMILElement::handleConditionEvent(Event*, Condition* condition)
    938 {
    939     if (condition->m_beginOrEnd == Begin)
    940         addBeginTime(elapsed() + condition->m_offset);
    941     else
    942         addEndTime(elapsed() + condition->m_offset);
    943 }
    944 
    945 void SVGSMILElement::beginByLinkActivation()
    946 {
    947     addBeginTime(elapsed());
    948 }
    949 
    950 }
    951 
    952 #endif
    953 
    954