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