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