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