Replace static_cast<SVGStyledElement> with toSVGStyledElement()
[WebKit-https.git] / Source / WebCore / svg / SVGAnimationElement.cpp
1 /*
2  * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2008 Apple Inc. All rights reserved.
6  * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
7  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "config.h"
26
27 #if ENABLE(SVG)
28 #include "SVGAnimationElement.h"
29
30 #include "Attribute.h"
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSParser.h"
33 #include "CSSPropertyNames.h"
34 #include "Document.h"
35 #include "FloatConversion.h"
36 #include "RenderObject.h"
37 #include "SVGAnimateElement.h"
38 #include "SVGElementInstance.h"
39 #include "SVGNames.h"
40 #include "SVGParserUtilities.h"
41 #include "SVGStyledElement.h"
42 #include <wtf/MathExtras.h>
43
44 namespace WebCore {
45
46 // Animated property definitions
47 DEFINE_ANIMATED_BOOLEAN(SVGAnimationElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
48
49 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGAnimationElement)
50     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
51     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
52 END_REGISTER_ANIMATED_PROPERTIES
53
54 SVGAnimationElement::SVGAnimationElement(const QualifiedName& tagName, Document* document)
55     : SVGSMILElement(tagName, document)
56     , m_fromPropertyValueType(RegularPropertyValue)
57     , m_toPropertyValueType(RegularPropertyValue)
58     , m_animationValid(false)
59     , m_attributeType(AttributeTypeAuto)
60     , m_hasInvalidCSSAttributeType(false)
61     , m_calcMode(CalcModeLinear)
62     , m_animationMode(NoAnimation)
63 {
64     registerAnimatedPropertiesForSVGAnimationElement();
65 }
66
67 static void parseKeyTimes(const String& parse, Vector<float>& result, bool verifyOrder)
68 {
69     result.clear();
70     Vector<String> parseList;
71     parse.split(';', parseList);
72     for (unsigned n = 0; n < parseList.size(); ++n) {
73         String timeString = parseList[n];
74         bool ok;
75         float time = timeString.toFloat(&ok);
76         if (!ok || time < 0 || time > 1)
77             goto fail;
78         if (verifyOrder) {
79             if (!n) {
80                 if (time)
81                     goto fail;
82             } else if (time < result.last())
83                 goto fail;
84         }
85         result.append(time);
86     }
87     return;
88 fail:
89     result.clear();
90 }
91
92 static void parseKeySplines(const String& parse, Vector<UnitBezier>& result)
93 {
94     result.clear();
95     if (parse.isEmpty())
96         return;
97     const UChar* cur = parse.characters();
98     const UChar* end = cur + parse.length();
99
100     skipOptionalSVGSpaces(cur, end);
101
102     bool delimParsed = false;
103     while (cur < end) {
104         delimParsed = false;
105         float posA = 0;
106         if (!parseNumber(cur, end, posA)) {
107             result.clear();
108             return;
109         }
110
111         float posB = 0;
112         if (!parseNumber(cur, end, posB)) {
113             result.clear();
114             return;
115         }
116
117         float posC = 0;
118         if (!parseNumber(cur, end, posC)) {
119             result.clear();
120             return;
121         }
122
123         float posD = 0;
124         if (!parseNumber(cur, end, posD, false)) {
125             result.clear();
126             return;
127         }
128
129         skipOptionalSVGSpaces(cur, end);
130
131         if (cur < end && *cur == ';') {
132             delimParsed = true;
133             cur++;
134         }
135         skipOptionalSVGSpaces(cur, end);
136
137         result.append(UnitBezier(posA, posB, posC, posD));
138     }
139     if (!(cur == end && !delimParsed))
140         result.clear();
141 }
142
143 bool SVGAnimationElement::isSupportedAttribute(const QualifiedName& attrName)
144 {
145     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
146     if (supportedAttributes.isEmpty()) {
147         SVGTests::addSupportedAttributes(supportedAttributes);
148         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
149         supportedAttributes.add(SVGNames::valuesAttr);
150         supportedAttributes.add(SVGNames::keyTimesAttr);
151         supportedAttributes.add(SVGNames::keyPointsAttr);
152         supportedAttributes.add(SVGNames::keySplinesAttr);
153         supportedAttributes.add(SVGNames::attributeTypeAttr);
154         supportedAttributes.add(SVGNames::calcModeAttr);
155         supportedAttributes.add(SVGNames::fromAttr);
156         supportedAttributes.add(SVGNames::toAttr);
157         supportedAttributes.add(SVGNames::byAttr);
158     }
159     return supportedAttributes.contains<QualifiedName, SVGAttributeHashTranslator>(attrName);
160 }
161
162 void SVGAnimationElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
163 {
164     if (!isSupportedAttribute(name)) {
165         SVGSMILElement::parseAttribute(name, value);
166         return;
167     }
168
169     if (name == SVGNames::valuesAttr) {
170         // Per the SMIL specification, leading and trailing white space,
171         // and white space before and after semicolon separators, is allowed and will be ignored.
172         // http://www.w3.org/TR/SVG11/animate.html#ValuesAttribute
173         value.string().split(';', m_values);
174         for (unsigned i = 0; i < m_values.size(); ++i)
175             m_values[i] = m_values[i].stripWhiteSpace();
176
177         updateAnimationMode();
178         return;
179     }
180
181     if (name == SVGNames::keyTimesAttr) {
182         parseKeyTimes(value, m_keyTimes, true);
183         return;
184     }
185
186     if (name == SVGNames::keyPointsAttr) {
187         if (hasTagName(SVGNames::animateMotionTag)) {
188             // This is specified to be an animateMotion attribute only but it is simpler to put it here 
189             // where the other timing calculatations are.
190             parseKeyTimes(value, m_keyPoints, false);
191         }
192         return;
193     }
194
195     if (name == SVGNames::keySplinesAttr) {
196         parseKeySplines(value, m_keySplines);
197         return;
198     }
199
200     if (name == SVGNames::attributeTypeAttr) {
201         setAttributeType(value);
202         return;
203     }
204
205     if (name == SVGNames::calcModeAttr) {
206         setCalcMode(value);
207         return;
208     }
209
210     if (name == SVGNames::fromAttr || name == SVGNames::toAttr || name == SVGNames::byAttr) {
211         updateAnimationMode();
212         return;
213     }
214
215     if (SVGTests::parseAttribute(name, value))
216         return;
217     if (SVGExternalResourcesRequired::parseAttribute(name, value))
218         return;
219
220     ASSERT_NOT_REACHED();
221 }
222
223 void SVGAnimationElement::svgAttributeChanged(const QualifiedName& attrName)
224 {
225     if (!isSupportedAttribute(attrName)) {
226         SVGSMILElement::svgAttributeChanged(attrName);
227         return;
228     }
229
230     animationAttributeChanged();
231 }
232
233 void SVGAnimationElement::animationAttributeChanged()
234 {
235     // Assumptions may not hold after an attribute change.
236     m_animationValid = false;
237     setInactive();
238 }
239
240 float SVGAnimationElement::getStartTime() const
241 {
242     return narrowPrecisionToFloat(intervalBegin().value());
243 }
244
245 float SVGAnimationElement::getCurrentTime() const
246 {
247     return narrowPrecisionToFloat(elapsed().value());
248 }
249
250 float SVGAnimationElement::getSimpleDuration(ExceptionCode&) const
251 {
252     return narrowPrecisionToFloat(simpleDuration().value());
253 }    
254     
255 void SVGAnimationElement::beginElement()
256 {
257     beginElementAt(0);
258 }
259
260 void SVGAnimationElement::beginElementAt(float offset)
261 {
262     if (std::isnan(offset))
263         return;
264     SMILTime elapsed = this->elapsed();
265     addBeginTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin);
266 }
267
268 void SVGAnimationElement::endElement()
269 {
270     endElementAt(0);
271 }
272
273 void SVGAnimationElement::endElementAt(float offset)
274 {
275     if (std::isnan(offset))
276         return;
277     SMILTime elapsed = this->elapsed();
278     addEndTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin);
279 }
280
281 void SVGAnimationElement::updateAnimationMode()
282 {
283     // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#AnimFuncValues
284     if (hasAttribute(SVGNames::valuesAttr))
285         setAnimationMode(ValuesAnimation);
286     else if (!toValue().isEmpty())
287         setAnimationMode(fromValue().isEmpty() ? ToAnimation : FromToAnimation);
288     else if (!byValue().isEmpty())
289         setAnimationMode(fromValue().isEmpty() ? ByAnimation : FromByAnimation);
290     else
291         setAnimationMode(NoAnimation);
292 }
293
294 void SVGAnimationElement::setCalcMode(const AtomicString& calcMode)
295 {
296     DEFINE_STATIC_LOCAL(const AtomicString, discrete, ("discrete", AtomicString::ConstructFromLiteral));
297     DEFINE_STATIC_LOCAL(const AtomicString, linear, ("linear", AtomicString::ConstructFromLiteral));
298     DEFINE_STATIC_LOCAL(const AtomicString, paced, ("paced", AtomicString::ConstructFromLiteral));
299     DEFINE_STATIC_LOCAL(const AtomicString, spline, ("spline", AtomicString::ConstructFromLiteral));
300     if (calcMode == discrete)
301         setCalcMode(CalcModeDiscrete);
302     else if (calcMode == linear)
303         setCalcMode(CalcModeLinear);
304     else if (calcMode == paced)
305         setCalcMode(CalcModePaced);
306     else if (calcMode == spline)
307         setCalcMode(CalcModeSpline);
308     else
309         setCalcMode(hasTagName(SVGNames::animateMotionTag) ? CalcModePaced : CalcModeLinear);
310 }
311
312 void SVGAnimationElement::setAttributeType(const AtomicString& attributeType)
313 {
314     DEFINE_STATIC_LOCAL(const AtomicString, css, ("CSS", AtomicString::ConstructFromLiteral));
315     DEFINE_STATIC_LOCAL(const AtomicString, xml, ("XML", AtomicString::ConstructFromLiteral));
316     if (attributeType == css)
317         m_attributeType = AttributeTypeCSS;
318     else if (attributeType == xml)
319         m_attributeType = AttributeTypeXML;
320     else
321         m_attributeType = AttributeTypeAuto;
322     checkInvalidCSSAttributeType(targetElement());
323 }
324
325 String SVGAnimationElement::toValue() const
326 {    
327     return fastGetAttribute(SVGNames::toAttr);
328 }
329
330 String SVGAnimationElement::byValue() const
331 {    
332     return fastGetAttribute(SVGNames::byAttr);
333 }
334
335 String SVGAnimationElement::fromValue() const
336 {    
337     return fastGetAttribute(SVGNames::fromAttr);
338 }
339
340 bool SVGAnimationElement::isAdditive() const
341 {
342     DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum", AtomicString::ConstructFromLiteral));
343     const AtomicString& value = fastGetAttribute(SVGNames::additiveAttr);
344     return value == sum || animationMode() == ByAnimation;
345 }
346
347 bool SVGAnimationElement::isAccumulated() const
348 {
349     DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum", AtomicString::ConstructFromLiteral));
350     const AtomicString& value = fastGetAttribute(SVGNames::accumulateAttr);
351     return value == sum && animationMode() != ToAnimation;
352 }
353
354 bool SVGAnimationElement::isTargetAttributeCSSProperty(SVGElement* targetElement, const QualifiedName& attributeName)
355 {
356     ASSERT(targetElement);
357     if (!targetElement->isSVGStyledElement())
358         return false;
359
360     return SVGStyledElement::isAnimatableCSSProperty(attributeName);
361 }
362
363 SVGAnimationElement::ShouldApplyAnimation SVGAnimationElement::shouldApplyAnimation(SVGElement* targetElement, const QualifiedName& attributeName)
364 {
365     if (!hasValidAttributeType() || !targetElement || attributeName == anyQName())
366         return DontApplyAnimation;
367
368     // Always animate CSS properties, using the ApplyCSSAnimation code path, regardless of the attributeType value.
369     if (isTargetAttributeCSSProperty(targetElement, attributeName))
370         return ApplyCSSAnimation;
371
372     // If attributeType="CSS" and attributeName doesn't point to a CSS property, ignore the animation.
373     if (attributeType() == AttributeTypeCSS)
374         return DontApplyAnimation;
375
376     return ApplyXMLAnimation;
377 }
378
379 void SVGAnimationElement::calculateKeyTimesForCalcModePaced()
380 {
381     ASSERT(calcMode() == CalcModePaced);
382     ASSERT(animationMode() == ValuesAnimation);
383
384     unsigned valuesCount = m_values.size();
385     ASSERT(valuesCount >= 1);
386     if (valuesCount == 1)
387         return;
388
389     // FIXME, webkit.org/b/109010: m_keyTimes should not be modified in this function.
390     m_keyTimes.clear();
391
392     Vector<float> keyTimesForPaced;
393     float totalDistance = 0;
394     keyTimesForPaced.append(0);
395     for (unsigned n = 0; n < valuesCount - 1; ++n) {
396         // Distance in any units
397         float distance = calculateDistance(m_values[n], m_values[n + 1]);
398         if (distance < 0)
399             return;
400         totalDistance += distance;
401         keyTimesForPaced.append(distance);
402     }
403     if (!totalDistance)
404         return;
405
406     // Normalize.
407     for (unsigned n = 1; n < keyTimesForPaced.size() - 1; ++n)
408         keyTimesForPaced[n] = keyTimesForPaced[n - 1] + keyTimesForPaced[n] / totalDistance;
409     keyTimesForPaced[keyTimesForPaced.size() - 1] = 1;
410
411     // Use key times calculated based on pacing instead of the user provided ones.
412     m_keyTimes = keyTimesForPaced;
413 }
414
415 static inline double solveEpsilon(double duration) { return 1 / (200 * duration); }
416
417 unsigned SVGAnimationElement::calculateKeyTimesIndex(float percent) const
418 {
419     unsigned index;
420     unsigned keyTimesCount = m_keyTimes.size();
421     // Compare index + 1 to keyTimesCount because the last keyTimes entry is
422     // required to be 1, and percent can never exceed 1; i.e., the second last
423     // keyTimes entry defines the beginning of the final interval
424     for (index = 1; index + 1 < keyTimesCount; ++index) {
425         if (m_keyTimes[index] > percent)
426             break;
427     }
428     return --index;
429 }
430
431 float SVGAnimationElement::calculatePercentForSpline(float percent, unsigned splineIndex) const
432 {
433     ASSERT(calcMode() == CalcModeSpline);
434     ASSERT_WITH_SECURITY_IMPLICATION(splineIndex < m_keySplines.size());
435     UnitBezier bezier = m_keySplines[splineIndex];
436     SMILTime duration = simpleDuration();
437     if (!duration.isFinite())
438         duration = 100.0;
439     return narrowPrecisionToFloat(bezier.solve(percent, solveEpsilon(duration.value())));
440 }
441
442 float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const
443 {
444     ASSERT(!m_keyPoints.isEmpty());
445     ASSERT(calcMode() != CalcModePaced);
446     ASSERT(m_keyTimes.size() > 1);
447     ASSERT(m_keyPoints.size() == m_keyTimes.size());
448
449     if (percent == 1)
450         return m_keyPoints[m_keyPoints.size() - 1];
451
452     unsigned index = calculateKeyTimesIndex(percent);
453     float fromPercent = m_keyTimes[index];
454     float toPercent = m_keyTimes[index + 1];
455     float fromKeyPoint = m_keyPoints[index];
456     float toKeyPoint = m_keyPoints[index + 1];
457     
458     if (calcMode() == CalcModeDiscrete)
459         return fromKeyPoint;
460     
461     float keyPointPercent = (percent - fromPercent) / (toPercent - fromPercent);
462     
463     if (calcMode() == CalcModeSpline) {
464         ASSERT(m_keySplines.size() == m_keyPoints.size() - 1);
465         keyPointPercent = calculatePercentForSpline(keyPointPercent, index);
466     }
467     return (toKeyPoint - fromKeyPoint) * keyPointPercent + fromKeyPoint;
468 }
469
470 float SVGAnimationElement::calculatePercentForFromTo(float percent) const
471 {
472     if (calcMode() == CalcModeDiscrete && m_keyTimes.size() == 2)
473         return percent > m_keyTimes[1] ? 1 : 0;
474
475     return percent;
476 }
477     
478 void SVGAnimationElement::currentValuesFromKeyPoints(float percent, float& effectivePercent, String& from, String& to) const
479 {
480     ASSERT(!m_keyPoints.isEmpty());
481     ASSERT(m_keyPoints.size() == m_keyTimes.size());
482     ASSERT(calcMode() != CalcModePaced);
483     effectivePercent = calculatePercentFromKeyPoints(percent);
484     unsigned index = effectivePercent == 1 ? m_values.size() - 2 : static_cast<unsigned>(effectivePercent * (m_values.size() - 1));
485     from = m_values[index];
486     to = m_values[index + 1];
487 }
488     
489 void SVGAnimationElement::currentValuesForValuesAnimation(float percent, float& effectivePercent, String& from, String& to)
490 {
491     unsigned valuesCount = m_values.size();
492     ASSERT(m_animationValid);
493     ASSERT(valuesCount >= 1);
494
495     if (percent == 1 || valuesCount == 1) {
496         from = m_values[valuesCount - 1];
497         to = m_values[valuesCount - 1];
498         effectivePercent = 1;
499         return;
500     }
501
502     CalcMode calcMode = this->calcMode();
503     if (hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::animateColorTag)) {
504         SVGAnimateElement* animateElement = static_cast<SVGAnimateElement*>(this);
505         AnimatedPropertyType attributeType = animateElement->determineAnimatedPropertyType(targetElement());
506         // Fall back to discrete animations for Strings.
507         if (attributeType == AnimatedBoolean
508             || attributeType == AnimatedEnumeration
509             || attributeType == AnimatedPreserveAspectRatio
510             || attributeType == AnimatedString)
511             calcMode = CalcModeDiscrete;
512     }
513     if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced)
514         return currentValuesFromKeyPoints(percent, effectivePercent, from, to);
515     
516     unsigned keyTimesCount = m_keyTimes.size();
517     ASSERT(!keyTimesCount || valuesCount == keyTimesCount);
518     ASSERT(!keyTimesCount || (keyTimesCount > 1 && !m_keyTimes[0]));
519
520     unsigned index = calculateKeyTimesIndex(percent);
521     if (calcMode == CalcModeDiscrete) {
522         if (!keyTimesCount) 
523             index = static_cast<unsigned>(percent * valuesCount);
524         from = m_values[index];
525         to = m_values[index];
526         effectivePercent = 0;
527         return;
528     }
529     
530     float fromPercent;
531     float toPercent;
532     if (keyTimesCount) {
533         fromPercent = m_keyTimes[index];
534         toPercent = m_keyTimes[index + 1];
535     } else {        
536         index = static_cast<unsigned>(floorf(percent * (valuesCount - 1)));
537         fromPercent =  static_cast<float>(index) / (valuesCount - 1);
538         toPercent =  static_cast<float>(index + 1) / (valuesCount - 1);
539     }
540     
541     if (index == valuesCount - 1)
542         --index;
543     from = m_values[index];
544     to = m_values[index + 1];
545     ASSERT(toPercent > fromPercent);
546     effectivePercent = (percent - fromPercent) / (toPercent - fromPercent);
547
548     if (calcMode == CalcModeSpline) {
549         ASSERT(m_keySplines.size() == m_values.size() - 1);
550         effectivePercent = calculatePercentForSpline(effectivePercent, index);
551     }
552 }
553     
554 void SVGAnimationElement::startedActiveInterval()
555 {
556     m_animationValid = false;
557
558     if (!hasValidAttributeType())
559         return;
560
561     // These validations are appropriate for all animation modes.
562     if (fastHasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() != m_keyTimes.size())
563         return;
564
565     AnimationMode animationMode = this->animationMode();
566     CalcMode calcMode = this->calcMode();
567     if (calcMode == CalcModeSpline) {
568         unsigned splinesCount = m_keySplines.size() + 1;
569         if ((fastHasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() != splinesCount)
570             || (animationMode == ValuesAnimation && m_values.size() != splinesCount)
571             || (fastHasAttribute(SVGNames::keyTimesAttr) && m_keyTimes.size() != splinesCount))
572             return;
573     }
574
575     String from = fromValue();
576     String to = toValue();
577     String by = byValue();
578     if (animationMode == NoAnimation)
579         return;
580     if (animationMode == FromToAnimation)
581         m_animationValid = calculateFromAndToValues(from, to);
582     else if (animationMode == ToAnimation) {
583         // For to-animations the from value is the current accumulated value from lower priority animations.
584         // The value is not static and is determined during the animation.
585         m_animationValid = calculateFromAndToValues(emptyString(), to);
586     } else if (animationMode == FromByAnimation)
587         m_animationValid = calculateFromAndByValues(from, by);
588     else if (animationMode == ByAnimation)
589         m_animationValid = calculateFromAndByValues(emptyString(), by);
590     else if (animationMode == ValuesAnimation) {
591         m_animationValid = m_values.size() >= 1
592             && (calcMode == CalcModePaced || !fastHasAttribute(SVGNames::keyTimesAttr) || fastHasAttribute(SVGNames::keyPointsAttr) || (m_values.size() == m_keyTimes.size()))
593             && (calcMode == CalcModeDiscrete || !m_keyTimes.size() || m_keyTimes.last() == 1)
594             && (calcMode != CalcModeSpline || ((m_keySplines.size() && (m_keySplines.size() == m_values.size() - 1)) || m_keySplines.size() == m_keyPoints.size() - 1))
595             && (!fastHasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size()));
596         if (m_animationValid)
597             m_animationValid = calculateToAtEndOfDurationValue(m_values.last());
598         if (calcMode == CalcModePaced && m_animationValid)
599             calculateKeyTimesForCalcModePaced();
600     } else if (animationMode == PathAnimation)
601         m_animationValid = calcMode == CalcModePaced || !fastHasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size());
602 }
603
604 void SVGAnimationElement::updateAnimation(float percent, unsigned repeatCount, SVGSMILElement* resultElement)
605 {    
606     if (!m_animationValid)
607         return;
608
609     float effectivePercent;
610     CalcMode calcMode = this->calcMode();
611     AnimationMode animationMode = this->animationMode();
612     if (animationMode == ValuesAnimation) {
613         String from;
614         String to;
615         currentValuesForValuesAnimation(percent, effectivePercent, from, to);
616         if (from != m_lastValuesAnimationFrom || to != m_lastValuesAnimationTo) {
617             m_animationValid = calculateFromAndToValues(from, to);
618             if (!m_animationValid)
619                 return;
620             m_lastValuesAnimationFrom = from;
621             m_lastValuesAnimationTo = to;
622         }
623     } else if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced)
624         effectivePercent = calculatePercentFromKeyPoints(percent);
625     else if (m_keyPoints.isEmpty() && calcMode == CalcModeSpline && m_keyTimes.size() > 1)
626         effectivePercent = calculatePercentForSpline(percent, calculateKeyTimesIndex(percent));
627     else if (animationMode == FromToAnimation || animationMode == ToAnimation)
628         effectivePercent = calculatePercentForFromTo(percent);
629     else
630         effectivePercent = percent;
631
632     calculateAnimatedValue(effectivePercent, repeatCount, resultElement);
633 }
634
635 void SVGAnimationElement::computeCSSPropertyValue(SVGElement* element, CSSPropertyID id, String& value)
636 {
637     ASSERT(element);
638     ASSERT(element->isSVGStyledElement());
639
640     // Don't include any properties resulting from CSS Transitions/Animations or SMIL animations, as we want to retrieve the "base value".
641     element->setUseOverrideComputedStyle(true);
642     value = CSSComputedStyleDeclaration::create(element)->getPropertyValue(id);
643     element->setUseOverrideComputedStyle(false);
644 }
645
646 void SVGAnimationElement::adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String& value)
647 {
648     // FIXME: At the moment the computed style gets returned as a String and needs to get parsed again.
649     // In the future we might want to work with the value type directly to avoid the String parsing.
650     ASSERT(targetElement);
651
652     Element* parent = targetElement->parentElement();
653     if (!parent || !parent->isSVGElement())
654         return;
655
656     SVGElement* svgParent = toSVGElement(parent);
657     if (!svgParent->isSVGStyledElement())
658         return;
659     computeCSSPropertyValue(svgParent, cssPropertyID(attributeName.localName()), value);
660 }
661
662 static bool inheritsFromProperty(SVGElement* targetElement, const QualifiedName& attributeName, const String& value)
663 {
664     ASSERT(targetElement);
665     DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit", AtomicString::ConstructFromLiteral));
666     
667     if (value.isEmpty() || value != inherit || !targetElement->isSVGStyledElement())
668         return false;
669     return SVGStyledElement::isAnimatableCSSProperty(attributeName);
670 }
671
672 void SVGAnimationElement::determinePropertyValueTypes(const String& from, const String& to)
673 {
674     SVGElement* targetElement = this->targetElement();
675     ASSERT(targetElement);
676
677     const QualifiedName& attributeName = this->attributeName();
678     if (inheritsFromProperty(targetElement, attributeName, from))
679         m_fromPropertyValueType = InheritValue;
680     if (inheritsFromProperty(targetElement, attributeName, to))
681         m_toPropertyValueType = InheritValue;
682 }
683
684 void SVGAnimationElement::setTargetElement(SVGElement* target)
685 {
686     SVGSMILElement::setTargetElement(target);
687     checkInvalidCSSAttributeType(target);
688 }
689
690 void SVGAnimationElement::setAttributeName(const QualifiedName& attributeName)
691 {
692     SVGSMILElement::setAttributeName(attributeName);
693     checkInvalidCSSAttributeType(targetElement());
694 }
695
696 void SVGAnimationElement::checkInvalidCSSAttributeType(SVGElement* target)
697 {
698     m_hasInvalidCSSAttributeType = target && hasValidAttributeName() && attributeType() == AttributeTypeCSS && !isTargetAttributeCSSProperty(target, attributeName());
699 }
700
701 }
702
703 #endif // ENABLE(SVG)