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.
7 This file is part of the WebKit project
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.
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.
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.
26 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
27 #include "SVGAnimateTransformElement.h"
29 #include "AffineTransform.h"
30 #include "RenderObject.h"
32 #include "SVGElementInstance.h"
33 #include "SVGParserUtilities.h"
34 #include "SVGSVGElement.h"
35 #include "SVGStyledTransformableElement.h"
36 #include "SVGTextElement.h"
37 #include "SVGTransform.h"
38 #include "SVGTransformList.h"
39 #include "SVGUseElement.h"
42 #include <wtf/MathExtras.h>
48 SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName
& tagName
, Document
* doc
)
49 : SVGAnimationElement(tagName
, doc
)
50 , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN
)
51 , m_baseIndexInTransformList(0)
55 SVGAnimateTransformElement::~SVGAnimateTransformElement()
59 bool SVGAnimateTransformElement::hasValidTarget() const
61 SVGElement
* targetElement
= this->targetElement();
62 return SVGAnimationElement::hasValidTarget() && (targetElement
->isStyledTransformable() || targetElement
->hasTagName(SVGNames::textTag
));
65 void SVGAnimateTransformElement::parseMappedAttribute(MappedAttribute
* attr
)
67 if (attr
->name() == SVGNames::typeAttr
) {
68 if (attr
->value() == "translate")
69 m_type
= SVGTransform::SVG_TRANSFORM_TRANSLATE
;
70 else if (attr
->value() == "scale")
71 m_type
= SVGTransform::SVG_TRANSFORM_SCALE
;
72 else if (attr
->value() == "rotate")
73 m_type
= SVGTransform::SVG_TRANSFORM_ROTATE
;
74 else if (attr
->value() == "skewX")
75 m_type
= SVGTransform::SVG_TRANSFORM_SKEWX
;
76 else if (attr
->value() == "skewY")
77 m_type
= SVGTransform::SVG_TRANSFORM_SKEWY
;
79 SVGAnimationElement::parseMappedAttribute(attr
);
83 static PassRefPtr
<SVGTransformList
> transformListFor(SVGElement
* element
)
86 if (element
->isStyledTransformable())
87 return static_cast<SVGStyledTransformableElement
*>(element
)->transform();
88 if (element
->hasTagName(SVGNames::textTag
))
89 return static_cast<SVGTextElement
*>(element
)->transform();
93 void SVGAnimateTransformElement::resetToBaseValue(const String
& baseValue
)
95 if (!hasValidTarget())
97 if (baseValue
.isEmpty()) {
99 RefPtr
<SVGTransformList
> list
= transformListFor(targetElement());
102 targetElement()->setAttribute(SVGNames::transformAttr
, baseValue
);
105 void SVGAnimateTransformElement::calculateAnimatedValue(float percentage
, unsigned repeat
, SVGSMILElement
* resultElement
)
107 if (!hasValidTarget())
109 SVGElement
* targetElement
= resultElement
->targetElement();
110 RefPtr
<SVGTransformList
> transformList
= transformListFor(targetElement
);
111 ASSERT(transformList
);
115 transformList
->clear(ec
);
116 if (isAccumulated() && repeat
) {
117 SVGTransform accumulatedTransform
= SVGTransformDistance(m_fromTransform
, m_toTransform
).scaledDistance(repeat
).addToSVGTransform(SVGTransform());
118 transformList
->appendItem(accumulatedTransform
, ec
);
120 SVGTransform transform
= SVGTransformDistance(m_fromTransform
, m_toTransform
).scaledDistance(percentage
).addToSVGTransform(m_fromTransform
);
121 transformList
->appendItem(transform
, ec
);
124 bool SVGAnimateTransformElement::calculateFromAndToValues(const String
& fromString
, const String
& toString
)
126 m_fromTransform
= parseTransformValue(fromString
);
127 if (!m_fromTransform
.isValid())
129 m_toTransform
= parseTransformValue(toString
);
130 return m_toTransform
.isValid();
133 bool SVGAnimateTransformElement::calculateFromAndByValues(const String
& fromString
, const String
& byString
)
136 m_fromTransform
= parseTransformValue(fromString
);
137 if (!m_fromTransform
.isValid())
139 m_toTransform
= SVGTransformDistance::addSVGTransforms(m_fromTransform
, parseTransformValue(byString
));
140 return m_toTransform
.isValid();
143 SVGTransform
SVGAnimateTransformElement::parseTransformValue(const String
& value
) const
146 return SVGTransform(m_type
);
148 // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis.
149 String
parseString("(" + value
+ ")");
150 const UChar
* ptr
= parseString
.characters();
151 SVGTransformable::parseTransformValue(m_type
, ptr
, ptr
+ parseString
.length(), result
); // ignoring return value
155 void SVGAnimateTransformElement::applyResultsToTarget()
157 if (!hasValidTarget())
159 // We accumulate to the target element transform list so there is not much to do here.
160 SVGElement
* targetElement
= this->targetElement();
161 if (targetElement
->renderer())
162 targetElement
->renderer()->setNeedsLayout(true);
164 // ...except in case where we have additional instances in <use> trees.
165 HashSet
<SVGElementInstance
*>* instances
= document()->accessSVGExtensions()->instancesForElement(targetElement
);
168 RefPtr
<SVGTransformList
> transformList
= transformListFor(targetElement
);
169 HashSet
<SVGElementInstance
*>::iterator end
= instances
->end();
170 for (HashSet
<SVGElementInstance
*>::iterator it
= instances
->begin(); it
!= end
; ++it
) {
171 SVGElement
* shadowTreeElement
= (*it
)->shadowTreeElement();
172 ASSERT(shadowTreeElement
);
173 if (shadowTreeElement
->isStyledTransformable())
174 static_cast<SVGStyledTransformableElement
*>(shadowTreeElement
)->setTransform(transformList
.get());
175 else if (shadowTreeElement
->hasTagName(SVGNames::textTag
))
176 static_cast<SVGTextElement
*>(shadowTreeElement
)->setTransform(transformList
.get());
177 if (shadowTreeElement
->renderer())
178 shadowTreeElement
->renderer()->setNeedsLayout(true);
182 float SVGAnimateTransformElement::calculateDistance(const String
& fromString
, const String
& toString
)
184 // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example)
185 // is paced separately. To implement this we need to treat each component as individual animation everywhere.
186 SVGTransform from
= parseTransformValue(fromString
);
189 SVGTransform to
= parseTransformValue(toString
);
190 if (!to
.isValid() || from
.type() != to
.type())
192 if (to
.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE
) {
193 FloatSize diff
= to
.translate() - from
.translate();
194 return sqrtf(diff
.width() * diff
.width() + diff
.height() * diff
.height());
196 if (to
.type() == SVGTransform::SVG_TRANSFORM_ROTATE
)
197 return fabsf(to
.angle() - from
.angle());
198 if (to
.type() == SVGTransform::SVG_TRANSFORM_SCALE
) {
199 FloatSize diff
= to
.scale() - from
.scale();
200 return sqrtf(diff
.width() * diff
.width() + diff
.height() * diff
.height());
208 #endif // ENABLE(SVG)