KHtml

SVGAnimateTransformElement.cpp
1 /*
2  Copyright (C) 2004, 2005 Nikolas Zimmermann <[email protected]>
3  2004, 2005, 2006, 2007 Rob Buis <[email protected]>
4  Copyright (C) 2007 Eric Seidel <[email protected]>
5  Copyright (C) 2008 Apple Inc. All Rights Reserved.
6 
7  This file is part of the WebKit project
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Library General Public
11  License as published by the Free Software Foundation; either
12  version 2 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Library General Public License for more details.
18 
19  You should have received a copy of the GNU Library General Public License
20  along with this library; see the file COPYING.LIB. If not, write to
21  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  Boston, MA 02110-1301, USA.
23 */
24 
25 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
26 #include "SVGAnimateTransformElement.h"
27 
28 #include "AffineTransform.h"
29 #include "RenderObject.h"
30 #include "SVGAngle.h"
31 #include "SVGElementInstance.h"
32 #include "SVGParserUtilities.h"
33 #include "SVGSVGElement.h"
34 #include "SVGStyledTransformableElement.h"
35 #include "SVGTextElement.h"
36 #include "SVGTransformList.h"
37 #include "SVGUseElement.h"
38 
39 #include <math.h>
40 #include <wtf/MathExtras.h>
41 
42 using namespace std;
43 
44 namespace WebCore
45 {
46 
47 SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName &tagName, Document *doc)
48  : SVGAnimationElement(tagName, doc)
49  , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
50  , m_baseIndexInTransformList(0)
51 {
52 }
53 
54 SVGAnimateTransformElement::~SVGAnimateTransformElement()
55 {
56 }
57 
58 bool SVGAnimateTransformElement::hasValidTarget() const
59 {
60  SVGElement *targetElement = this->targetElement();
61  return SVGAnimationElement::hasValidTarget() && (targetElement->isStyledTransformable() || targetElement->hasTagName(SVGNames::textTag));
62 }
63 
64 void SVGAnimateTransformElement::parseMappedAttribute(MappedAttribute *attr)
65 {
66  if (attr->name() == SVGNames::typeAttr) {
67  if (attr->value() == "translate") {
68  m_type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
69  } else if (attr->value() == "scale") {
70  m_type = SVGTransform::SVG_TRANSFORM_SCALE;
71  } else if (attr->value() == "rotate") {
72  m_type = SVGTransform::SVG_TRANSFORM_ROTATE;
73  } else if (attr->value() == "skewX") {
74  m_type = SVGTransform::SVG_TRANSFORM_SKEWX;
75  } else if (attr->value() == "skewY") {
76  m_type = SVGTransform::SVG_TRANSFORM_SKEWY;
77  }
78  } else {
79  SVGAnimationElement::parseMappedAttribute(attr);
80  }
81 }
82 
83 static PassRefPtr<SVGTransformList> transformListFor(SVGElement *element)
84 {
85  ASSERT(element);
86  if (element->isStyledTransformable()) {
87  return static_cast<SVGStyledTransformableElement *>(element)->transform();
88  }
89  if (element->hasTagName(SVGNames::textTag)) {
90  return static_cast<SVGTextElement *>(element)->transform();
91  }
92  return 0;
93 }
94 
95 void SVGAnimateTransformElement::resetToBaseValue(const String &baseValue)
96 {
97  if (!hasValidTarget()) {
98  return;
99  }
100  if (baseValue.isEmpty()) {
101  ExceptionCode ec;
102  RefPtr<SVGTransformList> list = transformListFor(targetElement());
103  list->clear(ec);
104  } else {
105  targetElement()->setAttribute(SVGNames::transformAttr, baseValue);
106  }
107 }
108 
109 void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement *resultElement)
110 {
111  if (!hasValidTarget()) {
112  return;
113  }
114  SVGElement *targetElement = resultElement->targetElement();
115  RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
116  ASSERT(transformList);
117 
118  ExceptionCode ec;
119  if (!isAdditive()) {
120  transformList->clear(ec);
121  }
122  if (isAccumulated() && repeat) {
123  SVGTransform accumulatedTransform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(repeat).addToSVGTransform(SVGTransform());
124  transformList->appendItem(accumulatedTransform, ec);
125  }
126  SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform);
127  transformList->appendItem(transform, ec);
128 }
129 
130 bool SVGAnimateTransformElement::calculateFromAndToValues(const String &fromString, const String &toString)
131 {
132  m_fromTransform = parseTransformValue(fromString);
133  if (!m_fromTransform.isValid()) {
134  return false;
135  }
136  m_toTransform = parseTransformValue(toString);
137  return m_toTransform.isValid();
138 }
139 
140 bool SVGAnimateTransformElement::calculateFromAndByValues(const String &fromString, const String &byString)
141 {
142 
143  m_fromTransform = parseTransformValue(fromString);
144  if (!m_fromTransform.isValid()) {
145  return false;
146  }
147  m_toTransform = SVGTransformDistance::addSVGTransforms(m_fromTransform, parseTransformValue(byString));
148  return m_toTransform.isValid();
149 }
150 
151 SVGTransform SVGAnimateTransformElement::parseTransformValue(const String &value) const
152 {
153  if (value.isEmpty()) {
154  return SVGTransform(m_type);
155  }
156  SVGTransform result;
157  // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis.
158  String parseString("(" + value + ")");
159  const UChar *ptr = parseString.characters();
160  SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value
161  return result;
162 }
163 
164 void SVGAnimateTransformElement::applyResultsToTarget()
165 {
166  if (!hasValidTarget()) {
167  return;
168  }
169  // We accumulate to the target element transform list so there is not much to do here.
170  SVGElement *targetElement = this->targetElement();
171  if (targetElement->renderer()) {
172  targetElement->renderer()->setNeedsLayout(true);
173  }
174 
175  // ...except in case where we have additional instances in <use> trees.
176  HashSet<SVGElementInstance *> *instances = document()->accessSVGExtensions()->instancesForElement(targetElement);
177  if (!instances) {
178  return;
179  }
180  RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
181  HashSet<SVGElementInstance *>::iterator end = instances->end();
182  for (HashSet<SVGElementInstance *>::iterator it = instances->begin(); it != end; ++it) {
183  SVGElement *shadowTreeElement = (*it)->shadowTreeElement();
184  ASSERT(shadowTreeElement);
185  if (shadowTreeElement->isStyledTransformable()) {
186  static_cast<SVGStyledTransformableElement *>(shadowTreeElement)->setTransform(transformList.get());
187  } else if (shadowTreeElement->hasTagName(SVGNames::textTag)) {
188  static_cast<SVGTextElement *>(shadowTreeElement)->setTransform(transformList.get());
189  }
190  if (shadowTreeElement->renderer()) {
191  shadowTreeElement->renderer()->setNeedsLayout(true);
192  }
193  }
194 }
195 
196 float SVGAnimateTransformElement::calculateDistance(const String &fromString, const String &toString)
197 {
198  // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example)
199  // is paced separately. To implement this we need to treat each component as individual animation everywhere.
200  SVGTransform from = parseTransformValue(fromString);
201  if (!from.isValid()) {
202  return -1.f;
203  }
204  SVGTransform to = parseTransformValue(toString);
205  if (!to.isValid() || from.type() != to.type()) {
206  return -1.f;
207  }
208  if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) {
209  FloatSize diff = to.translate() - from.translate();
210  return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
211  }
212  if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE) {
213  return fabsf(to.angle() - from.angle());
214  }
215  if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) {
216  FloatSize diff = to.scale() - from.scale();
217  return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
218  }
219  return -1.f;
220 }
221 
222 }
223 
224 #endif // ENABLE(SVG)
225 
KDOCTOOLS_EXPORT QString transform(const QString &file, const QString &stylesheet, const QVector< const char * > &params=QVector< const char * >())
const QList< QKeySequence > & end()
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:48:01 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.