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