Update To 11.40.268.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/SVGTransformList.h"
31
32 namespace blink {
33
34 inline SVGRadialGradientElement::SVGRadialGradientElement(Document& document)
35     : SVGGradientElement(SVGNames::radialGradientTag, document)
36     , m_cx(SVGAnimatedLength::create(this, SVGNames::cxAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
37     , m_cy(SVGAnimatedLength::create(this, SVGNames::cyAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
38     , m_r(SVGAnimatedLength::create(this, SVGNames::rAttr, SVGLength::create(LengthModeOther), ForbidNegativeLengths))
39     , m_fx(SVGAnimatedLength::create(this, SVGNames::fxAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
40     , m_fy(SVGAnimatedLength::create(this, SVGNames::fyAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
41     , m_fr(SVGAnimatedLength::create(this, SVGNames::frAttr, SVGLength::create(LengthModeOther), ForbidNegativeLengths))
42 {
43     // Spec: If the cx/cy/r attribute is not specified, the effect is as if a value of "50%" were specified.
44     m_cx->setDefaultValueAsString("50%");
45     m_cy->setDefaultValueAsString("50%");
46     m_r->setDefaultValueAsString("50%");
47
48     // SVG2-Draft Spec: If the fr attributed is not specified, the effect is as if a value of "0%" were specified.
49     m_fr->setDefaultValueAsString("0%");
50
51     addToPropertyMap(m_cx);
52     addToPropertyMap(m_cy);
53     addToPropertyMap(m_r);
54     addToPropertyMap(m_fx);
55     addToPropertyMap(m_fy);
56     addToPropertyMap(m_fr);
57 }
58
59 DEFINE_NODE_FACTORY(SVGRadialGradientElement)
60
61 bool SVGRadialGradientElement::isSupportedAttribute(const QualifiedName& attrName)
62 {
63     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
64     if (supportedAttributes.isEmpty()) {
65         supportedAttributes.add(SVGNames::cxAttr);
66         supportedAttributes.add(SVGNames::cyAttr);
67         supportedAttributes.add(SVGNames::fxAttr);
68         supportedAttributes.add(SVGNames::fyAttr);
69         supportedAttributes.add(SVGNames::rAttr);
70         supportedAttributes.add(SVGNames::frAttr);
71     }
72     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
73 }
74
75 void SVGRadialGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
76 {
77     parseAttributeNew(name, value);
78 }
79
80 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName)
81 {
82     if (!isSupportedAttribute(attrName)) {
83         SVGGradientElement::svgAttributeChanged(attrName);
84         return;
85     }
86
87     SVGElement::InvalidationGuard invalidationGuard(this);
88
89     updateRelativeLengthsInformation();
90
91     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
92     if (renderer)
93         renderer->invalidateCacheAndMarkForLayout();
94 }
95
96 RenderObject* SVGRadialGradientElement::createRenderer(RenderStyle*)
97 {
98     return new RenderSVGResourceRadialGradient(this);
99 }
100
101 static void setGradientAttributes(SVGGradientElement* element, RadialGradientAttributes& attributes, bool isRadial = true)
102 {
103     if (!attributes.hasSpreadMethod() && element->spreadMethod()->isSpecified())
104         attributes.setSpreadMethod(element->spreadMethod()->currentValue()->enumValue());
105
106     if (!attributes.hasGradientUnits() && element->gradientUnits()->isSpecified())
107         attributes.setGradientUnits(element->gradientUnits()->currentValue()->enumValue());
108
109     if (!attributes.hasGradientTransform() && element->gradientTransform()->isSpecified()) {
110         AffineTransform transform;
111         element->gradientTransform()->currentValue()->concatenate(transform);
112         attributes.setGradientTransform(transform);
113     }
114
115     if (!attributes.hasStops()) {
116         const Vector<Gradient::ColorStop>& stops(element->buildStops());
117         if (!stops.isEmpty())
118             attributes.setStops(stops);
119     }
120
121     if (isRadial) {
122         SVGRadialGradientElement* radial = toSVGRadialGradientElement(element);
123
124         if (!attributes.hasCx() && radial->cx()->isSpecified())
125             attributes.setCx(radial->cx()->currentValue());
126
127         if (!attributes.hasCy() && radial->cy()->isSpecified())
128             attributes.setCy(radial->cy()->currentValue());
129
130         if (!attributes.hasR() && radial->r()->isSpecified())
131             attributes.setR(radial->r()->currentValue());
132
133         if (!attributes.hasFx() && radial->fx()->isSpecified())
134             attributes.setFx(radial->fx()->currentValue());
135
136         if (!attributes.hasFy() && radial->fy()->isSpecified())
137             attributes.setFy(radial->fy()->currentValue());
138
139         if (!attributes.hasFr() && radial->fr()->isSpecified())
140             attributes.setFr(radial->fr()->currentValue());
141     }
142 }
143
144 bool SVGRadialGradientElement::collectGradientAttributes(RadialGradientAttributes& attributes)
145 {
146     if (!renderer())
147         return false;
148
149     WillBeHeapHashSet<RawPtrWillBeMember<SVGGradientElement> > processedGradients;
150     SVGGradientElement* current = this;
151
152     setGradientAttributes(current, attributes);
153     processedGradients.add(current);
154
155     while (true) {
156         // Respect xlink:href, take attributes from referenced element
157         Node* refNode = SVGURIReference::targetElementFromIRIString(current->href()->currentValue()->value(), treeScope());
158         if (refNode && isSVGGradientElement(*refNode)) {
159             current = toSVGGradientElement(refNode);
160
161             // Cycle detection
162             if (processedGradients.contains(current))
163                 break;
164
165             if (!current->renderer())
166                 return false;
167
168             setGradientAttributes(current, attributes, isSVGRadialGradientElement(*current));
169             processedGradients.add(current);
170         } else {
171             break;
172         }
173     }
174
175     // Handle default values for fx/fy
176     if (!attributes.hasFx())
177         attributes.setFx(attributes.cx());
178
179     if (!attributes.hasFy())
180         attributes.setFy(attributes.cy());
181
182     return true;
183 }
184
185 bool SVGRadialGradientElement::selfHasRelativeLengths() const
186 {
187     return m_cx->currentValue()->isRelative()
188         || m_cy->currentValue()->isRelative()
189         || m_r->currentValue()->isRelative()
190         || m_fx->currentValue()->isRelative()
191         || m_fy->currentValue()->isRelative()
192         || m_fr->currentValue()->isRelative();
193 }
194
195 } // namespace blink