Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / svg / SVGAnimateMotionElement.cpp
blobbbd4503917039afa145ae4895cbb7616053e24cc
1 /*
2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 * Copyright (C) 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) 2008 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "config.h"
23 #include "core/svg/SVGAnimateMotionElement.h"
25 #include "core/SVGNames.h"
26 #include "core/dom/ElementTraversal.h"
27 #include "core/layout/LayoutObject.h"
28 #include "core/svg/SVGMPathElement.h"
29 #include "core/svg/SVGParserUtilities.h"
30 #include "core/svg/SVGPathElement.h"
31 #include "core/svg/SVGPathUtilities.h"
32 #include "platform/transforms/AffineTransform.h"
33 #include "wtf/MathExtras.h"
34 #include "wtf/StdLibExtras.h"
36 namespace blink {
38 using namespace SVGNames;
40 inline SVGAnimateMotionElement::SVGAnimateMotionElement(Document& document)
41 : SVGAnimationElement(animateMotionTag, document)
42 , m_hasToPointAtEndOfDuration(false)
44 setCalcMode(CalcModePaced);
47 DEFINE_NODE_FACTORY(SVGAnimateMotionElement)
49 SVGAnimateMotionElement::~SVGAnimateMotionElement()
53 bool SVGAnimateMotionElement::hasValidAttributeType()
55 SVGElement* targetElement = this->targetElement();
56 if (!targetElement)
57 return false;
59 // We don't have a special attribute name to verify the animation type. Check the element name instead.
60 if (!targetElement->isSVGGraphicsElement())
61 return false;
62 // Spec: SVG 1.1 section 19.2.15
63 // FIXME: svgTag is missing. Needs to be checked, if transforming <svg> could cause problems.
64 return (isSVGGElement(*targetElement)
65 || isSVGDefsElement(*targetElement)
66 || isSVGUseElement(*targetElement)
67 || isSVGImageElement(*targetElement)
68 || isSVGSwitchElement(*targetElement)
69 || isSVGPathElement(*targetElement)
70 || isSVGRectElement(*targetElement)
71 || isSVGCircleElement(*targetElement)
72 || isSVGEllipseElement(*targetElement)
73 || isSVGLineElement(*targetElement)
74 || isSVGPolylineElement(*targetElement)
75 || isSVGPolygonElement(*targetElement)
76 || isSVGTextElement(*targetElement)
77 || isSVGClipPathElement(*targetElement)
78 || isSVGMaskElement(*targetElement)
79 || isSVGAElement(*targetElement)
80 || isSVGForeignObjectElement(*targetElement)
84 bool SVGAnimateMotionElement::hasValidAttributeName()
86 // AnimateMotion does not use attributeName so it is always valid.
87 return true;
90 void SVGAnimateMotionElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
92 if (name == SVGNames::pathAttr) {
93 m_path = Path();
94 buildPathFromString(value, m_path);
95 updateAnimationPath();
96 return;
99 SVGAnimationElement::parseAttribute(name, value);
102 SVGAnimateMotionElement::RotateMode SVGAnimateMotionElement::rotateMode() const
104 DEFINE_STATIC_LOCAL(const AtomicString, autoVal, ("auto", AtomicString::ConstructFromLiteral));
105 DEFINE_STATIC_LOCAL(const AtomicString, autoReverse, ("auto-reverse", AtomicString::ConstructFromLiteral));
106 const AtomicString& rotate = getAttribute(SVGNames::rotateAttr);
107 if (rotate == autoVal)
108 return RotateAuto;
109 if (rotate == autoReverse)
110 return RotateAutoReverse;
111 return RotateAngle;
114 void SVGAnimateMotionElement::updateAnimationPath()
116 m_animationPath = Path();
117 bool foundMPath = false;
119 for (SVGMPathElement* mpath = Traversal<SVGMPathElement>::firstChild(*this); mpath; mpath = Traversal<SVGMPathElement>::nextSibling(*mpath)) {
120 if (SVGPathElement* pathElement = mpath->pathElement()) {
121 m_animationPath = pathElement->asPath();
122 foundMPath = true;
123 break;
127 if (!foundMPath && fastHasAttribute(SVGNames::pathAttr))
128 m_animationPath = m_path;
130 updateAnimationMode();
133 template<typename CharType>
134 static bool parsePointInternal(const String& string, FloatPoint& point)
136 const CharType* ptr = string.getCharacters<CharType>();
137 const CharType* end = ptr + string.length();
139 if (!skipOptionalSVGSpaces(ptr, end))
140 return false;
142 float x = 0;
143 if (!parseNumber(ptr, end, x))
144 return false;
146 float y = 0;
147 if (!parseNumber(ptr, end, y))
148 return false;
150 point = FloatPoint(x, y);
152 // disallow anything except spaces at the end
153 return !skipOptionalSVGSpaces(ptr, end);
156 static bool parsePoint(const String& string, FloatPoint& point)
158 if (string.isEmpty())
159 return false;
160 if (string.is8Bit())
161 return parsePointInternal<LChar>(string, point);
162 return parsePointInternal<UChar>(string, point);
165 void SVGAnimateMotionElement::resetAnimatedType()
167 if (!hasValidAttributeType())
168 return;
169 SVGElement* targetElement = this->targetElement();
170 if (!targetElement)
171 return;
172 if (AffineTransform* transform = targetElement->animateMotionTransform())
173 transform->makeIdentity();
176 void SVGAnimateMotionElement::clearAnimatedType()
178 SVGElement* targetElement = this->targetElement();
179 if (!targetElement)
180 return;
182 AffineTransform* transform = targetElement->animateMotionTransform();
183 if (!transform)
184 return;
186 transform->makeIdentity();
188 if (LayoutObject* targetLayoutObject = targetElement->layoutObject()) {
189 targetLayoutObject->setNeedsTransformUpdate();
190 markForLayoutAndParentResourceInvalidation(targetLayoutObject);
194 bool SVGAnimateMotionElement::calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString)
196 parsePoint(toAtEndOfDurationString, m_toPointAtEndOfDuration);
197 m_hasToPointAtEndOfDuration = true;
198 return true;
201 bool SVGAnimateMotionElement::calculateFromAndToValues(const String& fromString, const String& toString)
203 m_hasToPointAtEndOfDuration = false;
204 parsePoint(fromString, m_fromPoint);
205 parsePoint(toString, m_toPoint);
206 return true;
209 bool SVGAnimateMotionElement::calculateFromAndByValues(const String& fromString, const String& byString)
211 m_hasToPointAtEndOfDuration = false;
212 if (animationMode() == ByAnimation && !isAdditive())
213 return false;
214 parsePoint(fromString, m_fromPoint);
215 FloatPoint byPoint;
216 parsePoint(byString, byPoint);
217 m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y());
218 return true;
221 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGSMILElement*)
223 SVGElement* targetElement = this->targetElement();
224 if (!targetElement)
225 return;
226 AffineTransform* transform = targetElement->animateMotionTransform();
227 if (!transform)
228 return;
230 if (LayoutObject* targetLayoutObject = targetElement->layoutObject())
231 targetLayoutObject->setNeedsTransformUpdate();
233 if (!isAdditive())
234 transform->makeIdentity();
236 if (animationMode() != PathAnimation) {
237 FloatPoint toPointAtEndOfDuration = m_toPoint;
238 if (isAccumulated() && repeatCount && m_hasToPointAtEndOfDuration)
239 toPointAtEndOfDuration = m_toPointAtEndOfDuration;
241 float animatedX = 0;
242 animateAdditiveNumber(percentage, repeatCount, m_fromPoint.x(), m_toPoint.x(), toPointAtEndOfDuration.x(), animatedX);
244 float animatedY = 0;
245 animateAdditiveNumber(percentage, repeatCount, m_fromPoint.y(), m_toPoint.y(), toPointAtEndOfDuration.y(), animatedY);
247 transform->translate(animatedX, animatedY);
248 return;
251 ASSERT(!m_animationPath.isEmpty());
253 float positionOnPath = m_animationPath.length() * percentage;
254 FloatPoint position;
255 float angle;
256 bool ok = m_animationPath.pointAndNormalAtLength(positionOnPath, position, angle);
257 if (!ok)
258 return;
260 // Handle accumulate="sum".
261 if (isAccumulated() && repeatCount) {
262 FloatPoint positionAtEndOfDuration = m_animationPath.pointAtLength(m_animationPath.length(), ok);
263 if (ok)
264 position.move(positionAtEndOfDuration.x() * repeatCount, positionAtEndOfDuration.y() * repeatCount);
267 transform->translate(position.x(), position.y());
268 RotateMode rotateMode = this->rotateMode();
269 if (rotateMode != RotateAuto && rotateMode != RotateAutoReverse)
270 return;
271 if (rotateMode == RotateAutoReverse)
272 angle += 180;
273 transform->rotate(angle);
276 void SVGAnimateMotionElement::applyResultsToTarget()
278 // We accumulate to the target element transform list so there is not much to do here.
279 SVGElement* targetElement = this->targetElement();
280 if (!targetElement)
281 return;
283 if (LayoutObject* layoutObject = targetElement->layoutObject())
284 markForLayoutAndParentResourceInvalidation(layoutObject);
286 AffineTransform* t = targetElement->animateMotionTransform();
287 if (!t)
288 return;
290 // ...except in case where we have additional instances in <use> trees.
291 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement>>& instances = targetElement->instancesForElement();
292 for (SVGElement* shadowTreeElement : instances) {
293 ASSERT(shadowTreeElement);
294 AffineTransform* transform = shadowTreeElement->animateMotionTransform();
295 if (!transform)
296 continue;
297 transform->setMatrix(t->a(), t->b(), t->c(), t->d(), t->e(), t->f());
298 if (LayoutObject* layoutObject = shadowTreeElement->layoutObject()) {
299 layoutObject->setNeedsTransformUpdate();
300 markForLayoutAndParentResourceInvalidation(layoutObject);
305 float SVGAnimateMotionElement::calculateDistance(const String& fromString, const String& toString)
307 FloatPoint from;
308 FloatPoint to;
309 if (!parsePoint(fromString, from))
310 return -1;
311 if (!parsePoint(toString, to))
312 return -1;
313 FloatSize diff = to - from;
314 return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
317 void SVGAnimateMotionElement::updateAnimationMode()
319 if (!m_animationPath.isEmpty())
320 setAnimationMode(PathAnimation);
321 else
322 SVGAnimationElement::updateAnimationMode();