Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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
26 #include "core/svg/SVGRadialGradientElement.h"
27
28 #include "core/rendering/svg/RenderSVGResourceRadialGradient.h"
29 #include "core/svg/RadialGradientAttributes.h"
30 #include "core/svg/SVGElementInstance.h"
31 #include "core/svg/SVGTransformList.h"
32
33 namespace WebCore {
34
35 // Animated property definitions
36
37 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGRadialGradientElement)
38     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGradientElement)
39 END_REGISTER_ANIMATED_PROPERTIES
40
41 inline SVGRadialGradientElement::SVGRadialGradientElement(Document& document)
42     : SVGGradientElement(SVGNames::radialGradientTag, document)
43     , m_cx(SVGAnimatedLength::create(this, SVGNames::cxAttr, SVGLength::create(LengthModeWidth)))
44     , m_cy(SVGAnimatedLength::create(this, SVGNames::cyAttr, SVGLength::create(LengthModeHeight)))
45     , m_r(SVGAnimatedLength::create(this, SVGNames::rAttr, SVGLength::create(LengthModeOther)))
46     , m_fx(SVGAnimatedLength::create(this, SVGNames::fxAttr, SVGLength::create(LengthModeWidth)))
47     , m_fy(SVGAnimatedLength::create(this, SVGNames::fyAttr, SVGLength::create(LengthModeHeight)))
48     , m_fr(SVGAnimatedLength::create(this, SVGNames::frAttr, SVGLength::create(LengthModeOther)))
49 {
50     ScriptWrappable::init(this);
51
52     // Spec: If the cx/cy/r attribute is not specified, the effect is as if a value of "50%" were specified.
53     m_cx->setDefaultValueAsString("50%");
54     m_cy->setDefaultValueAsString("50%");
55     m_r->setDefaultValueAsString("50%");
56
57     // SVG2-Draft Spec: If the fr attributed is not specified, the effect is as if a value of "0%" were specified.
58     m_fr->setDefaultValueAsString("0%");
59
60     addToPropertyMap(m_cx);
61     addToPropertyMap(m_cy);
62     addToPropertyMap(m_r);
63     addToPropertyMap(m_fx);
64     addToPropertyMap(m_fy);
65     addToPropertyMap(m_fr);
66     registerAnimatedPropertiesForSVGRadialGradientElement();
67 }
68
69 PassRefPtr<SVGRadialGradientElement> SVGRadialGradientElement::create(Document& document)
70 {
71     return adoptRef(new SVGRadialGradientElement(document));
72 }
73
74 bool SVGRadialGradientElement::isSupportedAttribute(const QualifiedName& attrName)
75 {
76     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
77     if (supportedAttributes.isEmpty()) {
78         supportedAttributes.add(SVGNames::cxAttr);
79         supportedAttributes.add(SVGNames::cyAttr);
80         supportedAttributes.add(SVGNames::fxAttr);
81         supportedAttributes.add(SVGNames::fyAttr);
82         supportedAttributes.add(SVGNames::rAttr);
83         supportedAttributes.add(SVGNames::frAttr);
84     }
85     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
86 }
87
88 void SVGRadialGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
89 {
90     SVGParsingError parseError = NoError;
91
92     if (!isSupportedAttribute(name))
93         SVGGradientElement::parseAttribute(name, value);
94     else if (name == SVGNames::cxAttr)
95         m_cx->setBaseValueAsString(value, AllowNegativeLengths, parseError);
96     else if (name == SVGNames::cyAttr)
97         m_cy->setBaseValueAsString(value, AllowNegativeLengths, parseError);
98     else if (name == SVGNames::rAttr)
99         m_r->setBaseValueAsString(value, ForbidNegativeLengths, parseError);
100     else if (name == SVGNames::fxAttr)
101         m_fx->setBaseValueAsString(value, AllowNegativeLengths, parseError);
102     else if (name == SVGNames::fyAttr)
103         m_fy->setBaseValueAsString(value, AllowNegativeLengths, parseError);
104     else if (name == SVGNames::frAttr)
105         m_fr->setBaseValueAsString(value, ForbidNegativeLengths, parseError);
106     else
107         ASSERT_NOT_REACHED();
108
109     reportAttributeParsingError(parseError, name, value);
110 }
111
112 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName)
113 {
114     if (!isSupportedAttribute(attrName)) {
115         SVGGradientElement::svgAttributeChanged(attrName);
116         return;
117     }
118
119     SVGElementInstance::InvalidationGuard invalidationGuard(this);
120
121     updateRelativeLengthsInformation();
122
123     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
124     if (renderer)
125         renderer->invalidateCacheAndMarkForLayout();
126 }
127
128 RenderObject* SVGRadialGradientElement::createRenderer(RenderStyle*)
129 {
130     return new RenderSVGResourceRadialGradient(this);
131 }
132
133 static void setGradientAttributes(SVGGradientElement* element, RadialGradientAttributes& attributes, bool isRadial = true)
134 {
135     if (!attributes.hasSpreadMethod() && element->spreadMethodSpecified())
136         attributes.setSpreadMethod(element->spreadMethodCurrentValue());
137
138     if (!attributes.hasGradientUnits() && element->gradientUnitsSpecified())
139         attributes.setGradientUnits(element->gradientUnitsCurrentValue());
140
141     if (!attributes.hasGradientTransform() && element->gradientTransformSpecified()) {
142         AffineTransform transform;
143         element->gradientTransformCurrentValue().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 = toSVGRadialGradientElement(element);
155
156         if (!attributes.hasCx() && radial->cx()->isSpecified())
157             attributes.setCx(radial->cx()->currentValue());
158
159         if (!attributes.hasCy() && radial->cy()->isSpecified())
160             attributes.setCy(radial->cy()->currentValue());
161
162         if (!attributes.hasR() && radial->r()->isSpecified())
163             attributes.setR(radial->r()->currentValue());
164
165         if (!attributes.hasFx() && radial->fx()->isSpecified())
166             attributes.setFx(radial->fx()->currentValue());
167
168         if (!attributes.hasFy() && radial->fy()->isSpecified())
169             attributes.setFy(radial->fy()->currentValue());
170
171         if (!attributes.hasFr() && radial->fr()->isSpecified())
172             attributes.setFr(radial->fr()->currentValue());
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()->currentValue()->value(), document());
190         if (refNode && isSVGGradientElement(*refNode)) {
191             current = toSVGGradientElement(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
207     // Handle default values for fx/fy
208     if (!attributes.hasFx())
209         attributes.setFx(attributes.cx());
210
211     if (!attributes.hasFy())
212         attributes.setFy(attributes.cy());
213
214     return true;
215 }
216
217 bool SVGRadialGradientElement::selfHasRelativeLengths() const
218 {
219     return m_cx->currentValue()->isRelative()
220         || m_cy->currentValue()->isRelative()
221         || m_r->currentValue()->isRelative()
222         || m_fx->currentValue()->isRelative()
223         || m_fy->currentValue()->isRelative()
224         || m_fr->currentValue()->isRelative();
225 }
226
227 }