Chromium Code Reviews| Index: third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp |
| diff --git a/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp b/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp |
| index 67e710b6f227f0a0e333521b3583384e95d910cb..558796f31cbaf4ec27527f3ce7ca5538b5095446 100644 |
| --- a/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp |
| +++ b/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp |
| @@ -27,6 +27,12 @@ |
| #include "core/dom/Document.h" |
| #include "core/dom/QualifiedName.h" |
| #include "core/dom/StyleChangeReason.h" |
| +#include "core/svg/SVGAnimatedColor.h" |
| +#include "core/svg/SVGLength.h" |
| +#include "core/svg/SVGLengthList.h" |
| +#include "core/svg/SVGNumber.h" |
| +#include "core/svg/SVGString.h" |
| +#include "core/svg/properties/SVGAnimatedProperty.h" |
| #include "core/svg/properties/SVGProperty.h" |
| namespace blink { |
| @@ -68,7 +74,8 @@ AnimatedPropertyValueType propertyValueType(const QualifiedName& attributeName, |
| SVGAnimateElement::SVGAnimateElement(const QualifiedName& tagName, |
| Document& document) |
| : SVGAnimationElement(tagName, document), |
| - m_animator(this), |
| + m_type(AnimatedUnknown), |
| + m_cssPropertyId(CSSPropertyInvalid), |
| m_fromPropertyValueType(RegularPropertyValue), |
| m_toPropertyValueType(RegularPropertyValue), |
| m_attributeType(AttributeTypeAuto), |
| @@ -120,12 +127,40 @@ void SVGAnimateElement::svgAttributeChanged(const QualifiedName& attrName) { |
| SVGAnimationElement::svgAttributeChanged(attrName); |
| } |
| +void SVGAnimateElement::resolveTargetProperty() { |
| + DCHECK(targetElement()); |
| + m_targetProperty = targetElement()->propertyFromAttribute(attributeName()); |
| + if (m_targetProperty) { |
| + m_type = m_targetProperty->type(); |
| + m_cssPropertyId = m_targetProperty->cssPropertyId(); |
| + |
| + // Only <animateTransform> is allowed to animate AnimatedTransformList. |
| + // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties |
| + if (m_type == AnimatedTransformList) { |
| + m_type = AnimatedUnknown; |
| + m_cssPropertyId = CSSPropertyInvalid; |
| + } |
| + } else { |
| + m_type = SVGElement::animatedPropertyTypeForCSSAttribute(attributeName()); |
| + m_cssPropertyId = m_type != AnimatedUnknown |
| + ? cssPropertyID(attributeName().localName()) |
| + : CSSPropertyInvalid; |
| + } |
| + DCHECK(m_type != AnimatedPoint && m_type != AnimatedStringList && |
| + m_type != AnimatedTransform && m_type != AnimatedTransformList); |
| +} |
| + |
| +void SVGAnimateElement::clearTargetProperty() { |
| + m_targetProperty = nullptr; |
| + m_type = AnimatedUnknown; |
| + m_cssPropertyId = CSSPropertyInvalid; |
| +} |
| + |
| AnimatedPropertyType SVGAnimateElement::animatedPropertyType() { |
| if (!targetElement()) |
| return AnimatedUnknown; |
| - |
| - m_animator.reset(*targetElement()); |
| - return m_animator.type(); |
| + resolveTargetProperty(); |
| + return m_type; |
| } |
| bool SVGAnimateElement::hasValidTarget() { |
| @@ -160,6 +195,81 @@ bool SVGAnimateElement::shouldApplyAnimation( |
| return getAttributeType() != AttributeTypeCSS; |
| } |
| +SVGPropertyBase* SVGAnimateElement::createPropertyForAttributeAnimation( |
| + const String& value) const { |
| + // SVG DOM animVal animation code-path. |
| + // TransformList must be animated via <animateTransform>, and its |
| + // {from,by,to} attribute values needs to be parsed w.r.t. its "type" |
| + // attribute. Spec: |
| + // http://www.w3.org/TR/SVG/single-page.html#animate-AnimateTransformElement |
| + DCHECK_NE(m_type, AnimatedTransformList); |
| + DCHECK(m_targetProperty); |
| + return m_targetProperty->currentValueBase()->cloneForAnimation(value); |
| +} |
| + |
| +SVGPropertyBase* SVGAnimateElement::createPropertyForCSSAnimation( |
| + const String& value) const { |
| + // CSS properties animation code-path. |
| + // Create a basic instance of the corresponding SVG property. |
| + // The instance will not have full context info. (e.g. SVGLengthMode) |
| + switch (m_type) { |
| + case AnimatedColor: |
| + return SVGColorProperty::create(value); |
| + case AnimatedNumber: { |
| + SVGNumber* property = SVGNumber::create(); |
| + property->setValueAsString(value); |
| + return property; |
| + } |
| + case AnimatedLength: { |
| + SVGLength* property = SVGLength::create(); |
| + property->setValueAsString(value); |
| + return property; |
| + } |
| + case AnimatedLengthList: { |
| + SVGLengthList* property = SVGLengthList::create(); |
| + property->setValueAsString(value); |
| + return property; |
| + } |
| + case AnimatedString: { |
| + SVGString* property = SVGString::create(); |
| + property->setValueAsString(value); |
| + return property; |
| + } |
| + // These types don't appear in the table in |
| + // SVGElement::animatedPropertyTypeForCSSAttribute() and thus don't need |
| + // support. |
| + case AnimatedAngle: |
| + case AnimatedBoolean: |
| + case AnimatedEnumeration: |
| + case AnimatedInteger: |
| + case AnimatedIntegerOptionalInteger: |
| + case AnimatedNumberList: |
| + case AnimatedNumberOptionalNumber: |
| + case AnimatedPath: |
| + case AnimatedPoint: |
| + case AnimatedPoints: |
| + case AnimatedPreserveAspectRatio: |
| + case AnimatedRect: |
| + case AnimatedStringList: |
| + case AnimatedTransform: |
| + case AnimatedTransformList: |
| + case AnimatedUnknown: |
| + break; |
| + default: |
| + break; |
| + } |
| + NOTREACHED(); |
| + return nullptr; |
| +} |
| + |
| +SVGPropertyBase* SVGAnimateElement::createPropertyForAnimation( |
| + const String& value) const { |
| + if (isAnimatingSVGDom()) |
| + return createPropertyForAttributeAnimation(value); |
| + DCHECK(isAnimatingCSSProperty()); |
| + return createPropertyForCSSAnimation(value); |
| +} |
| + |
| SVGPropertyBase* SVGAnimateElement::adjustForInheritance( |
| SVGPropertyBase* propertyValue, |
| AnimatedPropertyValueType valueType) const { |
| @@ -174,8 +284,8 @@ SVGPropertyBase* SVGAnimateElement::adjustForInheritance( |
| return propertyValue; |
| SVGElement* svgParent = toSVGElement(parent); |
| // Replace 'inherit' by its computed property value. |
| - String value = computeCSSPropertyValue(svgParent, m_animator.cssProperty()); |
| - return m_animator.createPropertyForAnimation(value); |
| + String value = computeCSSPropertyValue(svgParent, m_cssPropertyId); |
| + return createPropertyForAnimation(value); |
| } |
| void SVGAnimateElement::calculateAnimatedValue(float percentage, |
| @@ -187,16 +297,14 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, |
| return; |
| ASSERT(percentage >= 0 && percentage <= 1); |
|
Stephen Chennney
2016/12/22 20:07:25
I wonder how we got in a state where there are DCH
fs
2016/12/22 20:25:31
That's most likely an artifact of whoever changed
fs
2016/12/22 21:45:49
Done.
|
| - ASSERT(animatedPropertyType() != AnimatedTransformList || |
| - isSVGAnimateTransformElement(*this)); |
| - ASSERT(animatedPropertyType() != AnimatedUnknown); |
| + DCHECK(animatedPropertyType() != AnimatedUnknown); |
| ASSERT(m_fromProperty); |
| ASSERT(m_fromProperty->type() == animatedPropertyType()); |
| ASSERT(m_toProperty); |
| SVGAnimateElement* resultAnimationElement = |
| toSVGAnimateElement(resultElement); |
| - ASSERT(resultAnimationElement->m_animatedProperty); |
| + DCHECK(resultAnimationElement->m_animatedValue); |
| ASSERT(resultAnimationElement->animatedPropertyType() == |
| animatedPropertyType()); |
| @@ -211,7 +319,7 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, |
| // Values-animation accumulates using the last values entry corresponding to |
| // the end of duration time. |
| - SVGPropertyBase* animatedValue = resultAnimationElement->m_animatedProperty; |
| + SVGPropertyBase* animatedValue = resultAnimationElement->m_animatedValue; |
| SVGPropertyBase* toAtEndOfDurationValue = |
| m_toAtEndOfDurationProperty ? m_toAtEndOfDurationProperty : m_toProperty; |
| SVGPropertyBase* fromValue = |
| @@ -232,16 +340,16 @@ bool SVGAnimateElement::calculateToAtEndOfDurationValue( |
| if (toAtEndOfDurationString.isEmpty()) |
| return false; |
| m_toAtEndOfDurationProperty = |
| - m_animator.createPropertyForAnimation(toAtEndOfDurationString); |
| + createPropertyForAnimation(toAtEndOfDurationString); |
| return true; |
| } |
| bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, |
| const String& toString) { |
| DCHECK(targetElement()); |
| - m_fromProperty = m_animator.createPropertyForAnimation(fromString); |
| + m_fromProperty = createPropertyForAnimation(fromString); |
| m_fromPropertyValueType = propertyValueType(attributeName(), fromString); |
| - m_toProperty = m_animator.createPropertyForAnimation(toString); |
| + m_toProperty = createPropertyForAnimation(toString); |
| m_toPropertyValueType = propertyValueType(attributeName(), toString); |
| return true; |
| } |
| @@ -261,41 +369,41 @@ bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, |
| DCHECK(!isSVGSetElement(*this)); |
| - m_fromProperty = m_animator.createPropertyForAnimation(fromString); |
| + m_fromProperty = createPropertyForAnimation(fromString); |
| m_fromPropertyValueType = propertyValueType(attributeName(), fromString); |
| - m_toProperty = m_animator.createPropertyForAnimation(byString); |
| + m_toProperty = createPropertyForAnimation(byString); |
| m_toPropertyValueType = propertyValueType(attributeName(), byString); |
| m_toProperty->add(m_fromProperty, targetElement()); |
| return true; |
| } |
| void SVGAnimateElement::resetAnimatedType() { |
| + resolveTargetProperty(); |
| + |
| SVGElement* targetElement = this->targetElement(); |
| const QualifiedName& attributeName = this->attributeName(); |
| - m_animator.reset(*targetElement); |
| - |
| if (!shouldApplyAnimation(*targetElement, attributeName)) |
| return; |
| - if (m_animator.isAnimatingSVGDom()) { |
| + if (isAnimatingSVGDom()) { |
| // SVG DOM animVal animation code-path. |
| - m_animatedProperty = m_animator.createAnimatedValue(); |
| - targetElement->setAnimatedAttribute(attributeName, m_animatedProperty); |
| + m_animatedValue = m_targetProperty->createAnimatedValue(); |
| + DCHECK_EQ(m_animatedValue->type(), m_type); |
| + targetElement->setAnimatedAttribute(attributeName, m_animatedValue); |
| return; |
| } |
| - DCHECK(m_animator.isAnimatingCSSProperty()); |
| + DCHECK(isAnimatingCSSProperty()); |
| // Presentation attributes which has an SVG DOM representation should use the |
| // "SVG DOM" code-path (above.) |
| DCHECK(SVGElement::isAnimatableCSSProperty(attributeName)); |
| // CSS properties animation code-path. |
| - String baseValue = |
| - computeCSSPropertyValue(targetElement, m_animator.cssProperty()); |
| - m_animatedProperty = m_animator.createPropertyForAnimation(baseValue); |
| + String baseValue = computeCSSPropertyValue(targetElement, m_cssPropertyId); |
| + m_animatedValue = createPropertyForAnimation(baseValue); |
| } |
| void SVGAnimateElement::clearAnimatedType() { |
| - if (!m_animatedProperty) |
| + if (!m_animatedValue) |
| return; |
| // The animated property lock is held for the "result animation" (see |
| @@ -306,42 +414,40 @@ void SVGAnimateElement::clearAnimatedType() { |
| SVGElement* targetElement = this->targetElement(); |
| if (!targetElement) { |
| - m_animatedProperty.clear(); |
| + m_animatedValue.clear(); |
| return; |
| } |
| bool shouldApply = shouldApplyAnimation(*targetElement, attributeName()); |
| - if (m_animator.isAnimatingCSSProperty()) { |
| + if (isAnimatingCSSProperty()) { |
| // CSS properties animation code-path. |
| if (shouldApply) { |
| MutableStylePropertySet* propertySet = |
| targetElement->ensureAnimatedSMILStyleProperties(); |
| - if (propertySet->removeProperty(m_animator.cssProperty())) { |
| + if (propertySet->removeProperty(m_cssPropertyId)) { |
| targetElement->setNeedsStyleRecalc( |
| LocalStyleChange, |
| StyleChangeReasonForTracing::create(StyleChangeReason::Animation)); |
| } |
| } |
| } |
| - if (m_animator.isAnimatingSVGDom()) { |
| + if (isAnimatingSVGDom()) { |
| // SVG DOM animVal animation code-path. |
| targetElement->clearAnimatedAttribute(attributeName()); |
| if (shouldApply) |
| targetElement->invalidateAnimatedAttribute(attributeName()); |
| } |
| - m_animatedProperty.clear(); |
| - m_animator.clear(); |
| + m_animatedValue.clear(); |
| + clearTargetProperty(); |
| } |
| void SVGAnimateElement::applyResultsToTarget() { |
| - ASSERT(animatedPropertyType() != AnimatedTransformList || |
| - isSVGAnimateTransformElement(*this)); |
| - ASSERT(animatedPropertyType() != AnimatedUnknown); |
| + DCHECK(animatedPropertyType() != AnimatedUnknown); |
| // Early exit if our animated type got destructed by a previous |
| // endedActiveInterval(). |
| - if (!m_animatedProperty) |
| + if (!m_animatedValue) |
| return; |
| if (!shouldApplyAnimation(*targetElement(), attributeName())) |
| @@ -349,22 +455,22 @@ void SVGAnimateElement::applyResultsToTarget() { |
| // We do update the style and the animation property independent of each |
| // other. |
| - if (m_animator.isAnimatingCSSProperty()) { |
| + if (isAnimatingCSSProperty()) { |
| // CSS properties animation code-path. |
| // Convert the result of the animation to a String and apply it as CSS |
| // property on the target. |
| MutableStylePropertySet* propertySet = |
| targetElement()->ensureAnimatedSMILStyleProperties(); |
| if (propertySet |
| - ->setProperty(m_animator.cssProperty(), |
| - m_animatedProperty->valueAsString(), false, 0) |
| + ->setProperty(m_cssPropertyId, m_animatedValue->valueAsString(), |
| + false, 0) |
| .didChange) { |
| targetElement()->setNeedsStyleRecalc( |
| LocalStyleChange, |
| StyleChangeReasonForTracing::create(StyleChangeReason::Animation)); |
| } |
| } |
| - if (m_animator.isAnimatingSVGDom()) { |
| + if (isAnimatingSVGDom()) { |
| // SVG DOM animVal animation code-path. |
| // At this point the SVG DOM values are already changed, unlike for CSS. |
| // We only have to trigger update notifications here. |
| @@ -401,9 +507,8 @@ float SVGAnimateElement::calculateDistance(const String& fromString, |
| DCHECK(targetElement()); |
| // FIXME: A return value of float is not enough to support paced animations on |
| // lists. |
| - SVGPropertyBase* fromValue = |
| - m_animator.createPropertyForAnimation(fromString); |
| - SVGPropertyBase* toValue = m_animator.createPropertyForAnimation(toString); |
| + SVGPropertyBase* fromValue = createPropertyForAnimation(fromString); |
| + SVGPropertyBase* toValue = createPropertyForAnimation(toString); |
| return fromValue->calculateDistance(toValue, targetElement()); |
| } |
| @@ -451,19 +556,19 @@ void SVGAnimateElement::checkInvalidCSSAttributeType() { |
| } |
| void SVGAnimateElement::resetAnimatedPropertyType() { |
| - ASSERT(!m_animatedProperty); |
| + DCHECK(!m_animatedValue); |
| m_fromProperty.clear(); |
| m_toProperty.clear(); |
| m_toAtEndOfDurationProperty.clear(); |
| - m_animator.clear(); |
| + clearTargetProperty(); |
| } |
| DEFINE_TRACE(SVGAnimateElement) { |
| visitor->trace(m_fromProperty); |
| visitor->trace(m_toProperty); |
| visitor->trace(m_toAtEndOfDurationProperty); |
| - visitor->trace(m_animatedProperty); |
| - visitor->trace(m_animator); |
| + visitor->trace(m_animatedValue); |
| + visitor->trace(m_targetProperty); |
| SVGAnimationElement::trace(visitor); |
| } |