KHTML
SVGAnimateElement.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
00026 #include "SVGAnimateElement.h"
00027
00028 #include "ColorDistance.h"
00029 #include "FloatConversion.h"
00030 #include "SVGColor.h"
00031 #include "SVGParserUtilities.h"
00032 #include <math.h>
00033
00034 using namespace std;
00035
00036 namespace WebCore {
00037
00038 SVGAnimateElement::SVGAnimateElement(const QualifiedName& tagName, Document* doc)
00039 : SVGAnimationElement(tagName, doc)
00040 , m_propertyType(StringProperty)
00041 , m_fromNumber(0)
00042 , m_toNumber(0)
00043 , m_animatedNumber(numeric_limits<double>::infinity())
00044 {
00045 }
00046
00047 SVGAnimateElement::~SVGAnimateElement()
00048 {
00049 }
00050
00051 static bool parseNumberValueAndUnit(const String& in, double& value, String& unit)
00052 {
00053
00054 unsigned unitLength = 0;
00055 String parse = in.stripWhiteSpace();
00056 if (parse.endsWith("%"))
00057 unitLength = 1;
00058 else if (parse.endsWith("px") || parse.endsWith("pt") || parse.endsWith("em"))
00059 unitLength = 2;
00060 else if (parse.endsWith("deg") || parse.endsWith("rad"))
00061 unitLength = 3;
00062 else if (parse.endsWith("grad"))
00063 unitLength = 4;
00064 String newUnit = parse.right(unitLength);
00065 String number = parse.left(parse.length() - unitLength);
00066 if (!unit.isEmpty() && newUnit != unit || number.isEmpty())
00067 return false;
00068 UChar last = number[number.length() - 1];
00069 if (last < '0' || last > '9')
00070 return false;
00071 unit = newUnit;
00072 bool ok;
00073 value = number.toDouble(&ok);
00074 return ok;
00075 }
00076
00077 SVGAnimateElement::PropertyType SVGAnimateElement::determinePropertyType(const String& attribute) const
00078 {
00079
00080 if (hasTagName(SVGNames::animateColorTag))
00081 return ColorProperty;
00082 if (attribute == "color" || attribute == "fill" || attribute == "stroke")
00083 return ColorProperty;
00084 return NumberProperty;
00085 }
00086
00087 void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
00088 {
00089 ASSERT(percentage >= 0.f && percentage <= 1.f);
00090 ASSERT(resultElement);
00091 if (hasTagName(SVGNames::setTag))
00092 percentage = 1.f;
00093 if (!resultElement->hasTagName(SVGNames::animateTag) && !resultElement->hasTagName(SVGNames::animateColorTag)
00094 && !resultElement->hasTagName(SVGNames::setTag))
00095 return;
00096 SVGAnimateElement* results = static_cast<SVGAnimateElement*>(resultElement);
00097
00098 if (results->m_propertyType == StringProperty && m_propertyType != StringProperty)
00099 return;
00100 if (m_propertyType == NumberProperty) {
00101
00102 if (animationMode() == ToAnimation)
00103 m_fromNumber = results->m_animatedNumber;
00104
00105 double number = (m_toNumber - m_fromNumber) * percentage + m_fromNumber;
00106
00107
00108 if (isAccumulated() && repeat)
00109 number += m_toNumber * repeat;
00110 if (isAdditive() && animationMode() != ToAnimation)
00111 results->m_animatedNumber += number;
00112 else
00113 results->m_animatedNumber = number;
00114 return;
00115 }
00116 if (m_propertyType == ColorProperty) {
00117 if (animationMode() == ToAnimation)
00118 m_fromColor = results->m_animatedColor;
00119 Color color = ColorDistance(m_fromColor, m_toColor).scaledDistance(percentage).addToColorAndClamp(m_fromColor);
00120
00121 if (isAdditive() && animationMode() != ToAnimation)
00122 results->m_animatedColor = ColorDistance::addColorsAndClamp(results->m_animatedColor, color);
00123 else
00124 results->m_animatedColor = color;
00125 return;
00126 }
00127 AnimationMode animationMode = this->animationMode();
00128 ASSERT(animationMode == FromToAnimation || animationMode == ToAnimation || animationMode == ValuesAnimation);
00129 if ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1.0f)
00130 results->m_animatedString = m_toString;
00131 else
00132 results->m_animatedString = m_fromString;
00133
00134 results->m_propertyType = StringProperty;
00135 }
00136
00137 bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const String& toString)
00138 {
00139
00140 m_propertyType = determinePropertyType(attributeName());
00141 if (m_propertyType == ColorProperty) {
00142 m_fromColor = SVGColor::colorFromRGBColorString(fromString);
00143 m_toColor = SVGColor::colorFromRGBColorString(toString);
00144 if (m_fromColor.isValid() && m_toColor.isValid())
00145 return true;
00146 } else if (m_propertyType == NumberProperty) {
00147 m_numberUnit = String();
00148 if (parseNumberValueAndUnit(toString, m_toNumber, m_numberUnit)) {
00149
00150 if (animationMode() == ToAnimation || parseNumberValueAndUnit(fromString, m_fromNumber, m_numberUnit))
00151 return true;
00152 }
00153 }
00154 m_fromString = fromString;
00155 m_toString = toString;
00156 m_propertyType = StringProperty;
00157 return true;
00158 }
00159
00160 bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const String& byString)
00161 {
00162 ASSERT(!hasTagName(SVGNames::setTag));
00163 m_propertyType = determinePropertyType(attributeName());
00164 if (m_propertyType == ColorProperty) {
00165 m_fromColor = fromString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(fromString);
00166 m_toColor = ColorDistance::addColorsAndClamp(m_fromColor, SVGColor::colorFromRGBColorString(byString));
00167 if (!m_fromColor.isValid() || !m_toColor.isValid())
00168 return false;
00169 } else {
00170 m_numberUnit = String();
00171 m_fromNumber = 0;
00172 if (!fromString.isEmpty() && !parseNumberValueAndUnit(fromString, m_fromNumber, m_numberUnit))
00173 return false;
00174 if (!parseNumberValueAndUnit(byString, m_toNumber, m_numberUnit))
00175 return false;
00176 m_toNumber += m_fromNumber;
00177 }
00178 return true;
00179 }
00180
00181 void SVGAnimateElement::resetToBaseValue(const String& baseString)
00182 {
00183 m_animatedString = baseString;
00184 m_propertyType = determinePropertyType(attributeName());
00185 if (m_propertyType == ColorProperty) {
00186 m_animatedColor = baseString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(baseString);
00187 if (m_animatedColor.isValid())
00188 return;
00189 } else if (m_propertyType == NumberProperty) {
00190 if (baseString.isEmpty()) {
00191 m_animatedNumber = 0;
00192 m_numberUnit = String();
00193 return;
00194 }
00195 if (parseNumberValueAndUnit(baseString, m_animatedNumber, m_numberUnit))
00196 return;
00197 }
00198 m_propertyType = StringProperty;
00199 }
00200
00201 void SVGAnimateElement::applyResultsToTarget()
00202 {
00203 String valueToApply;
00204 if (m_propertyType == ColorProperty)
00205 valueToApply = m_animatedColor.name();
00206 else if (m_propertyType == NumberProperty)
00207 valueToApply = String::number(m_animatedNumber) + m_numberUnit;
00208 else
00209 valueToApply = m_animatedString;
00210
00211 setTargetAttributeAnimatedValue(valueToApply);
00212 }
00213
00214 float SVGAnimateElement::calculateDistance(const String& fromString, const String& toString)
00215 {
00216 m_propertyType = determinePropertyType(attributeName());
00217 if (m_propertyType == NumberProperty) {
00218 double from;
00219 double to;
00220 String unit;
00221 if (!parseNumberValueAndUnit(fromString, from, unit))
00222 return -1.f;
00223 if (!parseNumberValueAndUnit(toString, to, unit))
00224 return -1.f;
00225 return narrowPrecisionToFloat(fabs(to - from));
00226 } else if (m_propertyType == ColorProperty) {
00227 Color from = SVGColor::colorFromRGBColorString(fromString);
00228 if (!from.isValid())
00229 return -1.f;
00230 Color to = SVGColor::colorFromRGBColorString(toString);
00231 if (!to.isValid())
00232 return -1.f;
00233 return ColorDistance(from, to).distance();
00234 }
00235 return -1.f;
00236 }
00237
00238 }
00239
00240
00241 #endif // ENABLE(SVG)
00242