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