initial import
[vuplus_webkit] / Source / WebCore / 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 #if ENABLE(SVG)
27 #include "SVGLinearGradientElement.h"
28
29 #include "Attribute.h"
30 #include "Document.h"
31 #include "FloatPoint.h"
32 #include "LinearGradientAttributes.h"
33 #include "RenderSVGResourceLinearGradient.h"
34 #include "SVGElementInstance.h"
35 #include "SVGLength.h"
36 #include "SVGNames.h"
37 #include "SVGTransform.h"
38 #include "SVGTransformList.h"
39 #include "SVGUnitTypes.h"
40
41 namespace WebCore {
42
43 // Animated property definitions
44 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x1Attr, X1, x1)
45 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y1Attr, Y1, y1)
46 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x2Attr, X2, x2)
47 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y2Attr, Y2, y2)
48
49 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGLinearGradientElement)
50     REGISTER_LOCAL_ANIMATED_PROPERTY(x1)
51     REGISTER_LOCAL_ANIMATED_PROPERTY(y1)
52     REGISTER_LOCAL_ANIMATED_PROPERTY(x2)
53     REGISTER_LOCAL_ANIMATED_PROPERTY(y2)
54     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGradientElement)
55 END_REGISTER_ANIMATED_PROPERTIES
56
57 inline SVGLinearGradientElement::SVGLinearGradientElement(const QualifiedName& tagName, Document* document)
58     : SVGGradientElement(tagName, document)
59     , m_x1(LengthModeWidth)
60     , m_y1(LengthModeHeight)
61     , m_x2(LengthModeWidth, "100%")
62     , m_y2(LengthModeHeight)
63 {
64     // Spec: If the x2 attribute is not specified, the effect is as if a value of "100%" were specified.
65     ASSERT(hasTagName(SVGNames::linearGradientTag));
66     registerAnimatedPropertiesForSVGLinearGradientElement();
67 }
68
69 PassRefPtr<SVGLinearGradientElement> SVGLinearGradientElement::create(const QualifiedName& tagName, Document* document)
70 {
71     return adoptRef(new SVGLinearGradientElement(tagName, document));
72 }
73
74 bool SVGLinearGradientElement::isSupportedAttribute(const QualifiedName& attrName)
75 {
76     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
77     if (supportedAttributes.isEmpty()) {
78         supportedAttributes.add(SVGNames::x1Attr);
79         supportedAttributes.add(SVGNames::x2Attr);
80         supportedAttributes.add(SVGNames::y1Attr);
81         supportedAttributes.add(SVGNames::y2Attr);
82     }
83     return supportedAttributes.contains(attrName);
84 }
85
86 void SVGLinearGradientElement::parseMappedAttribute(Attribute* attr)
87 {
88     SVGParsingError parseError = NoError;
89
90     if (!isSupportedAttribute(attr->name()))
91         SVGGradientElement::parseMappedAttribute(attr);
92     else if (attr->name() == SVGNames::x1Attr)
93         setX1BaseValue(SVGLength::construct(LengthModeWidth, attr->value(), parseError));
94     else if (attr->name() == SVGNames::y1Attr)
95         setY1BaseValue(SVGLength::construct(LengthModeHeight, attr->value(), parseError));
96     else if (attr->name() == SVGNames::x2Attr)
97         setX2BaseValue(SVGLength::construct(LengthModeWidth, attr->value(), parseError));
98     else if (attr->name() == SVGNames::y2Attr)
99         setY2BaseValue(SVGLength::construct(LengthModeHeight, attr->value(), parseError));
100     else
101         ASSERT_NOT_REACHED();
102
103     reportAttributeParsingError(parseError, attr);
104 }
105
106 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName& attrName)
107 {
108     if (!isSupportedAttribute(attrName)) {
109         SVGGradientElement::svgAttributeChanged(attrName);
110         return;
111     }
112
113     SVGElementInstance::InvalidationGuard invalidationGuard(this);
114     
115     updateRelativeLengthsInformation();
116
117     if (RenderObject* object = renderer())
118         object->setNeedsLayout(true);
119 }
120
121 RenderObject* SVGLinearGradientElement::createRenderer(RenderArena* arena, RenderStyle*)
122 {
123     return new (arena) RenderSVGResourceLinearGradient(this);
124 }
125
126 bool SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttributes& attributes)
127 {
128     HashSet<SVGGradientElement*> processedGradients;
129
130     bool isLinear = true;
131     SVGGradientElement* current = this;
132
133     while (current) {
134         if (!current->renderer())
135             return false;
136
137         if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr))
138             attributes.setSpreadMethod(current->spreadMethod());
139
140         if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr))
141             attributes.setBoundingBoxMode(current->gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
142
143         if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) {
144             AffineTransform transform;
145             current->gradientTransform().concatenate(transform);
146             attributes.setGradientTransform(transform);
147         }
148
149         if (!attributes.hasStops()) {
150             const Vector<Gradient::ColorStop>& stops(current->buildStops());
151             if (!stops.isEmpty())
152                 attributes.setStops(stops);
153         }
154
155         if (isLinear) {
156             SVGLinearGradientElement* linear = static_cast<SVGLinearGradientElement*>(current);
157
158             if (!attributes.hasX1() && current->hasAttribute(SVGNames::x1Attr))
159                 attributes.setX1(linear->x1());
160
161             if (!attributes.hasY1() && current->hasAttribute(SVGNames::y1Attr))
162                 attributes.setY1(linear->y1());
163
164             if (!attributes.hasX2() && current->hasAttribute(SVGNames::x2Attr))
165                 attributes.setX2(linear->x2());
166
167             if (!attributes.hasY2() && current->hasAttribute(SVGNames::y2Attr))
168                 attributes.setY2(linear->y2());
169         }
170
171         processedGradients.add(current);
172
173         // Respect xlink:href, take attributes from referenced element
174         Node* refNode = SVGURIReference::targetElementFromIRIString(current->href(), document());
175         if (refNode && (refNode->hasTagName(SVGNames::linearGradientTag) || refNode->hasTagName(SVGNames::radialGradientTag))) {
176             current = static_cast<SVGGradientElement*>(refNode);
177
178             // Cycle detection
179             if (processedGradients.contains(current)) {
180                 current = 0;
181                 break;
182             }
183
184             isLinear = current->hasTagName(SVGNames::linearGradientTag);
185         } else
186             current = 0;
187     }
188
189     return true;
190 }
191
192 void SVGLinearGradientElement::calculateStartEndPoints(const LinearGradientAttributes& attributes, FloatPoint& startPoint, FloatPoint& endPoint)
193 {
194     // Determine gradient start/end points
195     if (attributes.boundingBoxMode()) {
196         startPoint = FloatPoint(attributes.x1().valueAsPercentage(), attributes.y1().valueAsPercentage());
197         endPoint = FloatPoint(attributes.x2().valueAsPercentage(), attributes.y2().valueAsPercentage());
198     } else {
199         startPoint = FloatPoint(attributes.x1().value(this), attributes.y1().value(this));
200         endPoint = FloatPoint(attributes.x2().value(this), attributes.y2().value(this));
201     }
202 }
203
204 bool SVGLinearGradientElement::selfHasRelativeLengths() const
205 {
206     return x1().isRelative()
207         || y1().isRelative()
208         || x2().isRelative()
209         || y2().isRelative();
210 }
211
212 }
213
214 #endif // ENABLE(SVG)