diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp')
-rw-r--r-- | chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp | 245 |
1 files changed, 103 insertions, 142 deletions
diff --git a/chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp b/chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp index 83e30da7fc3..c56ef5cb425 100644 --- a/chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp +++ b/chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp @@ -24,34 +24,35 @@ #include "core/svg/SVGAnimateElement.h" -#include "CSSPropertyNames.h" -#include "core/css/CSSParser.h" +#include "core/CSSPropertyNames.h" +#include "core/css/parser/BisonCSSParser.h" #include "core/css/StylePropertySet.h" +#include "core/dom/Document.h" #include "core/dom/QualifiedName.h" -#include "core/svg/SVGAnimatedType.h" #include "core/svg/SVGAnimatedTypeAnimator.h" -#include "core/svg/SVGAnimatorFactory.h" #include "core/svg/SVGDocumentExtensions.h" namespace WebCore { SVGAnimateElement::SVGAnimateElement(const QualifiedName& tagName, Document& document) : SVGAnimationElement(tagName, document) - , m_animatedPropertyType(AnimatedString) { - ASSERT(hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::setTag) || hasTagName(SVGNames::animateColorTag) || hasTagName(SVGNames::animateTransformTag)); + ASSERT(isSVGAnimateElement(*this)); ScriptWrappable::init(this); } -PassRefPtr<SVGAnimateElement> SVGAnimateElement::create(Document& document) +PassRefPtrWillBeRawPtr<SVGAnimateElement> SVGAnimateElement::create(Document& document) { - return adoptRef(new SVGAnimateElement(SVGNames::animateTag, document)); + return adoptRefWillBeNoop(new SVGAnimateElement(SVGNames::animateTag, document)); } SVGAnimateElement::~SVGAnimateElement() { - if (targetElement()) - clearAnimatedType(targetElement()); +} + +AnimatedPropertyType SVGAnimateElement::animatedPropertyType() +{ + return ensureAnimator()->type(); } bool SVGAnimateElement::hasValidAttributeType() @@ -60,39 +61,7 @@ bool SVGAnimateElement::hasValidAttributeType() if (!targetElement) return false; - return m_animatedPropertyType != AnimatedUnknown && !hasInvalidCSSAttributeType(); -} - -AnimatedPropertyType SVGAnimateElement::determineAnimatedPropertyType(SVGElement* targetElement) const -{ - ASSERT(targetElement); - - Vector<AnimatedPropertyType> propertyTypes; - targetElement->animatedPropertyTypeForAttribute(attributeName(), propertyTypes); - if (propertyTypes.isEmpty()) - return AnimatedUnknown; - - ASSERT(propertyTypes.size() <= 2); - AnimatedPropertyType type = propertyTypes[0]; - if (hasTagName(SVGNames::animateColorTag) && type != AnimatedColor) - return AnimatedUnknown; - - // Animations of transform lists are not allowed for <animate> or <set> - // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties - if (type == AnimatedTransformList && !hasTagName(SVGNames::animateTransformTag)) - return AnimatedUnknown; - - // Fortunately there's just one special case needed here: SVGMarkerElements orientAttr, which - // corresponds to SVGAnimatedAngle orientAngle and SVGAnimatedEnumeration orientType. We have to - // figure out whose value to change here. - if (targetElement->hasTagName(SVGNames::markerTag) && type == AnimatedAngle) { - ASSERT(propertyTypes.size() == 2); - ASSERT(propertyTypes[0] == AnimatedAngle); - ASSERT(propertyTypes[1] == AnimatedEnumeration); - } else if (propertyTypes.size() == 2) - ASSERT(propertyTypes[0] == propertyTypes[1]); - - return type; + return animatedPropertyType() != AnimatedUnknown && !hasInvalidCSSAttributeType(); } void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGSMILElement* resultElement) @@ -102,22 +71,19 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat if (!targetElement || !isSVGAnimateElement(*resultElement)) return; - ASSERT(m_animatedPropertyType == determineAnimatedPropertyType(targetElement)); - ASSERT(percentage >= 0 && percentage <= 1); - ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag)); - ASSERT(m_animatedPropertyType != AnimatedUnknown); ASSERT(m_animator); - ASSERT(m_animator->type() == m_animatedPropertyType); - ASSERT(m_fromType); - ASSERT(m_fromType->type() == m_animatedPropertyType); - ASSERT(m_toType); + ASSERT(animatedPropertyType() != AnimatedTransformList || isSVGAnimateTransformElement(*this)); + ASSERT(animatedPropertyType() != AnimatedUnknown); + ASSERT(m_fromProperty); + ASSERT(m_fromProperty->type() == animatedPropertyType()); + ASSERT(m_toProperty); SVGAnimateElement* resultAnimationElement = toSVGAnimateElement(resultElement); - ASSERT(resultAnimationElement->m_animatedType); - ASSERT(resultAnimationElement->m_animatedPropertyType == m_animatedPropertyType); + ASSERT(resultAnimationElement->m_animatedProperty); + ASSERT(resultAnimationElement->animatedPropertyType() == animatedPropertyType()); - if (hasTagName(SVGNames::setTag)) + if (isSVGSetElement(*this)) percentage = 1; if (calcMode() == CalcModeDiscrete) @@ -126,23 +92,16 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat // Target element might have changed. m_animator->setContextElement(targetElement); - // Be sure to detach list wrappers before we modfiy their underlying value. If we'd do - // if after calculateAnimatedValue() ran the cached pointers in the list propery tear - // offs would point nowhere, and we couldn't create copies of those values anymore, - // while detaching. This is covered by assertions, moving this down would fire them. - if (!m_animatedProperties.isEmpty()) - m_animator->animValWillChange(m_animatedProperties); - // Values-animation accumulates using the last values entry corresponding to the end of duration time. - SVGAnimatedType* toAtEndOfDurationType = m_toAtEndOfDurationType ? m_toAtEndOfDurationType.get() : m_toType.get(); - m_animator->calculateAnimatedValue(percentage, repeatCount, m_fromType.get(), m_toType.get(), toAtEndOfDurationType, resultAnimationElement->m_animatedType.get()); + SVGPropertyBase* toAtEndOfDurationProperty = m_toAtEndOfDurationProperty ? m_toAtEndOfDurationProperty.get() : m_toProperty.get(); + m_animator->calculateAnimatedValue(percentage, repeatCount, m_fromProperty.get(), m_toProperty.get(), toAtEndOfDurationProperty, resultAnimationElement->m_animatedProperty.get()); } bool SVGAnimateElement::calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString) { if (toAtEndOfDurationString.isEmpty()) return false; - m_toAtEndOfDurationType = ensureAnimator()->constructFromString(toAtEndOfDurationString); + m_toAtEndOfDurationProperty = ensureAnimator()->constructFromString(toAtEndOfDurationString); return true; } @@ -153,8 +112,7 @@ bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const return false; determinePropertyValueTypes(fromString, toString); - ensureAnimator()->calculateFromAndToValues(m_fromType, m_toType, fromString, toString); - ASSERT(m_animatedPropertyType == m_animator->type()); + ensureAnimator()->calculateFromAndToValues(m_fromProperty, m_toProperty, fromString, toString); return true; } @@ -171,37 +129,37 @@ bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const if (animationMode() == FromByAnimation && !animatedPropertyTypeSupportsAddition()) return false; - ASSERT(!hasTagName(SVGNames::setTag)); + ASSERT(!isSVGSetElement(*this)); determinePropertyValueTypes(fromString, byString); - ensureAnimator()->calculateFromAndByValues(m_fromType, m_toType, fromString, byString); - ASSERT(m_animatedPropertyType == m_animator->type()); + ensureAnimator()->calculateFromAndByValues(m_fromProperty, m_toProperty, fromString, byString); return true; } -#ifndef NDEBUG -static inline bool propertyTypesAreConsistent(AnimatedPropertyType expectedPropertyType, const SVGElementAnimatedPropertyList& animatedTypes) +namespace { + +WillBeHeapVector<RawPtrWillBeMember<SVGElement> > findElementInstances(SVGElement* targetElement) { - SVGElementAnimatedPropertyList::const_iterator end = animatedTypes.end(); - for (SVGElementAnimatedPropertyList::const_iterator it = animatedTypes.begin(); it != end; ++it) { - for (size_t i = 0; i < it->properties.size(); ++i) { - if (expectedPropertyType != it->properties[i]->animatedPropertyType()) { - // This is the only allowed inconsistency. SVGAnimatedAngleAnimator handles both SVGAnimatedAngle & SVGAnimatedEnumeration for markers orient attribute. - if (expectedPropertyType == AnimatedAngle && it->properties[i]->animatedPropertyType() == AnimatedEnumeration) - return true; - return false; - } - } + ASSERT(targetElement); + WillBeHeapVector<RawPtrWillBeMember<SVGElement> > animatedElements; + + animatedElements.append(targetElement); + + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = targetElement->instancesForElement(); + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end(); + for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) { + if (SVGElement* shadowTreeElement = *it) + animatedElements.append(shadowTreeElement); } - return true; + return animatedElements; +} + } -#endif void SVGAnimateElement::resetAnimatedType() { SVGAnimatedTypeAnimator* animator = ensureAnimator(); - ASSERT(m_animatedPropertyType == animator->type()); SVGElement* targetElement = this->targetElement(); const QualifiedName& attributeName = this->attributeName(); @@ -212,25 +170,22 @@ void SVGAnimateElement::resetAnimatedType() if (shouldApply == ApplyXMLAnimation) { // SVG DOM animVal animation code-path. - m_animatedProperties = animator->findAnimatedPropertiesForAttributeName(targetElement, attributeName); - SVGElementAnimatedPropertyList::const_iterator end = m_animatedProperties.end(); - for (SVGElementAnimatedPropertyList::const_iterator it = m_animatedProperties.begin(); it != end; ++it) - document().accessSVGExtensions()->addElementReferencingTarget(this, it->element); - - ASSERT(!m_animatedProperties.isEmpty()); - - ASSERT(propertyTypesAreConsistent(m_animatedPropertyType, m_animatedProperties)); - if (!m_animatedType) - m_animatedType = animator->startAnimValAnimation(m_animatedProperties); - else { - animator->resetAnimValToBaseVal(m_animatedProperties, m_animatedType.get()); - animator->animValDidChange(m_animatedProperties); - } + WillBeHeapVector<RawPtrWillBeMember<SVGElement> > animatedElements = findElementInstances(targetElement); + ASSERT(!animatedElements.isEmpty()); + + WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator end = animatedElements.end(); + for (WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator it = animatedElements.begin(); it != end; ++it) + document().accessSVGExtensions().addElementReferencingTarget(this, *it); + + if (!m_animatedProperty) + m_animatedProperty = animator->startAnimValAnimation(animatedElements); + else + m_animatedProperty = animator->resetAnimValToBaseVal(animatedElements); + return; } // CSS properties animation code-path. - ASSERT(m_animatedProperties.isEmpty()); String baseValue; if (shouldApply == ApplyCSSAnimation) { @@ -238,15 +193,14 @@ void SVGAnimateElement::resetAnimatedType() computeCSSPropertyValue(targetElement, cssPropertyID(attributeName.localName()), baseValue); } - if (!m_animatedType) - m_animatedType = animator->constructFromString(baseValue); - else - m_animatedType->setValueAsString(attributeName, baseValue); + m_animatedProperty = animator->constructFromString(baseValue); } static inline void applyCSSPropertyToTarget(SVGElement* targetElement, CSSPropertyID id, const String& value) { +#if !ENABLE(OILPAN) ASSERT_WITH_SECURITY_IMPLICATION(!targetElement->m_deletionHasBegun); +#endif MutableStylePropertySet* propertySet = targetElement->ensureAnimatedSMILStyleProperties(); if (!propertySet->setProperty(id, value, false, 0)) @@ -257,7 +211,9 @@ static inline void applyCSSPropertyToTarget(SVGElement* targetElement, CSSProper static inline void removeCSSPropertyFromTarget(SVGElement* targetElement, CSSPropertyID id) { +#if !ENABLE(OILPAN) ASSERT_WITH_SECURITY_IMPLICATION(!targetElement->m_deletionHasBegun); +#endif targetElement->ensureAnimatedSMILStyleProperties()->removeProperty(id); targetElement->setNeedsStyleRecalc(LocalStyleChange); } @@ -270,14 +226,14 @@ static inline void applyCSSPropertyToTargetAndInstances(SVGElement* targetElemen CSSPropertyID id = cssPropertyID(attributeName.localName()); - SVGElementInstance::InstanceUpdateBlocker blocker(targetElement); + SVGElement::InstanceUpdateBlocker blocker(targetElement); applyCSSPropertyToTarget(targetElement, id, valueAsString); // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt. - const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement(); - const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); - for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { - if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement()) + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = targetElement->instancesForElement(); + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end(); + for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) { + if (SVGElement* shadowTreeElement = *it) applyCSSPropertyToTarget(shadowTreeElement, id, valueAsString); } } @@ -290,21 +246,24 @@ static inline void removeCSSPropertyFromTargetAndInstances(SVGElement* targetEle CSSPropertyID id = cssPropertyID(attributeName.localName()); - SVGElementInstance::InstanceUpdateBlocker blocker(targetElement); + SVGElement::InstanceUpdateBlocker blocker(targetElement); removeCSSPropertyFromTarget(targetElement, id); // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt. - const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement(); - const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); - for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { - if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement()) + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = targetElement->instancesForElement(); + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end(); + for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) { + if (SVGElement* shadowTreeElement = *it) removeCSSPropertyFromTarget(shadowTreeElement, id); } } static inline void notifyTargetAboutAnimValChange(SVGElement* targetElement, const QualifiedName& attributeName) { +#if !ENABLE(OILPAN) ASSERT_WITH_SECURITY_IMPLICATION(!targetElement->m_deletionHasBegun); +#endif + targetElement->invalidateSVGAttributes(); targetElement->svgAttributeChanged(attributeName); } @@ -314,73 +273,71 @@ static inline void notifyTargetAndInstancesAboutAnimValChange(SVGElement* target if (attributeName == anyQName() || !targetElement->inDocument() || !targetElement->parentNode()) return; - SVGElementInstance::InstanceUpdateBlocker blocker(targetElement); + SVGElement::InstanceUpdateBlocker blocker(targetElement); notifyTargetAboutAnimValChange(targetElement, attributeName); // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt. - const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement(); - const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); - for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { - if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement()) - notifyTargetAboutAnimValChange(shadowTreeElement, attributeName); + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = targetElement->instancesForElement(); + const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end(); + for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) { + notifyTargetAboutAnimValChange(*it, attributeName); } } void SVGAnimateElement::clearAnimatedType(SVGElement* targetElement) { - if (!m_animatedType) + if (!m_animatedProperty) return; if (!targetElement) { - m_animatedType.clear(); + m_animatedProperty.clear(); return; } - if (m_animatedProperties.isEmpty()) { + if (ensureAnimator()->isAnimatingCSSProperty()) { // CSS properties animation code-path. removeCSSPropertyFromTargetAndInstances(targetElement, attributeName()); - m_animatedType.clear(); + m_animatedProperty.clear(); return; } // SVG DOM animVal animation code-path. if (m_animator) { - m_animator->stopAnimValAnimation(m_animatedProperties); + WillBeHeapVector<RawPtrWillBeMember<SVGElement> > animatedElements = findElementInstances(targetElement); + m_animator->stopAnimValAnimation(animatedElements); notifyTargetAndInstancesAboutAnimValChange(targetElement, attributeName()); } - m_animatedProperties.clear(); - m_animatedType.clear(); + m_animatedProperty.clear(); } void SVGAnimateElement::applyResultsToTarget() { - ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag)); - ASSERT(m_animatedPropertyType != AnimatedUnknown); ASSERT(m_animator); + ASSERT(animatedPropertyType() != AnimatedTransformList || isSVGAnimateTransformElement(*this)); + ASSERT(animatedPropertyType() != AnimatedUnknown); // Early exit if our animated type got destructed by a previous endedActiveInterval(). - if (!m_animatedType) + if (!m_animatedProperty) return; - if (m_animatedProperties.isEmpty()) { + if (m_animator->isAnimatingCSSProperty()) { // CSS properties animation code-path. // Convert the result of the animation to a String and apply it as CSS property on the target & all instances. - applyCSSPropertyToTargetAndInstances(targetElement(), attributeName(), m_animatedType->valueAsString()); + applyCSSPropertyToTargetAndInstances(targetElement(), attributeName(), m_animatedProperty->valueAsString()); return; } // 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. - m_animator->animValDidChange(m_animatedProperties); notifyTargetAndInstancesAboutAnimValChange(targetElement(), attributeName()); } -bool SVGAnimateElement::animatedPropertyTypeSupportsAddition() const +bool SVGAnimateElement::animatedPropertyTypeSupportsAddition() { // Spec: http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties. - switch (m_animatedPropertyType) { + switch (animatedPropertyType()) { case AnimatedBoolean: case AnimatedEnumeration: case AnimatedPreserveAspectRatio: @@ -392,7 +349,7 @@ bool SVGAnimateElement::animatedPropertyTypeSupportsAddition() const } } -bool SVGAnimateElement::isAdditive() const +bool SVGAnimateElement::isAdditive() { if (animationMode() == ByAnimation || animationMode() == FromByAnimation) if (!animatedPropertyTypeSupportsAddition()) @@ -425,20 +382,24 @@ void SVGAnimateElement::setAttributeName(const QualifiedName& attributeName) void SVGAnimateElement::resetAnimatedPropertyType() { - ASSERT(!m_animatedType); - m_fromType.clear(); - m_toType.clear(); - m_toAtEndOfDurationType.clear(); + ASSERT(!m_animatedProperty); + m_fromProperty.clear(); + m_toProperty.clear(); + m_toAtEndOfDurationProperty.clear(); m_animator.clear(); - m_animatedPropertyType = targetElement() ? determineAnimatedPropertyType(targetElement()) : AnimatedString; } SVGAnimatedTypeAnimator* SVGAnimateElement::ensureAnimator() { if (!m_animator) - m_animator = SVGAnimatorFactory::create(this, targetElement(), m_animatedPropertyType); - ASSERT(m_animatedPropertyType == m_animator->type()); + m_animator = SVGAnimatedTypeAnimator::create(this, targetElement()); return m_animator.get(); } +void SVGAnimateElement::trace(Visitor* visitor) +{ + visitor->trace(m_animator); + SVGAnimationElement::trace(visitor); +} + } |