KHTML
SVGAnimateMotionElement.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 "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
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
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
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
00210 SVGElement* targetElement = this->targetElement();
00211 if (targetElement && targetElement->renderer())
00212 targetElement->renderer()->setNeedsLayout(true);
00213
00214
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