summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/svg/SVGAnimateElement.cpp
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-24 11:24:40 +0100
committerBen Murdoch <benm@google.com>2011-06-02 09:53:15 +0100
commit81bc750723a18f21cd17d1b173cd2a4dda9cea6e (patch)
tree7a9e5ed86ff429fd347a25153107221543909b19 /Source/WebCore/svg/SVGAnimateElement.cpp
parent94088a6d336c1dd80a1e734af51e96abcbb689a7 (diff)
downloadexternal_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.cpp291
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)
-