KHTML
SVGAnimateMotionElement.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2007 Eric Seidel <eric@webkit.org> 00003 (C) 2007 Rob Buis <buis@kde.org> 00004 Copyright (C) 2008 Apple Inc. All Rights Reserved. 00005 00006 This file is part of the WebKit 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 "SVGAnimateMotionElement.h" 00027 00028 #include "RenderObject.h" 00029 #include "SVGElementInstance.h" 00030 #include "SVGMPathElement.h" 00031 #include "SVGParserUtilities.h" 00032 #include "SVGPathElement.h" 00033 #include "SVGTransformList.h" 00034 #include <math.h> 00035 00036 namespace WebCore { 00037 00038 using namespace SVGNames; 00039 00040 SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName& tagName, Document* doc) 00041 : SVGAnimationElement(tagName, doc) 00042 , m_baseIndexInTransformList(0) 00043 , m_angle(0) 00044 { 00045 } 00046 00047 SVGAnimateMotionElement::~SVGAnimateMotionElement() 00048 { 00049 } 00050 00051 bool SVGAnimateMotionElement::hasValidTarget() const 00052 { 00053 if (!SVGAnimationElement::hasValidTarget()) 00054 return false; 00055 SVGElement* targetElement = this->targetElement(); 00056 if (!targetElement->isStyledTransformable() && !targetElement->hasTagName(SVGNames::textTag)) 00057 return false; 00058 // Spec: SVG 1.1 section 19.2.15 00059 if (targetElement->hasTagName(gTag) 00060 || targetElement->hasTagName(defsTag) 00061 || targetElement->hasTagName(useTag) 00062 || targetElement->hasTagName(imageTag) 00063 || targetElement->hasTagName(switchTag) 00064 || targetElement->hasTagName(pathTag) 00065 || targetElement->hasTagName(rectTag) 00066 || targetElement->hasTagName(circleTag) 00067 || targetElement->hasTagName(ellipseTag) 00068 || targetElement->hasTagName(lineTag) 00069 || targetElement->hasTagName(polylineTag) 00070 || targetElement->hasTagName(polygonTag) 00071 || targetElement->hasTagName(textTag) 00072 || targetElement->hasTagName(clipPathTag) 00073 || targetElement->hasTagName(maskTag) 00074 || targetElement->hasTagName(aTag) 00075 #if ENABLE(SVG_FOREIGN_OBJECT) 00076 || targetElement->hasTagName(foreignObjectTag) 00077 #endif 00078 ) 00079 return true; 00080 return false; 00081 } 00082 00083 void SVGAnimateMotionElement::parseMappedAttribute(MappedAttribute* attr) 00084 { 00085 if (attr->name() == SVGNames::pathAttr) { 00086 m_path = Path(); 00087 pathFromSVGData(m_path, attr->value()); 00088 } else 00089 SVGAnimationElement::parseMappedAttribute(attr); 00090 } 00091 00092 SVGAnimateMotionElement::RotateMode SVGAnimateMotionElement::rotateMode() const 00093 { 00094 static const AtomicString autoVal("auto"); 00095 static const AtomicString autoReverse("auto-reverse"); 00096 String rotate = getAttribute(SVGNames::rotateAttr); 00097 if (rotate == autoVal) 00098 return RotateAuto; 00099 if (rotate == autoReverse) 00100 return RotateAutoReverse; 00101 return RotateAngle; 00102 } 00103 00104 Path SVGAnimateMotionElement::animationPath() const 00105 { 00106 for (Node* child = firstChild(); child; child = child->nextSibling()) { 00107 if (child->hasTagName(SVGNames::mpathTag)) { 00108 SVGMPathElement* mPath = static_cast<SVGMPathElement*>(child); 00109 SVGPathElement* pathElement = mPath->pathElement(); 00110 if (pathElement) 00111 return pathElement->toPathData(); 00112 return Path(); 00113 } 00114 } 00115 if (hasAttribute(SVGNames::pathAttr)) 00116 return m_path; 00117 return Path(); 00118 } 00119 00120 static bool parsePoint(const String& s, FloatPoint& point) 00121 { 00122 if (s.isEmpty()) 00123 return false; 00124 const UChar* cur = s.characters(); 00125 const UChar* end = cur + s.length(); 00126 00127 if (!skipOptionalSpaces(cur, end)) 00128 return false; 00129 00130 float x = 0.0f; 00131 if (!parseNumber(cur, end, x)) 00132 return false; 00133 00134 float y = 0.0f; 00135 if (!parseNumber(cur, end, y)) 00136 return false; 00137 00138 point = FloatPoint(x, y); 00139 00140 // disallow anything except spaces at the end 00141 return !skipOptionalSpaces(cur, end); 00142 } 00143 00144 void SVGAnimateMotionElement::resetToBaseValue(const String&) 00145 { 00146 if (!hasValidTarget()) 00147 return; 00148 SVGElement* target = targetElement(); 00149 AffineTransform* transform = target->supplementalTransform(); 00150 if (!transform) 00151 return; 00152 transform->reset(); 00153 } 00154 00155 bool SVGAnimateMotionElement::calculateFromAndToValues(const String& fromString, const String& toString) 00156 { 00157 parsePoint(fromString, m_fromPoint); 00158 parsePoint(toString, m_toPoint); 00159 return true; 00160 } 00161 00162 bool SVGAnimateMotionElement::calculateFromAndByValues(const String& fromString, const String& byString) 00163 { 00164 parsePoint(fromString, m_fromPoint); 00165 FloatPoint byPoint; 00166 parsePoint(byString, byPoint); 00167 m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y()); 00168 return true; 00169 } 00170 00171 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement*) 00172 { 00173 SVGElement* target = targetElement(); 00174 if (!target) 00175 return; 00176 AffineTransform* transform = target->supplementalTransform(); 00177 if (!transform) 00178 return; 00179 00180 if (!isAdditive()) 00181 transform->reset(); 00182 00183 // FIXME: Implement accumulate. 00184 00185 if (animationMode() == PathAnimation) { 00186 ASSERT(!animationPath().isEmpty()); 00187 Path path = animationPath(); 00188 float positionOnPath = path.length() * percentage; 00189 bool ok; 00190 FloatPoint position = path.pointAtLength(positionOnPath, ok); 00191 if (ok) { 00192 transform->translate(position.x(), position.y()); 00193 RotateMode rotateMode = this->rotateMode(); 00194 if (rotateMode == RotateAuto || rotateMode == RotateAutoReverse) { 00195 float angle = path.normalAngleAtLength(positionOnPath, ok); 00196 if (rotateMode == RotateAutoReverse) 00197 angle += 180.f; 00198 transform->rotate(angle); 00199 } 00200 } 00201 return; 00202 } 00203 FloatSize diff = m_toPoint - m_fromPoint; 00204 transform->translate(diff.width() * percentage + m_fromPoint.x(), diff.height() * percentage + m_fromPoint.y()); 00205 } 00206 00207 void SVGAnimateMotionElement::applyResultsToTarget() 00208 { 00209 // We accumulate to the target element transform list so there is not much to do here. 00210 SVGElement* targetElement = this->targetElement(); 00211 if (targetElement && targetElement->renderer()) 00212 targetElement->renderer()->setNeedsLayout(true); 00213 00214 // ...except in case where we have additional instances in <use> trees. 00215 HashSet<SVGElementInstance*>* instances = document()->accessSVGExtensions()->instancesForElement(targetElement); 00216 if (!instances) 00217 return; 00218 HashSet<SVGElementInstance*>::iterator end = instances->end(); 00219 for (HashSet<SVGElementInstance*>::iterator it = instances->begin(); it != end; ++it) { 00220 SVGElement* shadowTreeElement = (*it)->shadowTreeElement(); 00221 ASSERT(shadowTreeElement); 00222 AffineTransform* transform = shadowTreeElement->supplementalTransform(); 00223 AffineTransform* t = targetElement->supplementalTransform(); 00224 transform->setMatrix(t->a(), t->b(), t->c(), t->d(), t->e(), t->f()); 00225 if (shadowTreeElement->renderer()) 00226 shadowTreeElement->renderer()->setNeedsLayout(true); 00227 } 00228 } 00229 00230 float SVGAnimateMotionElement::calculateDistance(const String& fromString, const String& toString) 00231 { 00232 FloatPoint from; 00233 FloatPoint to; 00234 if (!parsePoint(fromString, from)) 00235 return -1.f; 00236 if (!parsePoint(toString, to)) 00237 return -1.f; 00238 FloatSize diff = to - from; 00239 return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); 00240 } 00241 00242 } 00243 00244 #endif // ENABLE(SVG) 00245 00246 // vim:ts=4:noet
KDE 4.6 API Reference