• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
3                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4     Copyright (C) 2007 Eric Seidel <eric@webkit.org>
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 #include "config.h"
26 
27 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
28 #include "SVGAnimateTransformElement.h"
29 
30 #include "MappedAttribute.h"
31 #include "RenderObject.h"
32 #include "SVGAngle.h"
33 #include "SVGElementInstance.h"
34 #include "SVGParserUtilities.h"
35 #include "SVGSVGElement.h"
36 #include "SVGStyledTransformableElement.h"
37 #include "SVGTextElement.h"
38 #include "SVGTransform.h"
39 #include "SVGTransformList.h"
40 #include "SVGUseElement.h"
41 #include "TransformationMatrix.h"
42 #include <math.h>
43 #include <wtf/MathExtras.h>
44 
45 using namespace std;
46 
47 namespace WebCore {
48 
SVGAnimateTransformElement(const QualifiedName & tagName,Document * doc)49 SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName& tagName, Document* doc)
50     : SVGAnimationElement(tagName, doc)
51     , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
52     , m_baseIndexInTransformList(0)
53 {
54 }
55 
~SVGAnimateTransformElement()56 SVGAnimateTransformElement::~SVGAnimateTransformElement()
57 {
58 }
59 
hasValidTarget() const60 bool SVGAnimateTransformElement::hasValidTarget() const
61 {
62     SVGElement* targetElement = this->targetElement();
63     return SVGAnimationElement::hasValidTarget() && (targetElement->isStyledTransformable() || targetElement->hasTagName(SVGNames::textTag));
64 }
65 
parseMappedAttribute(MappedAttribute * attr)66 void SVGAnimateTransformElement::parseMappedAttribute(MappedAttribute* attr)
67 {
68     if (attr->name() == SVGNames::typeAttr) {
69         if (attr->value() == "translate")
70             m_type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
71         else if (attr->value() == "scale")
72             m_type = SVGTransform::SVG_TRANSFORM_SCALE;
73         else if (attr->value() == "rotate")
74             m_type = SVGTransform::SVG_TRANSFORM_ROTATE;
75         else if (attr->value() == "skewX")
76             m_type = SVGTransform::SVG_TRANSFORM_SKEWX;
77         else if (attr->value() == "skewY")
78             m_type = SVGTransform::SVG_TRANSFORM_SKEWY;
79     } else
80         SVGAnimationElement::parseMappedAttribute(attr);
81 }
82 
83 
transformListFor(SVGElement * element)84 static PassRefPtr<SVGTransformList> transformListFor(SVGElement* element)
85 {
86     ASSERT(element);
87     if (element->isStyledTransformable())
88         return static_cast<SVGStyledTransformableElement*>(element)->transform();
89     if (element->hasTagName(SVGNames::textTag))
90         return static_cast<SVGTextElement*>(element)->transform();
91     return 0;
92 }
93 
resetToBaseValue(const String & baseValue)94 void SVGAnimateTransformElement::resetToBaseValue(const String& baseValue)
95 {
96     if (!hasValidTarget())
97         return;
98     if (baseValue.isEmpty()) {
99         ExceptionCode ec;
100         RefPtr<SVGTransformList> list = transformListFor(targetElement());
101         list->clear(ec);
102     } else
103         targetElement()->setAttribute(SVGNames::transformAttr, baseValue);
104 }
105 
calculateAnimatedValue(float percentage,unsigned repeat,SVGSMILElement * resultElement)106 void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
107 {
108     if (!hasValidTarget())
109         return;
110     SVGElement* targetElement = resultElement->targetElement();
111     RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
112     ASSERT(transformList);
113 
114     ExceptionCode ec;
115     if (!isAdditive())
116         transformList->clear(ec);
117     if (isAccumulated() && repeat) {
118         SVGTransform accumulatedTransform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(repeat).addToSVGTransform(SVGTransform());
119         transformList->appendItem(accumulatedTransform, ec);
120     }
121     SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform);
122     transformList->appendItem(transform, ec);
123 }
124 
calculateFromAndToValues(const String & fromString,const String & toString)125 bool SVGAnimateTransformElement::calculateFromAndToValues(const String& fromString, const String& toString)
126 {
127     m_fromTransform = parseTransformValue(fromString);
128     if (!m_fromTransform.isValid())
129         return false;
130     m_toTransform = parseTransformValue(toString);
131     return m_toTransform.isValid();
132 }
133 
calculateFromAndByValues(const String & fromString,const String & byString)134 bool SVGAnimateTransformElement::calculateFromAndByValues(const String& fromString, const String& byString)
135 {
136 
137     m_fromTransform = parseTransformValue(fromString);
138     if (!m_fromTransform.isValid())
139         return false;
140     m_toTransform = SVGTransformDistance::addSVGTransforms(m_fromTransform, parseTransformValue(byString));
141     return m_toTransform.isValid();
142 }
143 
parseTransformValue(const String & value) const144 SVGTransform SVGAnimateTransformElement::parseTransformValue(const String& value) const
145 {
146     if (value.isEmpty())
147         return SVGTransform(m_type);
148     SVGTransform result;
149     // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis.
150     String parseString("(" + value + ")");
151     const UChar* ptr = parseString.characters();
152     SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value
153     return result;
154 }
155 
applyResultsToTarget()156 void SVGAnimateTransformElement::applyResultsToTarget()
157 {
158     if (!hasValidTarget())
159         return;
160     // We accumulate to the target element transform list so there is not much to do here.
161     SVGElement* targetElement = this->targetElement();
162     if (targetElement->renderer())
163         targetElement->renderer()->setNeedsLayout(true);
164 
165     // ...except in case where we have additional instances in <use> trees.
166     HashSet<SVGElementInstance*> instances = targetElement->instancesForElement();
167     RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
168     HashSet<SVGElementInstance*>::iterator end = instances.end();
169     for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
170         SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
171         ASSERT(shadowTreeElement);
172         if (shadowTreeElement->isStyledTransformable())
173             static_cast<SVGStyledTransformableElement*>(shadowTreeElement)->setTransform(transformList.get());
174         else if (shadowTreeElement->hasTagName(SVGNames::textTag))
175             static_cast<SVGTextElement*>(shadowTreeElement)->setTransform(transformList.get());
176         if (shadowTreeElement->renderer())
177             shadowTreeElement->renderer()->setNeedsLayout(true);
178     }
179 }
180 
calculateDistance(const String & fromString,const String & toString)181 float SVGAnimateTransformElement::calculateDistance(const String& fromString, const String& toString)
182 {
183     // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example)
184     // is paced separately. To implement this we need to treat each component as individual animation everywhere.
185     SVGTransform from = parseTransformValue(fromString);
186     if (!from.isValid())
187         return -1.f;
188     SVGTransform to = parseTransformValue(toString);
189     if (!to.isValid() || from.type() != to.type())
190         return -1.f;
191     if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) {
192         FloatSize diff = to.translate() - from.translate();
193         return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
194     }
195     if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE)
196         return fabsf(to.angle() - from.angle());
197     if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) {
198         FloatSize diff = to.scale() - from.scale();
199         return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
200     }
201     return -1.f;
202 }
203 
204 }
205 
206 // vim:ts=4:noet
207 #endif // ENABLE(SVG)
208 
209