Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / svg / SVGRadialGradientElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
5  * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
6  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25 #include "SVGRadialGradientElement.h"
26
27 #include "FloatConversion.h"
28 #include "FloatPoint.h"
29 #include "RadialGradientAttributes.h"
30 #include "RenderSVGResourceRadialGradient.h"
31 #include "SVGNames.h"
32 #include "SVGStopElement.h"
33 #include "SVGTransform.h"
34 #include "SVGTransformList.h"
35 #include "SVGUnitTypes.h"
36 #include <wtf/NeverDestroyed.h>
37
38 namespace WebCore {
39
40 // Animated property definitions
41 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::cxAttr, Cx, cx)
42 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::cyAttr, Cy, cy)
43 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::rAttr, R, r)
44 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::fxAttr, Fx, fx)
45 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::fyAttr, Fy, fy)
46 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::frAttr, Fr, fr)
47
48 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGRadialGradientElement)
49     REGISTER_LOCAL_ANIMATED_PROPERTY(cx)
50     REGISTER_LOCAL_ANIMATED_PROPERTY(cy)
51     REGISTER_LOCAL_ANIMATED_PROPERTY(r)
52     REGISTER_LOCAL_ANIMATED_PROPERTY(fx)
53     REGISTER_LOCAL_ANIMATED_PROPERTY(fy)
54     REGISTER_LOCAL_ANIMATED_PROPERTY(fr)
55     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGradientElement)
56 END_REGISTER_ANIMATED_PROPERTIES
57
58 inline SVGRadialGradientElement::SVGRadialGradientElement(const QualifiedName& tagName, Document& document)
59     : SVGGradientElement(tagName, document)
60     , m_cx(LengthModeWidth, "50%")
61     , m_cy(LengthModeHeight, "50%")
62     , m_r(LengthModeOther, "50%")
63     , m_fx(LengthModeWidth)
64     , m_fy(LengthModeHeight)
65     , m_fr(LengthModeOther, "0%")
66 {
67     // Spec: If the cx/cy/r/fr attribute is not specified, the effect is as if a value of "50%" were specified.
68     ASSERT(hasTagName(SVGNames::radialGradientTag));
69     registerAnimatedPropertiesForSVGRadialGradientElement();
70 }
71
72 Ref<SVGRadialGradientElement> SVGRadialGradientElement::create(const QualifiedName& tagName, Document& document)
73 {
74     return adoptRef(*new SVGRadialGradientElement(tagName, document));
75 }
76
77 bool SVGRadialGradientElement::isSupportedAttribute(const QualifiedName& attrName)
78 {
79     static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
80     if (supportedAttributes.get().isEmpty()) {
81         supportedAttributes.get().add(SVGNames::cxAttr);
82         supportedAttributes.get().add(SVGNames::cyAttr);
83         supportedAttributes.get().add(SVGNames::fxAttr);
84         supportedAttributes.get().add(SVGNames::fyAttr);
85         supportedAttributes.get().add(SVGNames::rAttr);
86         supportedAttributes.get().add(SVGNames::frAttr);
87     }
88     return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
89 }
90
91 void SVGRadialGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
92 {
93     SVGParsingError parseError = NoError;
94
95     if (name == SVGNames::cxAttr)
96         setCxBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
97     else if (name == SVGNames::cyAttr)
98         setCyBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
99     else if (name == SVGNames::rAttr)
100         setRBaseValue(SVGLength::construct(LengthModeOther, value, parseError, ForbidNegativeLengths));
101     else if (name == SVGNames::fxAttr)
102         setFxBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
103     else if (name == SVGNames::fyAttr)
104         setFyBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
105     else if (name == SVGNames::frAttr)
106         setFrBaseValue(SVGLength::construct(LengthModeOther, value, parseError, ForbidNegativeLengths));
107
108     reportAttributeParsingError(parseError, name, value);
109
110     SVGGradientElement::parseAttribute(name, value);
111 }
112
113 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName)
114 {
115     if (!isSupportedAttribute(attrName)) {
116         SVGGradientElement::svgAttributeChanged(attrName);
117         return;
118     }
119
120     InstanceInvalidationGuard guard(*this);
121     
122     updateRelativeLengthsInformation();
123         
124     if (RenderObject* object = renderer())
125         object->setNeedsLayout();
126 }
127
128 RenderPtr<RenderElement> SVGRadialGradientElement::createElementRenderer(Ref<RenderStyle>&& style, const RenderTreePosition&)
129 {
130     return createRenderer<RenderSVGResourceRadialGradient>(*this, WTFMove(style));
131 }
132
133 static void setGradientAttributes(SVGGradientElement& element, RadialGradientAttributes& attributes, bool isRadial = true)
134 {
135     if (!attributes.hasSpreadMethod() && element.hasAttribute(SVGNames::spreadMethodAttr))
136         attributes.setSpreadMethod(element.spreadMethod());
137
138     if (!attributes.hasGradientUnits() && element.hasAttribute(SVGNames::gradientUnitsAttr))
139         attributes.setGradientUnits(element.gradientUnits());
140
141     if (!attributes.hasGradientTransform() && element.hasAttribute(SVGNames::gradientTransformAttr)) {
142         AffineTransform transform;
143         element.gradientTransform().concatenate(transform);
144         attributes.setGradientTransform(transform);
145     }
146
147     if (!attributes.hasStops()) {
148         const Vector<Gradient::ColorStop>& stops(element.buildStops());
149         if (!stops.isEmpty())
150             attributes.setStops(stops);
151     }
152
153     if (isRadial) {
154         SVGRadialGradientElement& radial = downcast<SVGRadialGradientElement>(element);
155
156         if (!attributes.hasCx() && element.hasAttribute(SVGNames::cxAttr))
157             attributes.setCx(radial.cx());
158
159         if (!attributes.hasCy() && element.hasAttribute(SVGNames::cyAttr))
160             attributes.setCy(radial.cy());
161
162         if (!attributes.hasR() && element.hasAttribute(SVGNames::rAttr))
163             attributes.setR(radial.r());
164
165         if (!attributes.hasFx() && element.hasAttribute(SVGNames::fxAttr))
166             attributes.setFx(radial.fx());
167
168         if (!attributes.hasFy() && element.hasAttribute(SVGNames::fyAttr))
169             attributes.setFy(radial.fy());
170
171         if (!attributes.hasFr() && element.hasAttribute(SVGNames::frAttr))
172             attributes.setFr(radial.fr());
173     }
174 }
175
176 bool SVGRadialGradientElement::collectGradientAttributes(RadialGradientAttributes& attributes)
177 {
178     if (!renderer())
179         return false;
180
181     HashSet<SVGGradientElement*> processedGradients;
182     SVGGradientElement* current = this;
183
184     setGradientAttributes(*current, attributes);
185     processedGradients.add(current);
186
187     while (true) {
188         // Respect xlink:href, take attributes from referenced element
189         Node* refNode = SVGURIReference::targetElementFromIRIString(current->href(), document());
190         if (is<SVGGradientElement>(refNode)) {
191             current = downcast<SVGGradientElement>(refNode);
192
193             // Cycle detection
194             if (processedGradients.contains(current))
195                 break;
196
197             if (!current->renderer())
198                 return false;
199
200             setGradientAttributes(*current, attributes, current->hasTagName(SVGNames::radialGradientTag));
201             processedGradients.add(current);
202         } else
203             break;
204     }
205
206     // Handle default values for fx/fy
207     if (!attributes.hasFx())
208         attributes.setFx(attributes.cx());
209
210     if (!attributes.hasFy())
211         attributes.setFy(attributes.cy());
212
213     return true;
214 }
215
216 bool SVGRadialGradientElement::selfHasRelativeLengths() const
217 {
218     return cx().isRelative()
219         || cy().isRelative()
220         || r().isRelative()
221         || fx().isRelative()
222         || fy().isRelative()
223         || fr().isRelative();
224 }
225
226 }