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