Remove unused variable movedSectionLogicalTop from table layout code.
[chromium-blink-merge.git] / third_party / WebKit / Source / core / svg / SVGAnimationElement.cpp
blob40f1bda14edc337dfcb4d935076cb409b9861702
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.
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.
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.
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.
25 #include "config.h"
26 #include "core/svg/SVGAnimationElement.h"
28 #include "bindings/core/v8/ExceptionState.h"
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"
40 namespace blink {
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)
52 ASSERT(RuntimeEnabledFeatures::smilEnabled());
53 UseCounter::count(document, UseCounter::SVGAnimationElement);
56 bool SVGAnimationElement::parseValues(const String& value, Vector<String>& result)
58 // Per the SMIL specification, leading and trailing white space,
59 // and white space before and after semicolon separators, is allowed and will be ignored.
60 // http://www.w3.org/TR/SVG11/animate.html#ValuesAttribute
61 result.clear();
62 Vector<String> parseList;
63 value.split(';', true, parseList);
64 unsigned last = parseList.size() - 1;
65 for (unsigned i = 0; i <= last; ++i) {
66 if (parseList[i].isEmpty()) {
67 // Tolerate trailing ';'
68 if (i < last)
69 goto fail;
70 } else {
71 parseList[i] = parseList[i].stripWhiteSpace();
72 result.append(parseList[i]);
76 return true;
77 fail:
78 result.clear();
79 return false;
82 static bool parseKeyTimes(const String& string, Vector<float>& result, bool verifyOrder)
84 result.clear();
85 Vector<String> parseList;
86 string.split(';', true, parseList);
87 for (unsigned n = 0; n < parseList.size(); ++n) {
88 String timeString = parseList[n].stripWhiteSpace();
89 bool ok;
90 float time = timeString.toFloat(&ok);
91 if (!ok || time < 0 || time > 1)
92 goto fail;
93 if (verifyOrder) {
94 if (!n) {
95 if (time)
96 goto fail;
97 } else if (time < result.last()) {
98 goto fail;
101 result.append(time);
103 return true;
104 fail:
105 result.clear();
106 return false;
109 template<typename CharType>
110 static bool parseKeySplinesInternal(const String& string, Vector<UnitBezier>& result)
112 const CharType* ptr = string.getCharacters<CharType>();
113 const CharType* end = ptr + string.length();
115 skipOptionalSVGSpaces(ptr, end);
117 while (ptr < end) {
118 float posA = 0;
119 if (!parseNumber(ptr, end, posA))
120 return false;
122 float posB = 0;
123 if (!parseNumber(ptr, end, posB))
124 return false;
126 float posC = 0;
127 if (!parseNumber(ptr, end, posC))
128 return false;
130 float posD = 0;
131 if (!parseNumber(ptr, end, posD, DisallowWhitespace))
132 return false;
134 skipOptionalSVGSpaces(ptr, end);
136 if (ptr < end && *ptr == ';')
137 ptr++;
138 skipOptionalSVGSpaces(ptr, end);
140 result.append(UnitBezier(posA, posB, posC, posD));
143 return ptr == end;
146 static bool parseKeySplines(const String& string, Vector<UnitBezier>& result)
148 result.clear();
149 if (string.isEmpty())
150 return true;
151 bool parsed = true;
152 if (string.is8Bit())
153 parsed = parseKeySplinesInternal<LChar>(string, result);
154 else
155 parsed = parseKeySplinesInternal<UChar>(string, result);
156 if (!parsed) {
157 result.clear();
158 return false;
160 return true;
163 void SVGAnimationElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
165 if (name == SVGNames::valuesAttr) {
166 if (!parseValues(value, m_values)) {
167 reportAttributeParsingError(ParsingAttributeFailedError, name, value);
168 return;
170 updateAnimationMode();
171 return;
174 if (name == SVGNames::keyTimesAttr) {
175 if (!parseKeyTimes(value, m_keyTimes, true))
176 reportAttributeParsingError(ParsingAttributeFailedError, name, value);
177 return;
180 if (name == SVGNames::keyPointsAttr) {
181 if (isSVGAnimateMotionElement(*this)) {
182 // This is specified to be an animateMotion attribute only but it is simpler to put it here
183 // where the other timing calculatations are.
184 if (!parseKeyTimes(value, m_keyPoints, false))
185 reportAttributeParsingError(ParsingAttributeFailedError, name, value);
187 return;
190 if (name == SVGNames::keySplinesAttr) {
191 if (!parseKeySplines(value, m_keySplines))
192 reportAttributeParsingError(ParsingAttributeFailedError, name, value);
193 return;
196 if (name == SVGNames::attributeTypeAttr) {
197 setAttributeType(value);
198 return;
201 if (name == SVGNames::calcModeAttr) {
202 setCalcMode(value);
203 return;
206 if (name == SVGNames::fromAttr || name == SVGNames::toAttr || name == SVGNames::byAttr) {
207 updateAnimationMode();
208 return;
211 SVGSMILElement::parseAttribute(name, value);
214 void SVGAnimationElement::svgAttributeChanged(const QualifiedName& attrName)
216 if (attrName == SVGNames::valuesAttr
217 || attrName == SVGNames::byAttr
218 || attrName == SVGNames::fromAttr
219 || attrName == SVGNames::toAttr
220 || attrName == SVGNames::calcModeAttr
221 || attrName == SVGNames::attributeTypeAttr
222 || attrName == SVGNames::keySplinesAttr
223 || attrName == SVGNames::keyPointsAttr
224 || attrName == SVGNames::keyTimesAttr) {
225 animationAttributeChanged();
226 return;
229 SVGSMILElement::svgAttributeChanged(attrName);
232 void SVGAnimationElement::animationAttributeChanged()
234 // Assumptions may not hold after an attribute change.
235 m_animationValid = false;
236 m_lastValuesAnimationFrom = String();
237 m_lastValuesAnimationTo = String();
238 setInactive();
241 float SVGAnimationElement::getStartTime(ExceptionState& exceptionState) const
243 SMILTime startTime = intervalBegin();
244 if (!startTime.isFinite()) {
245 exceptionState.throwDOMException(InvalidStateError, "No current interval.");
246 return 0;
248 return narrowPrecisionToFloat(startTime.value());
251 float SVGAnimationElement::getCurrentTime() const
253 return narrowPrecisionToFloat(elapsed().value());
256 float SVGAnimationElement::getSimpleDuration(ExceptionState& exceptionState) const
258 SMILTime duration = simpleDuration();
259 if (!duration.isFinite()) {
260 exceptionState.throwDOMException(NotSupportedError, "No simple duration defined.");
261 return 0;
263 return narrowPrecisionToFloat(duration.value());
266 void SVGAnimationElement::beginElement()
268 beginElementAt(0);
271 void SVGAnimationElement::beginElementAt(float offset)
273 ASSERT(std::isfinite(offset));
274 SMILTime elapsed = this->elapsed();
275 addBeginTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin);
278 void SVGAnimationElement::endElement()
280 endElementAt(0);
283 void SVGAnimationElement::endElementAt(float offset)
285 ASSERT(std::isfinite(offset));
286 SMILTime elapsed = this->elapsed();
287 addEndTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin);
290 void SVGAnimationElement::updateAnimationMode()
292 // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#AnimFuncValues
293 if (hasAttribute(SVGNames::valuesAttr))
294 setAnimationMode(ValuesAnimation);
295 else if (!toValue().isEmpty())
296 setAnimationMode(fromValue().isEmpty() ? ToAnimation : FromToAnimation);
297 else if (!byValue().isEmpty())
298 setAnimationMode(fromValue().isEmpty() ? ByAnimation : FromByAnimation);
299 else
300 setAnimationMode(NoAnimation);
303 void SVGAnimationElement::setCalcMode(const AtomicString& calcMode)
305 DEFINE_STATIC_LOCAL(const AtomicString, discrete, ("discrete", AtomicString::ConstructFromLiteral));
306 DEFINE_STATIC_LOCAL(const AtomicString, linear, ("linear", AtomicString::ConstructFromLiteral));
307 DEFINE_STATIC_LOCAL(const AtomicString, paced, ("paced", AtomicString::ConstructFromLiteral));
308 DEFINE_STATIC_LOCAL(const AtomicString, spline, ("spline", AtomicString::ConstructFromLiteral));
309 if (calcMode == discrete)
310 setCalcMode(CalcModeDiscrete);
311 else if (calcMode == linear)
312 setCalcMode(CalcModeLinear);
313 else if (calcMode == paced)
314 setCalcMode(CalcModePaced);
315 else if (calcMode == spline)
316 setCalcMode(CalcModeSpline);
317 else
318 setCalcMode(isSVGAnimateMotionElement(*this) ? CalcModePaced : CalcModeLinear);
321 void SVGAnimationElement::setAttributeType(const AtomicString& attributeType)
323 DEFINE_STATIC_LOCAL(const AtomicString, css, ("CSS", AtomicString::ConstructFromLiteral));
324 DEFINE_STATIC_LOCAL(const AtomicString, xml, ("XML", AtomicString::ConstructFromLiteral));
325 if (attributeType == css)
326 m_attributeType = AttributeTypeCSS;
327 else if (attributeType == xml)
328 m_attributeType = AttributeTypeXML;
329 else
330 m_attributeType = AttributeTypeAuto;
331 checkInvalidCSSAttributeType();
334 String SVGAnimationElement::toValue() const
336 return fastGetAttribute(SVGNames::toAttr);
339 String SVGAnimationElement::byValue() const
341 return fastGetAttribute(SVGNames::byAttr);
344 String SVGAnimationElement::fromValue() const
346 return fastGetAttribute(SVGNames::fromAttr);
349 bool SVGAnimationElement::isAdditive()
351 DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum", AtomicString::ConstructFromLiteral));
352 const AtomicString& value = fastGetAttribute(SVGNames::additiveAttr);
353 return value == sum || animationMode() == ByAnimation;
356 bool SVGAnimationElement::isAccumulated() const
358 DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum", AtomicString::ConstructFromLiteral));
359 const AtomicString& value = fastGetAttribute(SVGNames::accumulateAttr);
360 return value == sum && animationMode() != ToAnimation;
363 bool SVGAnimationElement::isTargetAttributeCSSProperty(SVGElement* targetElement, const QualifiedName& attributeName)
365 ASSERT(targetElement);
367 return SVGElement::isAnimatableCSSProperty(attributeName) || targetElement->isPresentationAttribute(attributeName);
370 SVGAnimationElement::ShouldApplyAnimation SVGAnimationElement::shouldApplyAnimation(SVGElement* targetElement, const QualifiedName& attributeName)
372 if (!hasValidAttributeType() || !targetElement || attributeName == anyQName() || !targetElement->inActiveDocument())
373 return DontApplyAnimation;
375 // Always animate CSS properties, using the ApplyCSSAnimation code path, regardless of the attributeType value.
376 if (isTargetAttributeCSSProperty(targetElement, attributeName)) {
377 if (targetElement->isPresentationAttributeWithSVGDOM(attributeName))
378 return ApplyXMLandCSSAnimation;
380 return ApplyCSSAnimation;
382 // If attributeType="CSS" and attributeName doesn't point to a CSS property, ignore the animation.
383 if (attributeType() == AttributeTypeCSS)
384 return DontApplyAnimation;
386 return ApplyXMLAnimation;
389 void SVGAnimationElement::calculateKeyTimesForCalcModePaced()
391 ASSERT(calcMode() == CalcModePaced);
392 ASSERT(animationMode() == ValuesAnimation);
394 unsigned valuesCount = m_values.size();
395 ASSERT(valuesCount >= 1);
396 if (valuesCount == 1)
397 return;
399 // FIXME, webkit.org/b/109010: m_keyTimes should not be modified in this function.
400 m_keyTimes.clear();
402 Vector<float> keyTimesForPaced;
403 float totalDistance = 0;
404 keyTimesForPaced.append(0);
405 for (unsigned n = 0; n < valuesCount - 1; ++n) {
406 // Distance in any units
407 float distance = calculateDistance(m_values[n], m_values[n + 1]);
408 if (distance < 0)
409 return;
410 totalDistance += distance;
411 keyTimesForPaced.append(distance);
413 if (!totalDistance)
414 return;
416 // Normalize.
417 for (unsigned n = 1; n < keyTimesForPaced.size() - 1; ++n)
418 keyTimesForPaced[n] = keyTimesForPaced[n - 1] + keyTimesForPaced[n] / totalDistance;
419 keyTimesForPaced[keyTimesForPaced.size() - 1] = 1;
421 // Use key times calculated based on pacing instead of the user provided ones.
422 m_keyTimes = keyTimesForPaced;
425 static inline double solveEpsilon(double duration) { return 1 / (200 * duration); }
427 unsigned SVGAnimationElement::calculateKeyTimesIndex(float percent) const
429 unsigned index;
430 unsigned keyTimesCount = m_keyTimes.size();
431 // For linear and spline animations, the last value must be '1'. In those
432 // cases we don't need to consider the last value, since |percent| is never
433 // greater than one.
434 if (keyTimesCount && calcMode() != CalcModeDiscrete)
435 keyTimesCount--;
436 for (index = 1; index < keyTimesCount; ++index) {
437 if (m_keyTimes[index] > percent)
438 break;
440 return --index;
443 float SVGAnimationElement::calculatePercentForSpline(float percent, unsigned splineIndex) const
445 ASSERT(calcMode() == CalcModeSpline);
446 ASSERT_WITH_SECURITY_IMPLICATION(splineIndex < m_keySplines.size());
447 UnitBezier bezier = m_keySplines[splineIndex];
448 SMILTime duration = simpleDuration();
449 if (!duration.isFinite())
450 duration = 100.0;
451 return narrowPrecisionToFloat(bezier.solve(percent, solveEpsilon(duration.value())));
454 float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const
456 ASSERT(!m_keyPoints.isEmpty());
457 ASSERT(calcMode() != CalcModePaced);
458 ASSERT(m_keyTimes.size() > 1);
459 ASSERT(m_keyPoints.size() == m_keyTimes.size());
461 if (percent == 1)
462 return m_keyPoints[m_keyPoints.size() - 1];
464 unsigned index = calculateKeyTimesIndex(percent);
465 float fromKeyPoint = m_keyPoints[index];
467 if (calcMode() == CalcModeDiscrete)
468 return fromKeyPoint;
470 ASSERT(index + 1 < m_keyTimes.size());
471 float fromPercent = m_keyTimes[index];
472 float toPercent = m_keyTimes[index + 1];
473 float toKeyPoint = m_keyPoints[index + 1];
474 float keyPointPercent = (percent - fromPercent) / (toPercent - fromPercent);
476 if (calcMode() == CalcModeSpline) {
477 ASSERT(m_keySplines.size() == m_keyPoints.size() - 1);
478 keyPointPercent = calculatePercentForSpline(keyPointPercent, index);
480 return (toKeyPoint - fromKeyPoint) * keyPointPercent + fromKeyPoint;
483 float SVGAnimationElement::calculatePercentForFromTo(float percent) const
485 if (calcMode() == CalcModeDiscrete && m_keyTimes.size() == 2)
486 return percent > m_keyTimes[1] ? 1 : 0;
488 return percent;
491 void SVGAnimationElement::currentValuesFromKeyPoints(float percent, float& effectivePercent, String& from, String& to) const
493 ASSERT(!m_keyPoints.isEmpty());
494 ASSERT(m_keyPoints.size() == m_keyTimes.size());
495 ASSERT(calcMode() != CalcModePaced);
496 effectivePercent = calculatePercentFromKeyPoints(percent);
497 unsigned index = effectivePercent == 1 ? m_values.size() - 2 : static_cast<unsigned>(effectivePercent * (m_values.size() - 1));
498 from = m_values[index];
499 to = m_values[index + 1];
502 void SVGAnimationElement::currentValuesForValuesAnimation(float percent, float& effectivePercent, String& from, String& to)
504 unsigned valuesCount = m_values.size();
505 ASSERT(m_animationValid);
506 ASSERT(valuesCount >= 1);
508 if (percent == 1 || valuesCount == 1) {
509 from = m_values[valuesCount - 1];
510 to = m_values[valuesCount - 1];
511 effectivePercent = 1;
512 return;
515 CalcMode calcMode = this->calcMode();
516 if (isSVGAnimateElement(*this)) {
517 SVGAnimateElement& animateElement = toSVGAnimateElement(*this);
518 if (!animateElement.animatedPropertyTypeSupportsAddition()) {
519 ASSERT(animateElement.animatedPropertyType() != AnimatedTransformList || isSVGAnimateTransformElement(*this));
520 ASSERT(animateElement.animatedPropertyType() != AnimatedUnknown);
521 calcMode = CalcModeDiscrete;
524 if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced)
525 return currentValuesFromKeyPoints(percent, effectivePercent, from, to);
527 unsigned keyTimesCount = m_keyTimes.size();
528 ASSERT(!keyTimesCount || valuesCount == keyTimesCount);
529 ASSERT(!keyTimesCount || (keyTimesCount > 1 && !m_keyTimes[0]));
531 unsigned index = calculateKeyTimesIndex(percent);
532 if (calcMode == CalcModeDiscrete) {
533 if (!keyTimesCount)
534 index = static_cast<unsigned>(percent * valuesCount);
535 from = m_values[index];
536 to = m_values[index];
537 effectivePercent = 0;
538 return;
541 float fromPercent;
542 float toPercent;
543 if (keyTimesCount) {
544 fromPercent = m_keyTimes[index];
545 toPercent = m_keyTimes[index + 1];
546 } else {
547 index = static_cast<unsigned>(floorf(percent * (valuesCount - 1)));
548 fromPercent = static_cast<float>(index) / (valuesCount - 1);
549 toPercent = static_cast<float>(index + 1) / (valuesCount - 1);
552 if (index == valuesCount - 1)
553 --index;
554 from = m_values[index];
555 to = m_values[index + 1];
556 ASSERT(toPercent > fromPercent);
557 effectivePercent = (percent - fromPercent) / (toPercent - fromPercent);
559 if (calcMode == CalcModeSpline) {
560 ASSERT(m_keySplines.size() == m_values.size() - 1);
561 effectivePercent = calculatePercentForSpline(effectivePercent, index);
565 void SVGAnimationElement::startedActiveInterval()
567 m_animationValid = false;
569 if (!isValid())
570 return;
572 if (!hasValidAttributeType())
573 return;
575 // These validations are appropriate for all animation modes.
576 if (fastHasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() != m_keyTimes.size())
577 return;
579 AnimationMode animationMode = this->animationMode();
580 CalcMode calcMode = this->calcMode();
581 if (calcMode == CalcModeSpline) {
582 unsigned splinesCount = m_keySplines.size();
583 if (!splinesCount
584 || (fastHasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() - 1 != splinesCount)
585 || (animationMode == ValuesAnimation && m_values.size() - 1 != splinesCount)
586 || (fastHasAttribute(SVGNames::keyTimesAttr) && m_keyTimes.size() - 1 != splinesCount))
587 return;
590 String from = fromValue();
591 String to = toValue();
592 String by = byValue();
593 if (animationMode == NoAnimation)
594 return;
595 if ((animationMode == FromToAnimation || animationMode == FromByAnimation || animationMode == ToAnimation || animationMode == ByAnimation)
596 && (fastHasAttribute(SVGNames::keyPointsAttr) && fastHasAttribute(SVGNames::keyTimesAttr) && (m_keyTimes.size() < 2 || m_keyTimes.size() != m_keyPoints.size())))
597 return;
598 if (animationMode == FromToAnimation) {
599 m_animationValid = calculateFromAndToValues(from, to);
600 } else if (animationMode == ToAnimation) {
601 // For to-animations the from value is the current accumulated value from lower priority animations.
602 // The value is not static and is determined during the animation.
603 m_animationValid = calculateFromAndToValues(emptyString(), to);
604 } else if (animationMode == FromByAnimation) {
605 m_animationValid = calculateFromAndByValues(from, by);
606 } else if (animationMode == ByAnimation) {
607 m_animationValid = calculateFromAndByValues(emptyString(), by);
608 } else if (animationMode == ValuesAnimation) {
609 m_animationValid = m_values.size() >= 1
610 && (calcMode == CalcModePaced || !fastHasAttribute(SVGNames::keyTimesAttr) || fastHasAttribute(SVGNames::keyPointsAttr) || (m_values.size() == m_keyTimes.size()))
611 && (calcMode == CalcModeDiscrete || !m_keyTimes.size() || m_keyTimes.last() == 1)
612 && (calcMode != CalcModeSpline || ((m_keySplines.size() && (m_keySplines.size() == m_values.size() - 1)) || m_keySplines.size() == m_keyPoints.size() - 1))
613 && (!fastHasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size()));
614 if (m_animationValid)
615 m_animationValid = calculateToAtEndOfDurationValue(m_values.last());
616 if (calcMode == CalcModePaced && m_animationValid)
617 calculateKeyTimesForCalcModePaced();
618 } else if (animationMode == PathAnimation) {
619 m_animationValid = calcMode == CalcModePaced || !fastHasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size());
623 void SVGAnimationElement::updateAnimation(float percent, unsigned repeatCount, SVGSMILElement* resultElement)
625 if (!m_animationValid)
626 return;
628 float effectivePercent;
629 CalcMode calcMode = this->calcMode();
630 AnimationMode animationMode = this->animationMode();
631 if (animationMode == ValuesAnimation) {
632 String from;
633 String to;
634 currentValuesForValuesAnimation(percent, effectivePercent, from, to);
635 if (from != m_lastValuesAnimationFrom || to != m_lastValuesAnimationTo) {
636 m_animationValid = calculateFromAndToValues(from, to);
637 if (!m_animationValid)
638 return;
639 m_lastValuesAnimationFrom = from;
640 m_lastValuesAnimationTo = to;
642 } else if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced)
643 effectivePercent = calculatePercentFromKeyPoints(percent);
644 else if (m_keyPoints.isEmpty() && calcMode == CalcModeSpline && m_keyTimes.size() > 1)
645 effectivePercent = calculatePercentForSpline(percent, calculateKeyTimesIndex(percent));
646 else if (animationMode == FromToAnimation || animationMode == ToAnimation)
647 effectivePercent = calculatePercentForFromTo(percent);
648 else
649 effectivePercent = percent;
651 calculateAnimatedValue(effectivePercent, repeatCount, resultElement);
654 void SVGAnimationElement::computeCSSPropertyValue(SVGElement* element, CSSPropertyID id, String& value)
656 ASSERT(element);
657 // FIXME: StyleEngine doesn't support document without a frame.
658 // Refer to comment in Element::computedStyle.
659 ASSERT(element->inActiveDocument());
661 // Don't include any properties resulting from CSS Transitions/Animations or SMIL animations, as we want to retrieve the "base value".
662 element->setUseOverrideComputedStyle(true);
663 value = CSSComputedStyleDeclaration::create(element)->getPropertyValue(id);
664 element->setUseOverrideComputedStyle(false);
667 void SVGAnimationElement::adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String& value)
669 // FIXME: At the moment the computed style gets returned as a String and needs to get parsed again.
670 // In the future we might want to work with the value type directly to avoid the String parsing.
671 ASSERT(targetElement);
673 Element* parent = targetElement->parentElement();
674 if (!parent || !parent->isSVGElement())
675 return;
677 SVGElement* svgParent = toSVGElement(parent);
678 computeCSSPropertyValue(svgParent, cssPropertyID(attributeName.localName()), value);
681 static bool inheritsFromProperty(SVGElement* targetElement, const QualifiedName& attributeName, const String& value)
683 ASSERT(targetElement);
684 DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit", AtomicString::ConstructFromLiteral));
686 if (value.isEmpty() || value != inherit)
687 return false;
688 return SVGElement::isAnimatableCSSProperty(attributeName);
691 void SVGAnimationElement::determinePropertyValueTypes(const String& from, const String& to)
693 SVGElement* targetElement = this->targetElement();
694 ASSERT(targetElement);
696 const QualifiedName& attributeName = this->attributeName();
697 if (inheritsFromProperty(targetElement, attributeName, from))
698 m_fromPropertyValueType = InheritValue;
699 if (inheritsFromProperty(targetElement, attributeName, to))
700 m_toPropertyValueType = InheritValue;
703 void SVGAnimationElement::setTargetElement(SVGElement* target)
705 SVGSMILElement::setTargetElement(target);
706 checkInvalidCSSAttributeType();
709 void SVGAnimationElement::setAttributeName(const QualifiedName& attributeName)
711 SVGSMILElement::setAttributeName(attributeName);
712 checkInvalidCSSAttributeType();
715 void SVGAnimationElement::checkInvalidCSSAttributeType()
717 bool hasInvalidCSSAttributeType = targetElement() && hasValidAttributeName() && attributeType() == AttributeTypeCSS && !isTargetAttributeCSSProperty(targetElement(), attributeName());
719 if (hasInvalidCSSAttributeType != m_hasInvalidCSSAttributeType) {
720 if (hasInvalidCSSAttributeType)
721 unscheduleIfScheduled();
723 m_hasInvalidCSSAttributeType = hasInvalidCSSAttributeType;
725 if (!hasInvalidCSSAttributeType)
726 schedule();
729 // Clear values that may depend on the previous target.
730 if (targetElement())
731 clearAnimatedType();