99c1781758d05c1815e23674aab681bee2237254
[WebKit-https.git] / Source / WebCore / svg / SVGStyledTransformableElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #if ENABLE(SVG)
24 #include "SVGStyledTransformableElement.h"
25
26 #include "AffineTransform.h"
27 #include "Attribute.h"
28 #include "RenderSVGPath.h"
29 #include "RenderSVGResource.h"
30 #include "SVGElementInstance.h"
31 #include "SVGNames.h"
32 #include "SVGPathData.h"
33
34 namespace WebCore {
35
36 // Animated property definitions
37 DEFINE_ANIMATED_TRANSFORM_LIST(SVGStyledTransformableElement, SVGNames::transformAttr, Transform, transform)
38
39 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGStyledTransformableElement)
40     REGISTER_LOCAL_ANIMATED_PROPERTY(transform)
41     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGStyledLocatableElement)
42 END_REGISTER_ANIMATED_PROPERTIES
43
44 SVGStyledTransformableElement::SVGStyledTransformableElement(const QualifiedName& tagName, Document* document, ConstructionType constructionType)
45     : SVGStyledLocatableElement(tagName, document, constructionType)
46 {
47     registerAnimatedPropertiesForSVGStyledTransformableElement();
48 }
49
50 SVGStyledTransformableElement::~SVGStyledTransformableElement()
51 {
52 }
53
54 AffineTransform SVGStyledTransformableElement::getCTM(StyleUpdateStrategy styleUpdateStrategy)
55 {
56     return SVGLocatable::computeCTM(this, SVGLocatable::NearestViewportScope, styleUpdateStrategy);
57 }
58
59 AffineTransform SVGStyledTransformableElement::getScreenCTM(StyleUpdateStrategy styleUpdateStrategy)
60 {
61     return SVGLocatable::computeCTM(this, SVGLocatable::ScreenScope, styleUpdateStrategy);
62 }
63
64 AffineTransform SVGStyledTransformableElement::animatedLocalTransform() const
65 {
66     AffineTransform matrix;
67     RenderStyle* style = renderer() ? renderer()->style() : 0;
68
69     // if CSS property was set, use that, otherwise fallback to attribute (if set)
70     if (style && style->hasTransform()) {
71         TransformationMatrix t;
72         // For now, the transform-origin is not taken into account
73         // Also, any percentage values will not be taken into account
74         style->applyTransform(t, IntSize(0, 0), RenderStyle::ExcludeTransformOrigin);
75         // Flatten any 3D transform
76         matrix = t.toAffineTransform();
77     } else
78         transform().concatenate(matrix);
79
80     if (m_supplementalTransform)
81         return *m_supplementalTransform * matrix;
82     return matrix;
83 }
84
85 AffineTransform* SVGStyledTransformableElement::supplementalTransform()
86 {
87     if (!m_supplementalTransform)
88         m_supplementalTransform = adoptPtr(new AffineTransform);
89     return m_supplementalTransform.get();
90 }
91
92 bool SVGStyledTransformableElement::isSupportedAttribute(const QualifiedName& attrName)
93 {
94     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
95     if (supportedAttributes.isEmpty())
96         supportedAttributes.add(SVGNames::transformAttr);
97     return supportedAttributes.contains<QualifiedName, SVGAttributeHashTranslator>(attrName);
98 }
99
100 void SVGStyledTransformableElement::parseAttribute(Attribute* attr)
101 {
102     if (!isSupportedAttribute(attr->name())) {
103         SVGStyledLocatableElement::parseAttribute(attr);
104         return;
105     }
106
107     if (attr->name() == SVGNames::transformAttr) {
108         SVGTransformList newList;
109         if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
110             newList.clear();
111         detachAnimatedTransformListWrappers(newList.size());
112         setTransformBaseValue(newList);
113         return;
114     }
115
116     ASSERT_NOT_REACHED();
117 }
118
119 void SVGStyledTransformableElement::svgAttributeChanged(const QualifiedName& attrName)
120 {
121     if (!isSupportedAttribute(attrName)) {
122         SVGStyledLocatableElement::svgAttributeChanged(attrName);
123         return;
124     }
125
126     SVGElementInstance::InvalidationGuard invalidationGuard(this);
127
128     RenderObject* object = renderer();
129     if (!object)
130         return;
131
132     if (attrName == SVGNames::transformAttr) {
133         object->setNeedsTransformUpdate();
134         RenderSVGResource::markForLayoutAndParentResourceInvalidation(object);
135         return;
136     }
137
138     ASSERT_NOT_REACHED();
139 }
140
141 SVGElement* SVGStyledTransformableElement::nearestViewportElement() const
142 {
143     return SVGTransformable::nearestViewportElement(this);
144 }
145
146 SVGElement* SVGStyledTransformableElement::farthestViewportElement() const
147 {
148     return SVGTransformable::farthestViewportElement(this);
149 }
150
151 FloatRect SVGStyledTransformableElement::getBBox(StyleUpdateStrategy styleUpdateStrategy)
152 {
153     return SVGTransformable::getBBox(this, styleUpdateStrategy);
154 }
155
156 RenderObject* SVGStyledTransformableElement::createRenderer(RenderArena* arena, RenderStyle*)
157 {
158     // By default, any subclass is expected to do path-based drawing
159     return new (arena) RenderSVGPath(this);
160 }
161
162 void SVGStyledTransformableElement::toClipPath(Path& path)
163 {
164     updatePathFromGraphicsElement(this, path);
165     // FIXME: How do we know the element has done a layout?
166     path.transform(animatedLocalTransform());
167 }
168
169 }
170
171 #endif // ENABLE(SVG)