Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / SVGLinearGradientElement.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/SVGLinearGradientElement.h"
27
28 #include "core/rendering/svg/RenderSVGResourceLinearGradient.h"
29 #include "core/svg/LinearGradientAttributes.h"
30 #include "core/svg/SVGElementInstance.h"
31 #include "core/svg/SVGLength.h"
32 #include "core/svg/SVGTransformList.h"
33
34 namespace WebCore {
35
36 inline SVGLinearGradientElement::SVGLinearGradientElement(Document& document)
37     : SVGGradientElement(SVGNames::linearGradientTag, document)
38     , m_x1(SVGAnimatedLength::create(this, SVGNames::x1Attr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
39     , m_y1(SVGAnimatedLength::create(this, SVGNames::y1Attr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
40     , m_x2(SVGAnimatedLength::create(this, SVGNames::x2Attr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
41     , m_y2(SVGAnimatedLength::create(this, SVGNames::y2Attr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
42 {
43     ScriptWrappable::init(this);
44
45     // Spec: If the x2 attribute is not specified, the effect is as if a value of "100%" were specified.
46     m_x2->setDefaultValueAsString("100%");
47
48     addToPropertyMap(m_x1);
49     addToPropertyMap(m_y1);
50     addToPropertyMap(m_x2);
51     addToPropertyMap(m_y2);
52 }
53
54 PassRefPtr<SVGLinearGradientElement> SVGLinearGradientElement::create(Document& document)
55 {
56     return adoptRef(new SVGLinearGradientElement(document));
57 }
58
59 bool SVGLinearGradientElement::isSupportedAttribute(const QualifiedName& attrName)
60 {
61     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
62     if (supportedAttributes.isEmpty()) {
63         supportedAttributes.add(SVGNames::x1Attr);
64         supportedAttributes.add(SVGNames::x2Attr);
65         supportedAttributes.add(SVGNames::y1Attr);
66         supportedAttributes.add(SVGNames::y2Attr);
67     }
68     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
69 }
70
71 void SVGLinearGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
72 {
73     SVGParsingError parseError = NoError;
74
75     if (!isSupportedAttribute(name))
76         SVGGradientElement::parseAttribute(name, value);
77     else if (name == SVGNames::x1Attr)
78         m_x1->setBaseValueAsString(value, parseError);
79     else if (name == SVGNames::y1Attr)
80         m_y1->setBaseValueAsString(value, parseError);
81     else if (name == SVGNames::x2Attr)
82         m_x2->setBaseValueAsString(value, parseError);
83     else if (name == SVGNames::y2Attr)
84         m_y2->setBaseValueAsString(value, parseError);
85     else
86         ASSERT_NOT_REACHED();
87
88     reportAttributeParsingError(parseError, name, value);
89 }
90
91 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName& attrName)
92 {
93     if (!isSupportedAttribute(attrName)) {
94         SVGGradientElement::svgAttributeChanged(attrName);
95         return;
96     }
97
98     SVGElement::InvalidationGuard invalidationGuard(this);
99
100     updateRelativeLengthsInformation();
101
102     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
103     if (renderer)
104         renderer->invalidateCacheAndMarkForLayout();
105 }
106
107 RenderObject* SVGLinearGradientElement::createRenderer(RenderStyle*)
108 {
109     return new RenderSVGResourceLinearGradient(this);
110 }
111
112 static void setGradientAttributes(SVGGradientElement* element, LinearGradientAttributes& attributes, bool isLinear = true)
113 {
114     if (!attributes.hasSpreadMethod() && element->spreadMethod()->isSpecified())
115         attributes.setSpreadMethod(element->spreadMethod()->currentValue()->enumValue());
116
117     if (!attributes.hasGradientUnits() && element->gradientUnits()->isSpecified())
118         attributes.setGradientUnits(element->gradientUnits()->currentValue()->enumValue());
119
120     if (!attributes.hasGradientTransform() && element->gradientTransform()->isSpecified()) {
121         AffineTransform transform;
122         element->gradientTransform()->currentValue()->concatenate(transform);
123         attributes.setGradientTransform(transform);
124     }
125
126     if (!attributes.hasStops()) {
127         const Vector<Gradient::ColorStop>& stops(element->buildStops());
128         if (!stops.isEmpty())
129             attributes.setStops(stops);
130     }
131
132     if (isLinear) {
133         SVGLinearGradientElement* linear = toSVGLinearGradientElement(element);
134
135         if (!attributes.hasX1() && linear->x1()->isSpecified())
136             attributes.setX1(linear->x1()->currentValue());
137
138         if (!attributes.hasY1() && linear->y1()->isSpecified())
139             attributes.setY1(linear->y1()->currentValue());
140
141         if (!attributes.hasX2() && linear->x2()->isSpecified())
142             attributes.setX2(linear->x2()->currentValue());
143
144         if (!attributes.hasY2() && linear->y2()->isSpecified())
145             attributes.setY2(linear->y2()->currentValue());
146     }
147 }
148
149 bool SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttributes& attributes)
150 {
151     if (!renderer())
152         return false;
153
154     HashSet<SVGGradientElement*> processedGradients;
155     SVGGradientElement* current = this;
156
157     setGradientAttributes(current, attributes);
158     processedGradients.add(current);
159
160     while (true) {
161         // Respect xlink:href, take attributes from referenced element
162         Node* refNode = SVGURIReference::targetElementFromIRIString(current->href()->currentValue()->value(), treeScope());
163         if (refNode && isSVGGradientElement(*refNode)) {
164             current = toSVGGradientElement(refNode);
165
166             // Cycle detection
167             if (processedGradients.contains(current))
168                 return true;
169
170             if (!current->renderer())
171                 return false;
172
173             setGradientAttributes(current, attributes, isSVGLinearGradientElement(*current));
174             processedGradients.add(current);
175         } else {
176             return true;
177         }
178     }
179
180     ASSERT_NOT_REACHED();
181     return false;
182 }
183
184 bool SVGLinearGradientElement::selfHasRelativeLengths() const
185 {
186     return m_x1->currentValue()->isRelative()
187         || m_y1->currentValue()->isRelative()
188         || m_x2->currentValue()->isRelative()
189         || m_y2->currentValue()->isRelative();
190 }
191
192 }