diff options
Diffstat (limited to 'Source/WebCore/svg/SVGAnimationElement.cpp')
-rw-r--r-- | Source/WebCore/svg/SVGAnimationElement.cpp | 212 |
1 files changed, 110 insertions, 102 deletions
diff --git a/Source/WebCore/svg/SVGAnimationElement.cpp b/Source/WebCore/svg/SVGAnimationElement.cpp index 6f228f785..b1457f403 100644 --- a/Source/WebCore/svg/SVGAnimationElement.cpp +++ b/Source/WebCore/svg/SVGAnimationElement.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2008 Apple Inc. All rights reserved. * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,23 +24,23 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGAnimationElement.h" -#include "Attribute.h" #include "CSSComputedStyleDeclaration.h" -#include "CSSParser.h" #include "CSSPropertyNames.h" +#include "CSSPropertyParser.h" #include "Document.h" #include "FloatConversion.h" #include "RenderObject.h" +#include "SVGAnimateColorElement.h" #include "SVGAnimateElement.h" #include "SVGElement.h" -#include "SVGElementInstance.h" #include "SVGNames.h" #include "SVGParserUtilities.h" +#include "SVGStringList.h" #include <wtf/MathExtras.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/text/StringView.h> namespace WebCore { @@ -53,13 +54,6 @@ END_REGISTER_ANIMATED_PROPERTIES SVGAnimationElement::SVGAnimationElement(const QualifiedName& tagName, Document& document) : SVGSMILElement(tagName, document) - , m_fromPropertyValueType(RegularPropertyValue) - , m_toPropertyValueType(RegularPropertyValue) - , m_animationValid(false) - , m_attributeType(AttributeTypeAuto) - , m_hasInvalidCSSAttributeType(false) - , m_calcMode(CalcModeLinear) - , m_animationMode(NoAnimation) { registerAnimatedPropertiesForSVGAnimationElement(); } @@ -94,7 +88,9 @@ static void parseKeySplines(const String& parse, Vector<UnitBezier>& result) result.clear(); if (parse.isEmpty()) return; - const UChar* cur = parse.deprecatedCharacters(); + + auto upconvertedCharacters = StringView(parse).upconvertedCharacters(); + const UChar* cur = upconvertedCharacters; const UChar* end = cur + parse.length(); skipOptionalSVGSpaces(cur, end); @@ -142,37 +138,32 @@ static void parseKeySplines(const String& parse, Vector<UnitBezier>& result) bool SVGAnimationElement::isSupportedAttribute(const QualifiedName& attrName) { - DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); - if (supportedAttributes.isEmpty()) { + static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes; + if (supportedAttributes.get().isEmpty()) { SVGTests::addSupportedAttributes(supportedAttributes); SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes); - supportedAttributes.add(SVGNames::valuesAttr); - supportedAttributes.add(SVGNames::keyTimesAttr); - supportedAttributes.add(SVGNames::keyPointsAttr); - supportedAttributes.add(SVGNames::keySplinesAttr); - supportedAttributes.add(SVGNames::attributeTypeAttr); - supportedAttributes.add(SVGNames::calcModeAttr); - supportedAttributes.add(SVGNames::fromAttr); - supportedAttributes.add(SVGNames::toAttr); - supportedAttributes.add(SVGNames::byAttr); + supportedAttributes.get().add(SVGNames::valuesAttr); + supportedAttributes.get().add(SVGNames::keyTimesAttr); + supportedAttributes.get().add(SVGNames::keyPointsAttr); + supportedAttributes.get().add(SVGNames::keySplinesAttr); + supportedAttributes.get().add(SVGNames::attributeTypeAttr); + supportedAttributes.get().add(SVGNames::calcModeAttr); + supportedAttributes.get().add(SVGNames::fromAttr); + supportedAttributes.get().add(SVGNames::toAttr); + supportedAttributes.get().add(SVGNames::byAttr); } - return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); + return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName); } void SVGAnimationElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { - if (!isSupportedAttribute(name)) { - SVGSMILElement::parseAttribute(name, value); - return; - } - if (name == SVGNames::valuesAttr) { // Per the SMIL specification, leading and trailing white space, // and white space before and after semicolon separators, is allowed and will be ignored. // http://www.w3.org/TR/SVG11/animate.html#ValuesAttribute value.string().split(';', m_values); - for (unsigned i = 0; i < m_values.size(); ++i) - m_values[i] = m_values[i].stripWhiteSpace(); + for (auto& value : m_values) + value = value.stripWhiteSpace(); updateAnimationMode(); return; @@ -212,12 +203,9 @@ void SVGAnimationElement::parseAttribute(const QualifiedName& name, const Atomic return; } - if (SVGTests::parseAttribute(name, value)) - return; - if (SVGExternalResourcesRequired::parseAttribute(name, value)) - return; - - ASSERT_NOT_REACHED(); + SVGSMILElement::parseAttribute(name, value); + SVGTests::parseAttribute(name, value); + SVGExternalResourcesRequired::parseAttribute(name, value); } void SVGAnimationElement::svgAttributeChanged(const QualifiedName& attrName) @@ -247,7 +235,7 @@ float SVGAnimationElement::getCurrentTime() const return narrowPrecisionToFloat(elapsed().value()); } -float SVGAnimationElement::getSimpleDuration(ExceptionCode&) const +float SVGAnimationElement::getSimpleDuration() const { return narrowPrecisionToFloat(simpleDuration().value()); } @@ -293,66 +281,70 @@ void SVGAnimationElement::updateAnimationMode() void SVGAnimationElement::setCalcMode(const AtomicString& calcMode) { - DEFINE_STATIC_LOCAL(const AtomicString, discrete, ("discrete", AtomicString::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const AtomicString, linear, ("linear", AtomicString::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const AtomicString, paced, ("paced", AtomicString::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const AtomicString, spline, ("spline", AtomicString::ConstructFromLiteral)); + static NeverDestroyed<const AtomicString> discrete("discrete", AtomicString::ConstructFromLiteral); + static NeverDestroyed<const AtomicString> linear("linear", AtomicString::ConstructFromLiteral); + static NeverDestroyed<const AtomicString> paced("paced", AtomicString::ConstructFromLiteral); + static NeverDestroyed<const AtomicString> spline("spline", AtomicString::ConstructFromLiteral); if (calcMode == discrete) - setCalcMode(CalcModeDiscrete); + setCalcMode(CalcMode::Discrete); else if (calcMode == linear) - setCalcMode(CalcModeLinear); + setCalcMode(CalcMode::Linear); else if (calcMode == paced) - setCalcMode(CalcModePaced); + setCalcMode(CalcMode::Paced); else if (calcMode == spline) - setCalcMode(CalcModeSpline); + setCalcMode(CalcMode::Spline); else - setCalcMode(hasTagName(SVGNames::animateMotionTag) ? CalcModePaced : CalcModeLinear); + setCalcMode(hasTagName(SVGNames::animateMotionTag) ? CalcMode::Paced : CalcMode::Linear); } void SVGAnimationElement::setAttributeType(const AtomicString& attributeType) { - DEFINE_STATIC_LOCAL(const AtomicString, css, ("CSS", AtomicString::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const AtomicString, xml, ("XML", AtomicString::ConstructFromLiteral)); + static NeverDestroyed<const AtomicString> css("CSS", AtomicString::ConstructFromLiteral); + static NeverDestroyed<const AtomicString> xml("XML", AtomicString::ConstructFromLiteral); if (attributeType == css) - m_attributeType = AttributeTypeCSS; + m_attributeType = AttributeType::CSS; else if (attributeType == xml) - m_attributeType = AttributeTypeXML; + m_attributeType = AttributeType::XML; else - m_attributeType = AttributeTypeAuto; + m_attributeType = AttributeType::Auto; checkInvalidCSSAttributeType(targetElement()); } String SVGAnimationElement::toValue() const { - return fastGetAttribute(SVGNames::toAttr); + return attributeWithoutSynchronization(SVGNames::toAttr); } String SVGAnimationElement::byValue() const { - return fastGetAttribute(SVGNames::byAttr); + return attributeWithoutSynchronization(SVGNames::byAttr); } String SVGAnimationElement::fromValue() const { - return fastGetAttribute(SVGNames::fromAttr); + return attributeWithoutSynchronization(SVGNames::fromAttr); } bool SVGAnimationElement::isAdditive() const { - DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum", AtomicString::ConstructFromLiteral)); - const AtomicString& value = fastGetAttribute(SVGNames::additiveAttr); + static NeverDestroyed<const AtomicString> sum("sum", AtomicString::ConstructFromLiteral); + const AtomicString& value = attributeWithoutSynchronization(SVGNames::additiveAttr); return value == sum || animationMode() == ByAnimation; } bool SVGAnimationElement::isAccumulated() const { - DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum", AtomicString::ConstructFromLiteral)); - const AtomicString& value = fastGetAttribute(SVGNames::accumulateAttr); + static NeverDestroyed<const AtomicString> sum("sum", AtomicString::ConstructFromLiteral); + const AtomicString& value = attributeWithoutSynchronization(SVGNames::accumulateAttr); return value == sum && animationMode() != ToAnimation; } -bool SVGAnimationElement::isTargetAttributeCSSProperty(SVGElement*, const QualifiedName& attributeName) +bool SVGAnimationElement::isTargetAttributeCSSProperty(SVGElement* element, const QualifiedName& attributeName) { + if (element->isTextContent() + && (attributeName == SVGNames::xAttr || attributeName == SVGNames::yAttr)) + return false; + return SVGElement::isAnimatableCSSProperty(attributeName); } @@ -362,11 +354,15 @@ SVGAnimationElement::ShouldApplyAnimation SVGAnimationElement::shouldApplyAnimat return DontApplyAnimation; // Always animate CSS properties, using the ApplyCSSAnimation code path, regardless of the attributeType value. - if (isTargetAttributeCSSProperty(targetElement, attributeName)) + if (isTargetAttributeCSSProperty(targetElement, attributeName)) { + if (targetElement->isPresentationAttributeWithSVGDOM(attributeName)) + return ApplyXMLandCSSAnimation; return ApplyCSSAnimation; + } + // If attributeType="CSS" and attributeName doesn't point to a CSS property, ignore the animation. - if (attributeType() == AttributeTypeCSS) + if (attributeType() == AttributeType::CSS) return DontApplyAnimation; return ApplyXMLAnimation; @@ -374,7 +370,7 @@ SVGAnimationElement::ShouldApplyAnimation SVGAnimationElement::shouldApplyAnimat void SVGAnimationElement::calculateKeyTimesForCalcModePaced() { - ASSERT(calcMode() == CalcModePaced); + ASSERT(calcMode() == CalcMode::Paced); ASSERT(animationMode() == ValuesAnimation); unsigned valuesCount = m_values.size(); @@ -426,7 +422,7 @@ unsigned SVGAnimationElement::calculateKeyTimesIndex(float percent) const float SVGAnimationElement::calculatePercentForSpline(float percent, unsigned splineIndex) const { - ASSERT(calcMode() == CalcModeSpline); + ASSERT(calcMode() == CalcMode::Spline); ASSERT_WITH_SECURITY_IMPLICATION(splineIndex < m_keySplines.size()); UnitBezier bezier = m_keySplines[splineIndex]; SMILTime duration = simpleDuration(); @@ -438,7 +434,7 @@ float SVGAnimationElement::calculatePercentForSpline(float percent, unsigned spl float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const { ASSERT(!m_keyPoints.isEmpty()); - ASSERT(calcMode() != CalcModePaced); + ASSERT(calcMode() != CalcMode::Paced); ASSERT(m_keyTimes.size() > 1); ASSERT(m_keyPoints.size() == m_keyTimes.size()); @@ -451,12 +447,12 @@ float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const float fromKeyPoint = m_keyPoints[index]; float toKeyPoint = m_keyPoints[index + 1]; - if (calcMode() == CalcModeDiscrete) + if (calcMode() == CalcMode::Discrete) return fromKeyPoint; float keyPointPercent = (percent - fromPercent) / (toPercent - fromPercent); - if (calcMode() == CalcModeSpline) { + if (calcMode() == CalcMode::Spline) { ASSERT(m_keySplines.size() == m_keyPoints.size() - 1); keyPointPercent = calculatePercentForSpline(keyPointPercent, index); } @@ -465,7 +461,7 @@ float SVGAnimationElement::calculatePercentFromKeyPoints(float percent) const float SVGAnimationElement::calculatePercentForFromTo(float percent) const { - if (calcMode() == CalcModeDiscrete && m_keyTimes.size() == 2) + if (calcMode() == CalcMode::Discrete && m_keyTimes.size() == 2) return percent > m_keyTimes[1] ? 1 : 0; return percent; @@ -475,7 +471,7 @@ void SVGAnimationElement::currentValuesFromKeyPoints(float percent, float& effec { ASSERT(!m_keyPoints.isEmpty()); ASSERT(m_keyPoints.size() == m_keyTimes.size()); - ASSERT(calcMode() != CalcModePaced); + ASSERT(calcMode() != CalcMode::Paced); effectivePercent = calculatePercentFromKeyPoints(percent); unsigned index = effectivePercent == 1 ? m_values.size() - 2 : static_cast<unsigned>(effectivePercent * (m_values.size() - 1)); from = m_values[index]; @@ -496,16 +492,13 @@ void SVGAnimationElement::currentValuesForValuesAnimation(float percent, float& } CalcMode calcMode = this->calcMode(); - if (hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::animateColorTag)) { - AnimatedPropertyType attributeType = toSVGAnimateElement(this)->determineAnimatedPropertyType(targetElement()); - // Fall back to discrete animations for Strings. - if (attributeType == AnimatedBoolean - || attributeType == AnimatedEnumeration - || attributeType == AnimatedPreserveAspectRatio - || attributeType == AnimatedString) - calcMode = CalcModeDiscrete; + if (is<SVGAnimateElement>(*this) || is<SVGAnimateColorElement>(*this)) { + ASSERT(targetElement()); + AnimatedPropertyType type = downcast<SVGAnimateElementBase>(*this).determineAnimatedPropertyType(*targetElement()); + if (type == AnimatedBoolean || type == AnimatedEnumeration || type == AnimatedPreserveAspectRatio || type == AnimatedString) + calcMode = CalcMode::Discrete; } - if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced) + if (!m_keyPoints.isEmpty() && calcMode != CalcMode::Paced) return currentValuesFromKeyPoints(percent, effectivePercent, from, to); unsigned keyTimesCount = m_keyTimes.size(); @@ -513,7 +506,7 @@ void SVGAnimationElement::currentValuesForValuesAnimation(float percent, float& ASSERT(!keyTimesCount || (keyTimesCount > 1 && !m_keyTimes[0])); unsigned index = calculateKeyTimesIndex(percent); - if (calcMode == CalcModeDiscrete) { + if (calcMode == CalcMode::Discrete) { if (!keyTimesCount) index = static_cast<unsigned>(percent * valuesCount); from = m_values[index]; @@ -540,7 +533,7 @@ void SVGAnimationElement::currentValuesForValuesAnimation(float percent, float& ASSERT_WITH_SECURITY_IMPLICATION(toPercent > fromPercent); effectivePercent = (percent - fromPercent) / (toPercent - fromPercent); - if (calcMode == CalcModeSpline) { + if (calcMode == CalcMode::Spline) { ASSERT(m_keySplines.size() == m_values.size() - 1); effectivePercent = calculatePercentForSpline(effectivePercent, index); } @@ -554,17 +547,17 @@ void SVGAnimationElement::startedActiveInterval() return; // These validations are appropriate for all animation modes. - if (fastHasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() != m_keyTimes.size()) + if (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && m_keyPoints.size() != m_keyTimes.size()) return; AnimationMode animationMode = this->animationMode(); CalcMode calcMode = this->calcMode(); - if (calcMode == CalcModeSpline) { + if (calcMode == CalcMode::Spline) { unsigned splinesCount = m_keySplines.size(); if (!splinesCount - || (fastHasAttribute(SVGNames::keyPointsAttr) && m_keyPoints.size() - 1 != splinesCount) + || (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && m_keyPoints.size() - 1 != splinesCount) || (animationMode == ValuesAnimation && m_values.size() - 1 != splinesCount) - || (fastHasAttribute(SVGNames::keyTimesAttr) && m_keyTimes.size() - 1 != splinesCount)) + || (hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) && m_keyTimes.size() - 1 != splinesCount)) return; } @@ -573,6 +566,9 @@ void SVGAnimationElement::startedActiveInterval() String by = byValue(); if (animationMode == NoAnimation) return; + if ((animationMode == FromToAnimation || animationMode == FromByAnimation || animationMode == ToAnimation || animationMode == ByAnimation) + && (hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) && hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) && (m_keyTimes.size() < 2 || m_keyTimes.size() != m_keyPoints.size()))) + return; if (animationMode == FromToAnimation) m_animationValid = calculateFromAndToValues(from, to); else if (animationMode == ToAnimation) { @@ -585,16 +581,16 @@ void SVGAnimationElement::startedActiveInterval() m_animationValid = calculateFromAndByValues(emptyString(), by); else if (animationMode == ValuesAnimation) { m_animationValid = m_values.size() >= 1 - && (calcMode == CalcModePaced || !fastHasAttribute(SVGNames::keyTimesAttr) || fastHasAttribute(SVGNames::keyPointsAttr) || (m_values.size() == m_keyTimes.size())) - && (calcMode == CalcModeDiscrete || !m_keyTimes.size() || m_keyTimes.last() == 1) - && (calcMode != CalcModeSpline || ((m_keySplines.size() && (m_keySplines.size() == m_values.size() - 1)) || m_keySplines.size() == m_keyPoints.size() - 1)) - && (!fastHasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size())); + && (calcMode == CalcMode::Paced || !hasAttributeWithoutSynchronization(SVGNames::keyTimesAttr) || hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (m_values.size() == m_keyTimes.size())) + && (calcMode == CalcMode::Discrete || !m_keyTimes.size() || m_keyTimes.last() == 1) + && (calcMode != CalcMode::Spline || ((m_keySplines.size() && (m_keySplines.size() == m_values.size() - 1)) || m_keySplines.size() == m_keyPoints.size() - 1)) + && (!hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size())); if (m_animationValid) m_animationValid = calculateToAtEndOfDurationValue(m_values.last()); - if (calcMode == CalcModePaced && m_animationValid) + if (calcMode == CalcMode::Paced && m_animationValid) calculateKeyTimesForCalcModePaced(); } else if (animationMode == PathAnimation) - m_animationValid = calcMode == CalcModePaced || !fastHasAttribute(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size()); + m_animationValid = calcMode == CalcMode::Paced || !hasAttributeWithoutSynchronization(SVGNames::keyPointsAttr) || (m_keyTimes.size() > 1 && m_keyTimes.size() == m_keyPoints.size()); } void SVGAnimationElement::updateAnimation(float percent, unsigned repeatCount, SVGSMILElement* resultElement) @@ -616,9 +612,9 @@ void SVGAnimationElement::updateAnimation(float percent, unsigned repeatCount, S m_lastValuesAnimationFrom = from; m_lastValuesAnimationTo = to; } - } else if (!m_keyPoints.isEmpty() && calcMode != CalcModePaced) + } else if (!m_keyPoints.isEmpty() && calcMode != CalcMode::Paced) effectivePercent = calculatePercentFromKeyPoints(percent); - else if (m_keyPoints.isEmpty() && calcMode == CalcModeSpline && m_keyTimes.size() > 1) + else if (m_keyPoints.isEmpty() && calcMode == CalcMode::Spline && m_keyTimes.size() > 1) effectivePercent = calculatePercentForSpline(percent, calculateKeyTimesIndex(percent)); else if (animationMode == FromToAnimation || animationMode == ToAnimation) effectivePercent = calculatePercentForFromTo(percent); @@ -649,13 +645,13 @@ void SVGAnimationElement::adjustForInheritance(SVGElement* targetElement, const if (!parent || !parent->isSVGElement()) return; - SVGElement* svgParent = toSVGElement(parent); - computeCSSPropertyValue(svgParent, cssPropertyID(attributeName.localName()), value); + SVGElement& svgParent = downcast<SVGElement>(*parent); + computeCSSPropertyValue(&svgParent, cssPropertyID(attributeName.localName()), value); } static bool inheritsFromProperty(SVGElement*, const QualifiedName& attributeName, const String& value) { - DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit", AtomicString::ConstructFromLiteral)); + static NeverDestroyed<const AtomicString> inherit("inherit", AtomicString::ConstructFromLiteral); if (value.isEmpty() || value != inherit) return false; @@ -673,6 +669,11 @@ void SVGAnimationElement::determinePropertyValueTypes(const String& from, const if (inheritsFromProperty(targetElement, attributeName, to)) m_toPropertyValueType = InheritValue; } +void SVGAnimationElement::resetAnimatedPropertyType() +{ + m_lastValuesAnimationFrom = String(); + m_lastValuesAnimationTo = String(); +} void SVGAnimationElement::setTargetElement(SVGElement* target) { @@ -680,17 +681,24 @@ void SVGAnimationElement::setTargetElement(SVGElement* target) checkInvalidCSSAttributeType(target); } -void SVGAnimationElement::setAttributeName(const QualifiedName& attributeName) +void SVGAnimationElement::checkInvalidCSSAttributeType(SVGElement* target) { - SVGSMILElement::setAttributeName(attributeName); - checkInvalidCSSAttributeType(targetElement()); + m_hasInvalidCSSAttributeType = target && hasValidAttributeName() && attributeType() == AttributeType::CSS && !isTargetAttributeCSSProperty(target, attributeName()); } -void SVGAnimationElement::checkInvalidCSSAttributeType(SVGElement* target) +Ref<SVGStringList> SVGAnimationElement::requiredFeatures() { - m_hasInvalidCSSAttributeType = target && hasValidAttributeName() && attributeType() == AttributeTypeCSS && !isTargetAttributeCSSProperty(target, attributeName()); + return SVGTests::requiredFeatures(*this); } +Ref<SVGStringList> SVGAnimationElement::requiredExtensions() +{ + return SVGTests::requiredExtensions(*this); } -#endif // ENABLE(SVG) +Ref<SVGStringList> SVGAnimationElement::systemLanguage() +{ + return SVGTests::systemLanguage(*this); +} + +} |