KHTML
SVGAnimateElement.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org> 00003 2004, 2005, 2006 Rob Buis <buis@kde.org> 00004 Copyright (C) 2008 Apple Inc. All rights reserved. 00005 00006 This file is part of the KDE project 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 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 // FIXME: These are from top of my head, figure out all property types that can be animated as numbers. 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 // FIXME: We need a full property table for figuring this out reliably. 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 // Can't accumulate over a string property. 00098 if (results->m_propertyType == StringProperty && m_propertyType != StringProperty) 00099 return; 00100 if (m_propertyType == NumberProperty) { 00101 // To animation uses contributions from the lower priority animations as the base value. 00102 if (animationMode() == ToAnimation) 00103 m_fromNumber = results->m_animatedNumber; 00104 00105 double number = (m_toNumber - m_fromNumber) * percentage + m_fromNumber; 00106 00107 // FIXME: This is not correct for values animation. 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 // FIXME: Accumulate colors. 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 // Higher priority replace animation overrides any additive results so far. 00134 results->m_propertyType = StringProperty; 00135 } 00136 00137 bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const String& toString) 00138 { 00139 // FIXME: Needs more solid way determine target attribute type. 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 // For to-animations the from number is calculated later 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 // vim:ts=4:noet 00241 #endif // ENABLE(SVG) 00242
KDE 4.6 API Reference