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