diff options
author | Ben Murdoch <benm@google.com> | 2011-05-24 11:24:40 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-02 09:53:15 +0100 |
commit | 81bc750723a18f21cd17d1b173cd2a4dda9cea6e (patch) | |
tree | 7a9e5ed86ff429fd347a25153107221543909b19 /Source/WebCore/svg/SVGAnimateElement.cpp | |
parent | 94088a6d336c1dd80a1e734af51e96abcbb689a7 (diff) | |
download | external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.zip external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.gz external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.bz2 |
Merge WebKit at r80534: Intial merge by Git
Change-Id: Ia7a83357124c9e1cdb1debf55d9661ec0bd09a61
Diffstat (limited to 'Source/WebCore/svg/SVGAnimateElement.cpp')
-rw-r--r-- | Source/WebCore/svg/SVGAnimateElement.cpp | 291 |
1 files changed, 215 insertions, 76 deletions
diff --git a/Source/WebCore/svg/SVGAnimateElement.cpp b/Source/WebCore/svg/SVGAnimateElement.cpp index 0dfe086..33ca46b 100644 --- a/Source/WebCore/svg/SVGAnimateElement.cpp +++ b/Source/WebCore/svg/SVGAnimateElement.cpp @@ -24,6 +24,8 @@ #if ENABLE(SVG) && ENABLE(SVG_ANIMATION) #include "SVGAnimateElement.h" +#include "CSSComputedStyleDeclaration.h" +#include "CSSParser.h" #include "CSSPropertyNames.h" #include "ColorDistance.h" #include "FloatConversion.h" @@ -35,6 +37,7 @@ #include "SVGPathParserFactory.h" #include "SVGPathSegList.h" #include "SVGPointList.h" +#include "SVGStyledElement.h" using namespace std; @@ -42,7 +45,7 @@ namespace WebCore { SVGAnimateElement::SVGAnimateElement(const QualifiedName& tagName, Document* document) : SVGAnimationElement(tagName, document) - , m_propertyType(StringProperty) + , m_animatedAttributeType(AnimatedString) , m_fromNumber(0) , m_toNumber(0) , m_animatedNumber(numeric_limits<double>::infinity()) @@ -85,55 +88,125 @@ static bool parseNumberValueAndUnit(const String& in, double& value, String& uni return ok; } -static inline bool adjustForCurrentColor(Color& color, const String& value, SVGElement* target) +static inline void adjustForCurrentColor(SVGElement* targetElement, Color& color) { - if (!target || !target->isStyled() || value != "currentColor") - return false; + ASSERT(targetElement); - if (RenderObject* targetRenderer = target->renderer()) + if (RenderObject* targetRenderer = targetElement->renderer()) color = targetRenderer->style()->visitedDependentColor(CSSPropertyColor); + else + color = Color(); +} - return true; +static inline void adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String& value) +{ + // FIXME: At the moment the computed style gets returned as a String and needs to get parsed again. + // In the future we might want to work with the value type directly to avoid the String parsing. + ASSERT(targetElement); + + Element* parent = targetElement->parentElement(); + if (!parent || !parent->isSVGElement()) + return; + + SVGElement* svgParent = static_cast<SVGElement*>(parent); + if (svgParent->isStyled()) + value = computedStyle(svgParent)->getPropertyValue(cssPropertyID(attributeName.localName())); +} + +bool SVGAnimateElement::hasValidAttributeType() const +{ + SVGElement* targetElement = this->targetElement(); + if (!targetElement) + return false; + + return determineAnimatedAttributeType(targetElement) != AnimatedUnknown; } -SVGAnimateElement::PropertyType SVGAnimateElement::determinePropertyType(const String& attribute) const +AnimatedAttributeType SVGAnimateElement::determineAnimatedAttributeType(SVGElement* targetElement) const { - // FIXME: We should not allow animation of attribute types other than AnimatedColor for <animateColor>. - if (hasTagName(SVGNames::animateColorTag)) - return ColorProperty; - - // FIXME: Now that we have a full property table we need a more granular type specific animation. - AnimatedAttributeType type = targetElement()->animatedPropertyTypeForAttribute(QualifiedName(nullAtom, attribute, nullAtom)); - if (type == AnimatedColor) - return ColorProperty; - if (type == AnimatedPath) - return PathProperty; - if (type == AnimatedPoints) - return PointsProperty; - return NumberProperty; + ASSERT(targetElement); + + AnimatedAttributeType type = targetElement->animatedPropertyTypeForAttribute(attributeName()); + if (type == AnimatedUnknown || (hasTagName(SVGNames::animateColorTag) && type != AnimatedColor)) + return AnimatedUnknown; + + // FIXME: We need type specific animations in the future. Many animations marked as AnimatedString today will + // support continuous animations. + switch (type) { + case AnimatedBoolean: + case AnimatedEnumeration: + case AnimatedLengthList: + case AnimatedNumberList: + case AnimatedNumberOptionalNumber: + case AnimatedPreserveAspectRatio: + case AnimatedRect: + case AnimatedString: + return AnimatedString; + case AnimatedAngle: + case AnimatedInteger: + case AnimatedLength: + case AnimatedNumber: + return AnimatedNumber; + case AnimatedPath: + return AnimatedPath; + case AnimatedPoints: + return AnimatedPoints; + case AnimatedColor: + return AnimatedColor; + case AnimatedUnknown: + case AnimatedTransformList: + // Animations of transform lists are not allowed for <animate> or <set> + // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties + return AnimatedUnknown; + } + + ASSERT_NOT_REACHED(); + return AnimatedUnknown; } void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement) { - ASSERT(percentage >= 0.f && percentage <= 1.f); + ASSERT(percentage >= 0 && percentage <= 1); ASSERT(resultElement); - bool isInFirstHalfOfAnimation = percentage < 0.5; + bool isInFirstHalfOfAnimation = percentage < 0.5f; AnimationMode animationMode = this->animationMode(); + SVGElement* targetElement = 0; + // Avoid targetElement() call if possible. It might slow down animations. + if (m_fromPropertyValueType == InheritValue || m_toPropertyValueType == InheritValue + || m_fromPropertyValueType == CurrentColorValue || m_toPropertyValueType == CurrentColorValue) { + targetElement = this->targetElement(); + if (!targetElement) + return; + } if (hasTagName(SVGNames::setTag)) - percentage = 1.f; + percentage = 1; if (!resultElement->hasTagName(SVGNames::animateTag) && !resultElement->hasTagName(SVGNames::animateColorTag) && !resultElement->hasTagName(SVGNames::setTag)) return; SVGAnimateElement* results = static_cast<SVGAnimateElement*>(resultElement); // Can't accumulate over a string property. - if (results->m_propertyType == StringProperty && m_propertyType != StringProperty) + if (results->m_animatedAttributeType == AnimatedString && m_animatedAttributeType != AnimatedString) return; - if (m_propertyType == NumberProperty) { + if (m_animatedAttributeType == AnimatedNumber) { // To animation uses contributions from the lower priority animations as the base value. if (animationMode == ToAnimation) m_fromNumber = results->m_animatedNumber; + // Replace 'currentColor' / 'inherit' by their computed property values. + if (m_fromPropertyValueType == InheritValue) { + String fromNumberString; + adjustForInheritance(targetElement, attributeName(), fromNumberString); + if (!parseNumberValueAndUnit(fromNumberString, m_fromNumber, m_numberUnit)) + return; + } + if (m_toPropertyValueType == InheritValue) { + String toNumberString; + adjustForInheritance(targetElement, attributeName(), toNumberString); + if (!parseNumberValueAndUnit(toNumberString, m_toNumber, m_numberUnit)) + return; + } + double number; if (calcMode() == CalcModeDiscrete) number = isInFirstHalfOfAnimation ? m_fromNumber : m_toNumber; @@ -149,9 +222,26 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat results->m_animatedNumber = number; return; } - if (m_propertyType == ColorProperty) { + if (m_animatedAttributeType == AnimatedColor) { if (animationMode == ToAnimation) m_fromColor = results->m_animatedColor; + + // Replace 'currentColor' / 'inherit' by their computed property values. + if (m_fromPropertyValueType == CurrentColorValue) + adjustForCurrentColor(targetElement, m_fromColor); + else if (m_fromPropertyValueType == InheritValue) { + String fromColorString; + adjustForInheritance(targetElement, attributeName(), fromColorString); + m_fromColor = SVGColor::colorFromRGBColorString(fromColorString); + } + if (m_toPropertyValueType == CurrentColorValue) + adjustForCurrentColor(targetElement, m_toColor); + else if (m_toPropertyValueType == InheritValue) { + String toColorString; + adjustForInheritance(targetElement, attributeName(), toColorString); + m_toColor = SVGColor::colorFromRGBColorString(toColorString); + } + Color color; if (calcMode() == CalcModeDiscrete) color = isInFirstHalfOfAnimation ? m_fromColor : m_toColor; @@ -165,7 +255,7 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat results->m_animatedColor = color; return; } - if (m_propertyType == PathProperty) { + if (m_animatedAttributeType == AnimatedPath) { if (animationMode == ToAnimation) { ASSERT(results->m_animatedPathPointer); m_fromPath = results->m_animatedPathPointer->copy(); @@ -174,7 +264,7 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat ASSERT(m_fromPath); ASSERT(percentage >= 0); results->m_animatedPathPointer = m_fromPath.get(); - } else if (percentage == 1.f) { + } else if (percentage == 1) { ASSERT(m_toPath); results->m_animatedPathPointer = m_toPath.get(); } else { @@ -192,16 +282,16 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat ASSERT(m_fromPath); ASSERT(m_toPath); ASSERT(!results->m_animatedPath); - results->m_animatedPathPointer = ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1.0f) + results->m_animatedPathPointer = ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1) ? m_toPath.get() : m_fromPath.get(); } } return; } - if (m_propertyType == PointsProperty) { + if (m_animatedAttributeType == AnimatedPoints) { if (!percentage) results->m_animatedPoints = m_fromPoints; - else if (percentage == 1.f) + else if (percentage == 1) results->m_animatedPoints = m_toPoints; else { if (!m_fromPoints.isEmpty() && !m_toPoints.isEmpty()) @@ -210,40 +300,75 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat results->m_animatedPoints.clear(); // Fall back to discrete animation if the points are not compatible if (results->m_animatedPoints.isEmpty()) - results->m_animatedPoints = ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1.0f) + results->m_animatedPoints = ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1) ? m_toPoints : m_fromPoints; } return; } ASSERT(animationMode == FromToAnimation || animationMode == ToAnimation || animationMode == ValuesAnimation); - if ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1.0f) + // Replace 'currentColor' / 'inherit' by their computed property values. + if (m_fromPropertyValueType == InheritValue) + adjustForInheritance(targetElement, attributeName(), m_fromString); + if (m_toPropertyValueType == InheritValue) + adjustForInheritance(targetElement, attributeName(), m_toString); + + if ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1) results->m_animatedString = m_toString; else results->m_animatedString = m_fromString; // Higher priority replace animation overrides any additive results so far. - results->m_propertyType = StringProperty; + results->m_animatedAttributeType = AnimatedString; +} + +static bool inheritsFromProperty(SVGElement* targetElement, const QualifiedName& attributeName, const String& value) +{ + ASSERT(targetElement); + DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit")); + + if (value.isEmpty() || value != inherit || !targetElement->isStyled()) + return false; + return SVGStyledElement::isAnimatableCSSProperty(attributeName); +} + +static bool attributeValueIsCurrentColor(const String& value) +{ + DEFINE_STATIC_LOCAL(const AtomicString, currentColor, ("currentColor")); + return value == currentColor; } bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const String& toString) { + SVGElement* targetElement = this->targetElement(); + if (!targetElement) + return false; + m_fromPropertyValueType = inheritsFromProperty(targetElement, attributeName(), fromString) ? InheritValue : RegularPropertyValue; + m_toPropertyValueType = inheritsFromProperty(targetElement, attributeName(), toString) ? InheritValue : RegularPropertyValue; + // FIXME: Needs more solid way determine target attribute type. - m_propertyType = determinePropertyType(attributeName()); - if (m_propertyType == ColorProperty) { - SVGElement* targetElement = this->targetElement(); - if (!adjustForCurrentColor(m_fromColor, fromString, targetElement)) + m_animatedAttributeType = determineAnimatedAttributeType(targetElement); + if (m_animatedAttributeType == AnimatedColor) { + bool fromIsCurrentColor = attributeValueIsCurrentColor(fromString); + bool toIsCurrentColor = attributeValueIsCurrentColor(toString); + if (fromIsCurrentColor) + m_fromPropertyValueType = CurrentColorValue; + else m_fromColor = SVGColor::colorFromRGBColorString(fromString); - if (!adjustForCurrentColor(m_toColor, toString, targetElement)) + if (toIsCurrentColor) + m_toPropertyValueType = CurrentColorValue; + else m_toColor = SVGColor::colorFromRGBColorString(toString); - if ((m_fromColor.isValid() && m_toColor.isValid()) || (m_toColor.isValid() && animationMode() == ToAnimation)) + bool fromIsValid = m_fromColor.isValid() || fromIsCurrentColor || m_fromPropertyValueType == InheritValue; + bool toIsValid = m_toColor.isValid() || toIsCurrentColor || m_toPropertyValueType == InheritValue; + if ((fromIsValid && toIsValid) || (toIsValid && animationMode() == ToAnimation)) return true; - } else if (m_propertyType == NumberProperty) { + } else if (m_animatedAttributeType == AnimatedNumber) { m_numberUnit = String(); if (parseNumberValueAndUnit(toString, m_toNumber, m_numberUnit)) { // For to-animations the from number is calculated later if (animationMode() == ToAnimation || parseNumberValueAndUnit(fromString, m_fromNumber, m_numberUnit)) return true; } - } else if (m_propertyType == PathProperty) { + } else if (m_animatedAttributeType == AnimatedPath) { SVGPathParserFactory* factory = SVGPathParserFactory::self(); if (factory->buildSVGPathByteStreamFromString(toString, m_toPath, UnalteredParsing)) { // For to-animations the from number is calculated later @@ -252,7 +377,7 @@ bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const } m_fromPath.clear(); m_toPath.clear(); - } else if (m_propertyType == PointsProperty) { + } else if (m_animatedAttributeType == AnimatedPoints) { m_fromPoints.clear(); if (pointsListFromSVGData(m_fromPoints, fromString)) { m_toPoints.clear(); @@ -262,22 +387,34 @@ bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const } m_fromString = fromString; m_toString = toString; - m_propertyType = StringProperty; + m_animatedAttributeType = AnimatedString; return true; } bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const String& byString) { + SVGElement* targetElement = this->targetElement(); + if (!targetElement) + return false; + m_fromPropertyValueType = inheritsFromProperty(targetElement, attributeName(), fromString) ? InheritValue : RegularPropertyValue; + m_toPropertyValueType = inheritsFromProperty(targetElement, attributeName(), byString) ? InheritValue : RegularPropertyValue; + ASSERT(!hasTagName(SVGNames::setTag)); - m_propertyType = determinePropertyType(attributeName()); - if (m_propertyType == ColorProperty) { - SVGElement* targetElement = this->targetElement(); - if (!adjustForCurrentColor(m_fromColor, fromString, targetElement)) - m_fromColor = fromString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(fromString); - if (!adjustForCurrentColor(m_toColor, byString, targetElement)) + m_animatedAttributeType = determineAnimatedAttributeType(targetElement); + if (m_animatedAttributeType == AnimatedColor) { + bool fromIsCurrentColor = attributeValueIsCurrentColor(fromString); + bool byIsCurrentColor = attributeValueIsCurrentColor(byString); + if (fromIsCurrentColor) + m_fromPropertyValueType = CurrentColorValue; + else + m_fromColor = SVGColor::colorFromRGBColorString(fromString); + if (byIsCurrentColor) + m_toPropertyValueType = CurrentColorValue; + else m_toColor = SVGColor::colorFromRGBColorString(byString); - m_toColor = ColorDistance::addColorsAndClamp(m_fromColor, m_toColor); - if (!m_fromColor.isValid() || !m_toColor.isValid()) + + if ((!m_fromColor.isValid() && !fromIsCurrentColor) + || (!m_toColor.isValid() && !byIsCurrentColor)) return false; } else { m_numberUnit = String(); @@ -293,16 +430,18 @@ bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const void SVGAnimateElement::resetToBaseValue(const String& baseString) { + SVGElement* targetElement = this->targetElement(); + ASSERT(targetElement); m_animatedString = baseString; - PropertyType lastType = m_propertyType; - m_propertyType = determinePropertyType(attributeName()); - if (m_propertyType == ColorProperty) { + AnimatedAttributeType lastType = m_animatedAttributeType; + m_animatedAttributeType = determineAnimatedAttributeType(targetElement); + if (m_animatedAttributeType == AnimatedColor) { m_animatedColor = baseString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(baseString); if (isContributing(elapsed())) { - m_propertyType = lastType; + m_animatedAttributeType = lastType; return; } - } else if (m_propertyType == NumberProperty) { + } else if (m_animatedAttributeType == AnimatedNumber) { if (baseString.isEmpty()) { m_animatedNumber = 0; m_numberUnit = String(); @@ -310,27 +449,27 @@ void SVGAnimateElement::resetToBaseValue(const String& baseString) } if (parseNumberValueAndUnit(baseString, m_animatedNumber, m_numberUnit)) return; - } else if (m_propertyType == PathProperty) { + } else if (m_animatedAttributeType == AnimatedPath) { m_animatedPath.clear(); SVGPathParserFactory* factory = SVGPathParserFactory::self(); factory->buildSVGPathByteStreamFromString(baseString, m_animatedPath, UnalteredParsing); m_animatedPathPointer = m_animatedPath.get(); return; - } else if (m_propertyType == PointsProperty) { + } else if (m_animatedAttributeType == AnimatedPoints) { m_animatedPoints.clear(); return; } - m_propertyType = StringProperty; + m_animatedAttributeType = AnimatedString; } void SVGAnimateElement::applyResultsToTarget() { String valueToApply; - if (m_propertyType == ColorProperty) - valueToApply = m_animatedColor.name(); - else if (m_propertyType == NumberProperty) + if (m_animatedAttributeType == AnimatedColor) + valueToApply = m_animatedColor.serialized(); + else if (m_animatedAttributeType == AnimatedNumber) valueToApply = String::number(m_animatedNumber) + m_numberUnit; - else if (m_propertyType == PathProperty) { + else if (m_animatedAttributeType == AnimatedPath) { if (!m_animatedPathPointer || m_animatedPathPointer->isEmpty()) valueToApply = m_animatedString; else { @@ -341,7 +480,7 @@ void SVGAnimateElement::applyResultsToTarget() SVGPathParserFactory* factory = SVGPathParserFactory::self(); factory->buildStringFromByteStream(m_animatedPathPointer, valueToApply, UnalteredParsing); } - } else if (m_propertyType == PointsProperty) + } else if (m_animatedAttributeType == AnimatedPoints) valueToApply = m_animatedPoints.isEmpty() ? m_animatedString : m_animatedPoints.valueAsString(); else valueToApply = m_animatedString; @@ -351,31 +490,31 @@ void SVGAnimateElement::applyResultsToTarget() float SVGAnimateElement::calculateDistance(const String& fromString, const String& toString) { - m_propertyType = determinePropertyType(attributeName()); - if (m_propertyType == NumberProperty) { + SVGElement* targetElement = this->targetElement(); + if (!targetElement) + return -1; + m_animatedAttributeType = determineAnimatedAttributeType(targetElement); + if (m_animatedAttributeType == AnimatedNumber) { double from; double to; String unit; if (!parseNumberValueAndUnit(fromString, from, unit)) - return -1.f; + return -1; if (!parseNumberValueAndUnit(toString, to, unit)) - return -1.f; + return -1; return narrowPrecisionToFloat(fabs(to - from)); } - if (m_propertyType == ColorProperty) { + if (m_animatedAttributeType == AnimatedColor) { Color from = SVGColor::colorFromRGBColorString(fromString); if (!from.isValid()) - return -1.f; + return -1; Color to = SVGColor::colorFromRGBColorString(toString); if (!to.isValid()) - return -1.f; + return -1; return ColorDistance(from, to).distance(); } - return -1.f; + return -1; } } - -// vim:ts=4:noet #endif // ENABLE(SVG) - |