Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / svg / SVGGraphicsElement.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 #include "SVGGraphicsElement.h"
23
24 #include "RenderSVGPath.h"
25 #include "RenderSVGResource.h"
26 #include "SVGMatrix.h"
27 #include "SVGNames.h"
28 #include "SVGPathData.h"
29 #include "SVGRect.h"
30 #include "SVGSVGElement.h"
31 #include "SVGStringList.h"
32 #include <wtf/NeverDestroyed.h>
33
34 namespace WebCore {
35
36 // Animated property definitions
37 DEFINE_ANIMATED_TRANSFORM_LIST(SVGGraphicsElement, SVGNames::transformAttr, Transform, transform)
38
39 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGGraphicsElement)
40     REGISTER_LOCAL_ANIMATED_PROPERTY(transform)
41     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
42     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
43 END_REGISTER_ANIMATED_PROPERTIES
44
45 SVGGraphicsElement::SVGGraphicsElement(const QualifiedName& tagName, Document& document)
46     : SVGElement(tagName, document)
47     , m_shouldIsolateBlending(false)
48 {
49     registerAnimatedPropertiesForSVGGraphicsElement();
50 }
51
52 SVGGraphicsElement::~SVGGraphicsElement() = default;
53
54 Ref<SVGMatrix> SVGGraphicsElement::getCTMForBindings()
55 {
56     return SVGMatrix::create(getCTM());
57 }
58
59 AffineTransform SVGGraphicsElement::getCTM(StyleUpdateStrategy styleUpdateStrategy)
60 {
61     return SVGLocatable::computeCTM(this, SVGLocatable::NearestViewportScope, styleUpdateStrategy);
62 }
63
64 Ref<SVGMatrix> SVGGraphicsElement::getScreenCTMForBindings()
65 {
66     return SVGMatrix::create(getScreenCTM());
67 }
68
69 AffineTransform SVGGraphicsElement::getScreenCTM(StyleUpdateStrategy styleUpdateStrategy)
70 {
71     return SVGLocatable::computeCTM(this, SVGLocatable::ScreenScope, styleUpdateStrategy);
72 }
73
74 AffineTransform SVGGraphicsElement::animatedLocalTransform() const
75 {
76     AffineTransform matrix;
77     auto* style = renderer() ? &renderer()->style() : nullptr;
78
79     // If CSS property was set, use that, otherwise fallback to attribute (if set).
80     if (style && style->hasTransform()) {
81         
82         FloatRect boundingBox;
83         switch (style->transformBox()) {
84         case TransformBox::FillBox:
85             boundingBox = renderer()->objectBoundingBox();
86             break;
87         case TransformBox::BorderBox:
88             // For SVG elements without an associated CSS layout box, the used value for border-box is view-box.
89         case TransformBox::ViewBox: {
90             FloatSize viewportSize;
91             SVGLengthContext(this).determineViewport(viewportSize);
92             boundingBox.setSize(viewportSize);
93             break;
94             }
95         }
96         
97         // Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath.
98         // See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/
99         TransformationMatrix transform;
100         style->applyTransform(transform, boundingBox);
101
102         // Flatten any 3D transform.
103         matrix = transform.toAffineTransform();
104         // CSS bakes the zoom factor into lengths, including translation components.
105         // In order to align CSS & SVG transforms, we need to invert this operation.
106         float zoom = style->effectiveZoom();
107         if (zoom != 1) {
108             matrix.setE(matrix.e() / zoom);
109             matrix.setF(matrix.f() / zoom);
110         }
111
112     } else
113         transform().concatenate(matrix);
114
115     if (m_supplementalTransform)
116         return *m_supplementalTransform * matrix;
117     return matrix;
118 }
119
120 AffineTransform* SVGGraphicsElement::supplementalTransform()
121 {
122     if (!m_supplementalTransform)
123         m_supplementalTransform = std::make_unique<AffineTransform>();
124     return m_supplementalTransform.get();
125 }
126
127 bool SVGGraphicsElement::isSupportedAttribute(const QualifiedName& attrName)
128 {
129     static const auto supportedAttributes = makeNeverDestroyed([] {
130         HashSet<QualifiedName> set;
131         SVGTests::addSupportedAttributes(set);
132         set.add(SVGNames::transformAttr);
133         return set;
134     }());
135     return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
136 }
137
138 void SVGGraphicsElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
139 {
140     if (name == SVGNames::transformAttr) {
141         SVGTransformListValues newList;
142         newList.parse(value);
143         detachAnimatedTransformListWrappers(newList.size());
144         setTransformBaseValue(newList);
145         return;
146     }
147
148     SVGElement::parseAttribute(name, value);
149     SVGTests::parseAttribute(name, value);
150 }
151
152 void SVGGraphicsElement::svgAttributeChanged(const QualifiedName& attrName)
153 {
154     if (!isSupportedAttribute(attrName)) {
155         SVGElement::svgAttributeChanged(attrName);
156         return;
157     }
158
159     InstanceInvalidationGuard guard(*this);
160
161     if (SVGTests::handleAttributeChange(this, attrName))
162         return;
163
164     auto renderer = this->renderer();
165     if (!renderer)
166         return;
167
168     if (attrName == SVGNames::transformAttr) {
169         renderer->setNeedsTransformUpdate();
170         RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
171         return;
172     }
173
174     ASSERT_NOT_REACHED();
175 }
176
177 SVGElement* SVGGraphicsElement::nearestViewportElement() const
178 {
179     return SVGTransformable::nearestViewportElement(this);
180 }
181
182 SVGElement* SVGGraphicsElement::farthestViewportElement() const
183 {
184     return SVGTransformable::farthestViewportElement(this);
185 }
186
187 Ref<SVGRect> SVGGraphicsElement::getBBoxForBindings()
188 {
189     return SVGRect::create(getBBox());
190 }
191
192 FloatRect SVGGraphicsElement::getBBox(StyleUpdateStrategy styleUpdateStrategy)
193 {
194     return SVGTransformable::getBBox(this, styleUpdateStrategy);
195 }
196
197 RenderPtr<RenderElement> SVGGraphicsElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
198 {
199     return createRenderer<RenderSVGPath>(*this, WTFMove(style));
200 }
201
202 void SVGGraphicsElement::toClipPath(Path& path)
203 {
204     updatePathFromGraphicsElement(this, path);
205     // FIXME: How do we know the element has done a layout?
206     path.transform(animatedLocalTransform());
207 }
208
209 Ref<SVGStringList> SVGGraphicsElement::requiredFeatures()
210 {
211     return SVGTests::requiredFeatures(*this);
212 }
213
214 Ref<SVGStringList> SVGGraphicsElement::requiredExtensions()
215
216     return SVGTests::requiredExtensions(*this);
217 }
218
219 Ref<SVGStringList> SVGGraphicsElement::systemLanguage()
220 {
221     return SVGTests::systemLanguage(*this);
222 }
223
224 }