File indexing completed on 2024-04-28 11:39:08
0001 /* 0002 Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org> 0003 2004, 2005, 2006 Rob Buis <buis@kde.org> 0004 Copyright (C) 2008 Apple Inc. All rights reserved. 0005 0006 This file is part of the KDE project 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION) 0025 #include "SVGAnimateElement.h" 0026 0027 #include "ColorDistance.h" 0028 #include "FloatConversion.h" 0029 #include "SVGColor.h" 0030 #include "SVGParserUtilities.h" 0031 #include <math.h> 0032 0033 using namespace std; 0034 0035 namespace WebCore 0036 { 0037 0038 SVGAnimateElement::SVGAnimateElement(const QualifiedName &tagName, Document *doc) 0039 : SVGAnimationElement(tagName, doc) 0040 , m_propertyType(StringProperty) 0041 , m_fromNumber(0) 0042 , m_toNumber(0) 0043 , m_animatedNumber(numeric_limits<double>::infinity()) 0044 { 0045 } 0046 0047 SVGAnimateElement::~SVGAnimateElement() 0048 { 0049 } 0050 0051 static bool parseNumberValueAndUnit(const String &in, double &value, String &unit) 0052 { 0053 // FIXME: These are from top of my head, figure out all property types that can be animated as numbers. 0054 unsigned unitLength = 0; 0055 String parse = in.stripWhiteSpace(); 0056 if (parse.endsWith("%")) { 0057 unitLength = 1; 0058 } else if (parse.endsWith("px") || parse.endsWith("pt") || parse.endsWith("em")) { 0059 unitLength = 2; 0060 } else if (parse.endsWith("deg") || parse.endsWith("rad")) { 0061 unitLength = 3; 0062 } else if (parse.endsWith("grad")) { 0063 unitLength = 4; 0064 } 0065 String newUnit = parse.right(unitLength); 0066 String number = parse.left(parse.length() - unitLength); 0067 if (!unit.isEmpty() && newUnit != unit || number.isEmpty()) { 0068 return false; 0069 } 0070 UChar last = number[number.length() - 1]; 0071 if (last < '0' || last > '9') { 0072 return false; 0073 } 0074 unit = newUnit; 0075 bool ok; 0076 value = number.toDouble(&ok); 0077 return ok; 0078 } 0079 0080 SVGAnimateElement::PropertyType SVGAnimateElement::determinePropertyType(const String &attribute) const 0081 { 0082 // FIXME: We need a full property table for figuring this out reliably. 0083 if (hasTagName(SVGNames::animateColorTag)) { 0084 return ColorProperty; 0085 } 0086 if (attribute == "color" || attribute == "fill" || attribute == "stroke") { 0087 return ColorProperty; 0088 } 0089 return NumberProperty; 0090 } 0091 0092 void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement *resultElement) 0093 { 0094 ASSERT(percentage >= 0.f && percentage <= 1.f); 0095 ASSERT(resultElement); 0096 if (hasTagName(SVGNames::setTag)) { 0097 percentage = 1.f; 0098 } 0099 if (!resultElement->hasTagName(SVGNames::animateTag) && !resultElement->hasTagName(SVGNames::animateColorTag) 0100 && !resultElement->hasTagName(SVGNames::setTag)) { 0101 return; 0102 } 0103 SVGAnimateElement *results = static_cast<SVGAnimateElement *>(resultElement); 0104 // Can't accumulate over a string property. 0105 if (results->m_propertyType == StringProperty && m_propertyType != StringProperty) { 0106 return; 0107 } 0108 if (m_propertyType == NumberProperty) { 0109 // To animation uses contributions from the lower priority animations as the base value. 0110 if (animationMode() == ToAnimation) { 0111 m_fromNumber = results->m_animatedNumber; 0112 } 0113 0114 double number = (m_toNumber - m_fromNumber) * percentage + m_fromNumber; 0115 0116 // FIXME: This is not correct for values animation. 0117 if (isAccumulated() && repeat) { 0118 number += m_toNumber * repeat; 0119 } 0120 if (isAdditive() && animationMode() != ToAnimation) { 0121 results->m_animatedNumber += number; 0122 } else { 0123 results->m_animatedNumber = number; 0124 } 0125 return; 0126 } 0127 if (m_propertyType == ColorProperty) { 0128 if (animationMode() == ToAnimation) { 0129 m_fromColor = results->m_animatedColor; 0130 } 0131 Color color = ColorDistance(m_fromColor, m_toColor).scaledDistance(percentage).addToColorAndClamp(m_fromColor); 0132 // FIXME: Accumulate colors. 0133 if (isAdditive() && animationMode() != ToAnimation) { 0134 results->m_animatedColor = ColorDistance::addColorsAndClamp(results->m_animatedColor, color); 0135 } else { 0136 results->m_animatedColor = color; 0137 } 0138 return; 0139 } 0140 AnimationMode animationMode = this->animationMode(); 0141 ASSERT(animationMode == FromToAnimation || animationMode == ToAnimation || animationMode == ValuesAnimation); 0142 if ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1.0f) { 0143 results->m_animatedString = m_toString; 0144 } else { 0145 results->m_animatedString = m_fromString; 0146 } 0147 // Higher priority replace animation overrides any additive results so far. 0148 results->m_propertyType = StringProperty; 0149 } 0150 0151 bool SVGAnimateElement::calculateFromAndToValues(const String &fromString, const String &toString) 0152 { 0153 // FIXME: Needs more solid way determine target attribute type. 0154 m_propertyType = determinePropertyType(attributeName()); 0155 if (m_propertyType == ColorProperty) { 0156 m_fromColor = SVGColor::colorFromRGBColorString(fromString); 0157 m_toColor = SVGColor::colorFromRGBColorString(toString); 0158 if (m_fromColor.isValid() && m_toColor.isValid()) { 0159 return true; 0160 } 0161 } else if (m_propertyType == NumberProperty) { 0162 m_numberUnit = String(); 0163 if (parseNumberValueAndUnit(toString, m_toNumber, m_numberUnit)) { 0164 // For to-animations the from number is calculated later 0165 if (animationMode() == ToAnimation || parseNumberValueAndUnit(fromString, m_fromNumber, m_numberUnit)) { 0166 return true; 0167 } 0168 } 0169 } 0170 m_fromString = fromString; 0171 m_toString = toString; 0172 m_propertyType = StringProperty; 0173 return true; 0174 } 0175 0176 bool SVGAnimateElement::calculateFromAndByValues(const String &fromString, const String &byString) 0177 { 0178 ASSERT(!hasTagName(SVGNames::setTag)); 0179 m_propertyType = determinePropertyType(attributeName()); 0180 if (m_propertyType == ColorProperty) { 0181 m_fromColor = fromString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(fromString); 0182 m_toColor = ColorDistance::addColorsAndClamp(m_fromColor, SVGColor::colorFromRGBColorString(byString)); 0183 if (!m_fromColor.isValid() || !m_toColor.isValid()) { 0184 return false; 0185 } 0186 } else { 0187 m_numberUnit = String(); 0188 m_fromNumber = 0; 0189 if (!fromString.isEmpty() && !parseNumberValueAndUnit(fromString, m_fromNumber, m_numberUnit)) { 0190 return false; 0191 } 0192 if (!parseNumberValueAndUnit(byString, m_toNumber, m_numberUnit)) { 0193 return false; 0194 } 0195 m_toNumber += m_fromNumber; 0196 } 0197 return true; 0198 } 0199 0200 void SVGAnimateElement::resetToBaseValue(const String &baseString) 0201 { 0202 m_animatedString = baseString; 0203 m_propertyType = determinePropertyType(attributeName()); 0204 if (m_propertyType == ColorProperty) { 0205 m_animatedColor = baseString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(baseString); 0206 if (m_animatedColor.isValid()) { 0207 return; 0208 } 0209 } else if (m_propertyType == NumberProperty) { 0210 if (baseString.isEmpty()) { 0211 m_animatedNumber = 0; 0212 m_numberUnit = String(); 0213 return; 0214 } 0215 if (parseNumberValueAndUnit(baseString, m_animatedNumber, m_numberUnit)) { 0216 return; 0217 } 0218 } 0219 m_propertyType = StringProperty; 0220 } 0221 0222 void SVGAnimateElement::applyResultsToTarget() 0223 { 0224 String valueToApply; 0225 if (m_propertyType == ColorProperty) { 0226 valueToApply = m_animatedColor.name(); 0227 } else if (m_propertyType == NumberProperty) { 0228 valueToApply = String::number(m_animatedNumber) + m_numberUnit; 0229 } else { 0230 valueToApply = m_animatedString; 0231 } 0232 0233 setTargetAttributeAnimatedValue(valueToApply); 0234 } 0235 0236 float SVGAnimateElement::calculateDistance(const String &fromString, const String &toString) 0237 { 0238 m_propertyType = determinePropertyType(attributeName()); 0239 if (m_propertyType == NumberProperty) { 0240 double from; 0241 double to; 0242 String unit; 0243 if (!parseNumberValueAndUnit(fromString, from, unit)) { 0244 return -1.f; 0245 } 0246 if (!parseNumberValueAndUnit(toString, to, unit)) { 0247 return -1.f; 0248 } 0249 return narrowPrecisionToFloat(fabs(to - from)); 0250 } else if (m_propertyType == ColorProperty) { 0251 Color from = SVGColor::colorFromRGBColorString(fromString); 0252 if (!from.isValid()) { 0253 return -1.f; 0254 } 0255 Color to = SVGColor::colorFromRGBColorString(toString); 0256 if (!to.isValid()) { 0257 return -1.f; 0258 } 0259 return ColorDistance(from, to).distance(); 0260 } 0261 return -1.f; 0262 } 0263 0264 } 0265 0266 #endif // ENABLE(SVG) 0267