summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/svg/SVGAnimateElement.cpp245
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);
+}
+
}