KHtml

SVGAnimateMotionElement.cpp
1 /*
2  Copyright (C) 2007 Eric Seidel <[email protected]>
3  (C) 2007 Rob Buis <[email protected]>
4  Copyright (C) 2008 Apple Inc. All Rights Reserved.
5 
6  This file is part of the WebKit project
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
23 
24 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
25 #include "SVGAnimateMotionElement.h"
26 
27 #include "RenderObject.h"
28 #include "SVGElementInstance.h"
29 #include "SVGMPathElement.h"
30 #include "SVGParserUtilities.h"
31 #include "SVGPathElement.h"
32 #include "SVGTransformList.h"
33 #include <math.h>
34 
35 namespace WebCore
36 {
37 
38 using namespace SVGNames;
39 
40 SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName &tagName, Document *doc)
41  : SVGAnimationElement(tagName, doc)
42  , m_baseIndexInTransformList(0)
43  , m_angle(0)
44 {
45 }
46 
47 SVGAnimateMotionElement::~SVGAnimateMotionElement()
48 {
49 }
50 
51 bool SVGAnimateMotionElement::hasValidTarget() const
52 {
53  if (!SVGAnimationElement::hasValidTarget()) {
54  return false;
55  }
56  SVGElement *targetElement = this->targetElement();
57  if (!targetElement->isStyledTransformable() && !targetElement->hasTagName(SVGNames::textTag)) {
58  return false;
59  }
60  // Spec: SVG 1.1 section 19.2.15
61  if (targetElement->hasTagName(gTag)
62  || targetElement->hasTagName(defsTag)
63  || targetElement->hasTagName(useTag)
64  || targetElement->hasTagName(imageTag)
65  || targetElement->hasTagName(switchTag)
66  || targetElement->hasTagName(pathTag)
67  || targetElement->hasTagName(rectTag)
68  || targetElement->hasTagName(circleTag)
69  || targetElement->hasTagName(ellipseTag)
70  || targetElement->hasTagName(lineTag)
71  || targetElement->hasTagName(polylineTag)
72  || targetElement->hasTagName(polygonTag)
73  || targetElement->hasTagName(textTag)
74  || targetElement->hasTagName(clipPathTag)
75  || targetElement->hasTagName(maskTag)
76  || targetElement->hasTagName(aTag)
77 #if ENABLE(SVG_FOREIGN_OBJECT)
78  || targetElement->hasTagName(foreignObjectTag)
79 #endif
80  ) {
81  return true;
82  }
83  return false;
84 }
85 
86 void SVGAnimateMotionElement::parseMappedAttribute(MappedAttribute *attr)
87 {
88  if (attr->name() == SVGNames::pathAttr) {
89  m_path = Path();
90  pathFromSVGData(m_path, attr->value());
91  } else {
92  SVGAnimationElement::parseMappedAttribute(attr);
93  }
94 }
95 
96 SVGAnimateMotionElement::RotateMode SVGAnimateMotionElement::rotateMode() const
97 {
98  static const AtomicString autoVal("auto");
99  static const AtomicString autoReverse("auto-reverse");
100  String rotate = getAttribute(SVGNames::rotateAttr);
101  if (rotate == autoVal) {
102  return RotateAuto;
103  }
104  if (rotate == autoReverse) {
105  return RotateAutoReverse;
106  }
107  return RotateAngle;
108 }
109 
110 Path SVGAnimateMotionElement::animationPath() const
111 {
112  for (Node *child = firstChild(); child; child = child->nextSibling()) {
113  if (child->hasTagName(SVGNames::mpathTag)) {
114  SVGMPathElement *mPath = static_cast<SVGMPathElement *>(child);
115  SVGPathElement *pathElement = mPath->pathElement();
116  if (pathElement) {
117  return pathElement->toPathData();
118  }
119  return Path();
120  }
121  }
122  if (hasAttribute(SVGNames::pathAttr)) {
123  return m_path;
124  }
125  return Path();
126 }
127 
128 static bool parsePoint(const String &s, FloatPoint &point)
129 {
130  if (s.isEmpty()) {
131  return false;
132  }
133  const UChar *cur = s.characters();
134  const UChar *end = cur + s.length();
135 
136  if (!skipOptionalSpaces(cur, end)) {
137  return false;
138  }
139 
140  float x = 0.0f;
141  if (!parseNumber(cur, end, x)) {
142  return false;
143  }
144 
145  float y = 0.0f;
146  if (!parseNumber(cur, end, y)) {
147  return false;
148  }
149 
150  point = FloatPoint(x, y);
151 
152  // disallow anything except spaces at the end
153  return !skipOptionalSpaces(cur, end);
154 }
155 
156 void SVGAnimateMotionElement::resetToBaseValue(const String &)
157 {
158  if (!hasValidTarget()) {
159  return;
160  }
161  SVGElement *target = targetElement();
162  AffineTransform *transform = target->supplementalTransform();
163  if (!transform) {
164  return;
165  }
166  transform->reset();
167 }
168 
169 bool SVGAnimateMotionElement::calculateFromAndToValues(const String &fromString, const String &toString)
170 {
171  parsePoint(fromString, m_fromPoint);
172  parsePoint(toString, m_toPoint);
173  return true;
174 }
175 
176 bool SVGAnimateMotionElement::calculateFromAndByValues(const String &fromString, const String &byString)
177 {
178  parsePoint(fromString, m_fromPoint);
179  FloatPoint byPoint;
180  parsePoint(byString, byPoint);
181  m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y());
182  return true;
183 }
184 
185 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement *)
186 {
187  SVGElement *target = targetElement();
188  if (!target) {
189  return;
190  }
191  AffineTransform *transform = target->supplementalTransform();
192  if (!transform) {
193  return;
194  }
195 
196  if (!isAdditive()) {
197  transform->reset();
198  }
199 
200  // FIXME: Implement accumulate.
201 
202  if (animationMode() == PathAnimation) {
203  ASSERT(!animationPath().isEmpty());
204  Path path = animationPath();
205  float positionOnPath = path.length() * percentage;
206  bool ok;
207  FloatPoint position = path.pointAtLength(positionOnPath, ok);
208  if (ok) {
209  transform->translate(position.x(), position.y());
210  RotateMode rotateMode = this->rotateMode();
211  if (rotateMode == RotateAuto || rotateMode == RotateAutoReverse) {
212  float angle = path.normalAngleAtLength(positionOnPath, ok);
213  if (rotateMode == RotateAutoReverse) {
214  angle += 180.f;
215  }
216  transform->rotate(angle);
217  }
218  }
219  return;
220  }
221  FloatSize diff = m_toPoint - m_fromPoint;
222  transform->translate(diff.width() * percentage + m_fromPoint.x(), diff.height() * percentage + m_fromPoint.y());
223 }
224 
225 void SVGAnimateMotionElement::applyResultsToTarget()
226 {
227  // We accumulate to the target element transform list so there is not much to do here.
228  SVGElement *targetElement = this->targetElement();
229  if (targetElement && targetElement->renderer()) {
230  targetElement->renderer()->setNeedsLayout(true);
231  }
232 
233  // ...except in case where we have additional instances in <use> trees.
234  HashSet<SVGElementInstance *> *instances = document()->accessSVGExtensions()->instancesForElement(targetElement);
235  if (!instances) {
236  return;
237  }
238  HashSet<SVGElementInstance *>::iterator end = instances->end();
239  for (HashSet<SVGElementInstance *>::iterator it = instances->begin(); it != end; ++it) {
240  SVGElement *shadowTreeElement = (*it)->shadowTreeElement();
241  ASSERT(shadowTreeElement);
242  AffineTransform *transform = shadowTreeElement->supplementalTransform();
243  AffineTransform *t = targetElement->supplementalTransform();
244  transform->setMatrix(t->a(), t->b(), t->c(), t->d(), t->e(), t->f());
245  if (shadowTreeElement->renderer()) {
246  shadowTreeElement->renderer()->setNeedsLayout(true);
247  }
248  }
249 }
250 
251 float SVGAnimateMotionElement::calculateDistance(const String &fromString, const String &toString)
252 {
253  FloatPoint from;
254  FloatPoint to;
255  if (!parsePoint(fromString, from)) {
256  return -1.f;
257  }
258  if (!parsePoint(toString, to)) {
259  return -1.f;
260  }
261  FloatSize diff = to - from;
262  return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
263 }
264 
265 }
266 
267 #endif // ENABLE(SVG)
268 
KDOCTOOLS_EXPORT QString transform(const QString &file, const QString &stylesheet, const QVector< const char * > &params=QVector< const char * >())
MESSAGECORE_EXPORT KMime::Content * firstChild(const KMime::Content *node)
const QList< QKeySequence > & end()
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:09 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.