File indexing completed on 2024-04-28 11:39:09
0001 /* 0002 Copyright (C) 2007 Eric Seidel <eric@webkit.org> 0003 (C) 2007 Rob Buis <buis@kde.org> 0004 Copyright (C) 2008 Apple Inc. All Rights Reserved. 0005 0006 This file is part of the WebKit 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 "SVGAnimateMotionElement.h" 0026 0027 #include "RenderObject.h" 0028 #include "SVGElementInstance.h" 0029 #include "SVGMPathElement.h" 0030 #include "SVGParserUtilities.h" 0031 #include "SVGPathElement.h" 0032 #include "SVGTransformList.h" 0033 #include <math.h> 0034 0035 namespace WebCore 0036 { 0037 0038 using namespace SVGNames; 0039 0040 SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName &tagName, Document *doc) 0041 : SVGAnimationElement(tagName, doc) 0042 , m_baseIndexInTransformList(0) 0043 , m_angle(0) 0044 { 0045 } 0046 0047 SVGAnimateMotionElement::~SVGAnimateMotionElement() 0048 { 0049 } 0050 0051 bool SVGAnimateMotionElement::hasValidTarget() const 0052 { 0053 if (!SVGAnimationElement::hasValidTarget()) { 0054 return false; 0055 } 0056 SVGElement *targetElement = this->targetElement(); 0057 if (!targetElement->isStyledTransformable() && !targetElement->hasTagName(SVGNames::textTag)) { 0058 return false; 0059 } 0060 // Spec: SVG 1.1 section 19.2.15 0061 if (targetElement->hasTagName(gTag) 0062 || targetElement->hasTagName(defsTag) 0063 || targetElement->hasTagName(useTag) 0064 || targetElement->hasTagName(imageTag) 0065 || targetElement->hasTagName(switchTag) 0066 || targetElement->hasTagName(pathTag) 0067 || targetElement->hasTagName(rectTag) 0068 || targetElement->hasTagName(circleTag) 0069 || targetElement->hasTagName(ellipseTag) 0070 || targetElement->hasTagName(lineTag) 0071 || targetElement->hasTagName(polylineTag) 0072 || targetElement->hasTagName(polygonTag) 0073 || targetElement->hasTagName(textTag) 0074 || targetElement->hasTagName(clipPathTag) 0075 || targetElement->hasTagName(maskTag) 0076 || targetElement->hasTagName(aTag) 0077 #if ENABLE(SVG_FOREIGN_OBJECT) 0078 || targetElement->hasTagName(foreignObjectTag) 0079 #endif 0080 ) { 0081 return true; 0082 } 0083 return false; 0084 } 0085 0086 void SVGAnimateMotionElement::parseMappedAttribute(MappedAttribute *attr) 0087 { 0088 if (attr->name() == SVGNames::pathAttr) { 0089 m_path = Path(); 0090 pathFromSVGData(m_path, attr->value()); 0091 } else { 0092 SVGAnimationElement::parseMappedAttribute(attr); 0093 } 0094 } 0095 0096 SVGAnimateMotionElement::RotateMode SVGAnimateMotionElement::rotateMode() const 0097 { 0098 static const AtomicString autoVal("auto"); 0099 static const AtomicString autoReverse("auto-reverse"); 0100 String rotate = getAttribute(SVGNames::rotateAttr); 0101 if (rotate == autoVal) { 0102 return RotateAuto; 0103 } 0104 if (rotate == autoReverse) { 0105 return RotateAutoReverse; 0106 } 0107 return RotateAngle; 0108 } 0109 0110 Path SVGAnimateMotionElement::animationPath() const 0111 { 0112 for (Node *child = firstChild(); child; child = child->nextSibling()) { 0113 if (child->hasTagName(SVGNames::mpathTag)) { 0114 SVGMPathElement *mPath = static_cast<SVGMPathElement *>(child); 0115 SVGPathElement *pathElement = mPath->pathElement(); 0116 if (pathElement) { 0117 return pathElement->toPathData(); 0118 } 0119 return Path(); 0120 } 0121 } 0122 if (hasAttribute(SVGNames::pathAttr)) { 0123 return m_path; 0124 } 0125 return Path(); 0126 } 0127 0128 static bool parsePoint(const String &s, FloatPoint &point) 0129 { 0130 if (s.isEmpty()) { 0131 return false; 0132 } 0133 const UChar *cur = s.characters(); 0134 const UChar *end = cur + s.length(); 0135 0136 if (!skipOptionalSpaces(cur, end)) { 0137 return false; 0138 } 0139 0140 float x = 0.0f; 0141 if (!parseNumber(cur, end, x)) { 0142 return false; 0143 } 0144 0145 float y = 0.0f; 0146 if (!parseNumber(cur, end, y)) { 0147 return false; 0148 } 0149 0150 point = FloatPoint(x, y); 0151 0152 // disallow anything except spaces at the end 0153 return !skipOptionalSpaces(cur, end); 0154 } 0155 0156 void SVGAnimateMotionElement::resetToBaseValue(const String &) 0157 { 0158 if (!hasValidTarget()) { 0159 return; 0160 } 0161 SVGElement *target = targetElement(); 0162 AffineTransform *transform = target->supplementalTransform(); 0163 if (!transform) { 0164 return; 0165 } 0166 transform->reset(); 0167 } 0168 0169 bool SVGAnimateMotionElement::calculateFromAndToValues(const String &fromString, const String &toString) 0170 { 0171 parsePoint(fromString, m_fromPoint); 0172 parsePoint(toString, m_toPoint); 0173 return true; 0174 } 0175 0176 bool SVGAnimateMotionElement::calculateFromAndByValues(const String &fromString, const String &byString) 0177 { 0178 parsePoint(fromString, m_fromPoint); 0179 FloatPoint byPoint; 0180 parsePoint(byString, byPoint); 0181 m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y()); 0182 return true; 0183 } 0184 0185 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement *) 0186 { 0187 SVGElement *target = targetElement(); 0188 if (!target) { 0189 return; 0190 } 0191 AffineTransform *transform = target->supplementalTransform(); 0192 if (!transform) { 0193 return; 0194 } 0195 0196 if (!isAdditive()) { 0197 transform->reset(); 0198 } 0199 0200 // FIXME: Implement accumulate. 0201 0202 if (animationMode() == PathAnimation) { 0203 ASSERT(!animationPath().isEmpty()); 0204 Path path = animationPath(); 0205 float positionOnPath = path.length() * percentage; 0206 bool ok; 0207 FloatPoint position = path.pointAtLength(positionOnPath, ok); 0208 if (ok) { 0209 transform->translate(position.x(), position.y()); 0210 RotateMode rotateMode = this->rotateMode(); 0211 if (rotateMode == RotateAuto || rotateMode == RotateAutoReverse) { 0212 float angle = path.normalAngleAtLength(positionOnPath, ok); 0213 if (rotateMode == RotateAutoReverse) { 0214 angle += 180.f; 0215 } 0216 transform->rotate(angle); 0217 } 0218 } 0219 return; 0220 } 0221 FloatSize diff = m_toPoint - m_fromPoint; 0222 transform->translate(diff.width() * percentage + m_fromPoint.x(), diff.height() * percentage + m_fromPoint.y()); 0223 } 0224 0225 void SVGAnimateMotionElement::applyResultsToTarget() 0226 { 0227 // We accumulate to the target element transform list so there is not much to do here. 0228 SVGElement *targetElement = this->targetElement(); 0229 if (targetElement && targetElement->renderer()) { 0230 targetElement->renderer()->setNeedsLayout(true); 0231 } 0232 0233 // ...except in case where we have additional instances in <use> trees. 0234 HashSet<SVGElementInstance *> *instances = document()->accessSVGExtensions()->instancesForElement(targetElement); 0235 if (!instances) { 0236 return; 0237 } 0238 HashSet<SVGElementInstance *>::iterator end = instances->end(); 0239 for (HashSet<SVGElementInstance *>::iterator it = instances->begin(); it != end; ++it) { 0240 SVGElement *shadowTreeElement = (*it)->shadowTreeElement(); 0241 ASSERT(shadowTreeElement); 0242 AffineTransform *transform = shadowTreeElement->supplementalTransform(); 0243 AffineTransform *t = targetElement->supplementalTransform(); 0244 transform->setMatrix(t->a(), t->b(), t->c(), t->d(), t->e(), t->f()); 0245 if (shadowTreeElement->renderer()) { 0246 shadowTreeElement->renderer()->setNeedsLayout(true); 0247 } 0248 } 0249 } 0250 0251 float SVGAnimateMotionElement::calculateDistance(const String &fromString, const String &toString) 0252 { 0253 FloatPoint from; 0254 FloatPoint to; 0255 if (!parsePoint(fromString, from)) { 0256 return -1.f; 0257 } 0258 if (!parsePoint(toString, to)) { 0259 return -1.f; 0260 } 0261 FloatSize diff = to - from; 0262 return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); 0263 } 0264 0265 } 0266 0267 #endif // ENABLE(SVG) 0268