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