2 Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
5 This file is part of the KDE project
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
24 #include "wtf/Platform.h"
27 #include "SVGRadialGradientElement.h"
29 #include "FloatConversion.h"
30 #include "FloatPoint.h"
31 #include "RadialGradientAttributes.h"
32 #include "RenderObject.h"
33 #include "SVGLength.h"
35 #include "SVGPaintServerRadialGradient.h"
36 #include "SVGStopElement.h"
37 #include "SVGTransform.h"
38 #include "SVGTransformList.h"
39 #include "SVGUnitTypes.h"
43 SVGRadialGradientElement::SVGRadialGradientElement(const QualifiedName
& tagName
, Document
* doc
)
44 : SVGGradientElement(tagName
, doc
)
45 , m_cx(this, LengthModeWidth
)
46 , m_cy(this, LengthModeHeight
)
47 , m_r(this, LengthModeOther
)
48 , m_fx(this, LengthModeWidth
)
49 , m_fy(this, LengthModeHeight
)
51 // Spec: If the attribute is not specified, the effect is as if a value of "50%" were specified.
52 setCxBaseValue(SVGLength(this, LengthModeWidth
, "50%"));
53 setCyBaseValue(SVGLength(this, LengthModeHeight
, "50%"));
54 setRBaseValue(SVGLength(this, LengthModeOther
, "50%"));
57 SVGRadialGradientElement::~SVGRadialGradientElement()
61 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement
, SVGLength
, Length
, length
, Cx
, cx
, SVGNames::cxAttr
, m_cx
)
62 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement
, SVGLength
, Length
, length
, Cy
, cy
, SVGNames::cyAttr
, m_cy
)
63 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement
, SVGLength
, Length
, length
, Fx
, fx
, SVGNames::fxAttr
, m_fx
)
64 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement
, SVGLength
, Length
, length
, Fy
, fy
, SVGNames::fyAttr
, m_fy
)
65 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement
, SVGLength
, Length
, length
, R
, r
, SVGNames::rAttr
, m_r
)
67 void SVGRadialGradientElement::parseMappedAttribute(MappedAttribute
* attr
)
69 if (attr
->name() == SVGNames::cxAttr
)
70 setCxBaseValue(SVGLength(this, LengthModeWidth
, attr
->value()));
71 else if (attr
->name() == SVGNames::cyAttr
)
72 setCyBaseValue(SVGLength(this, LengthModeHeight
, attr
->value()));
73 else if (attr
->name() == SVGNames::rAttr
) {
74 setRBaseValue(SVGLength(this, LengthModeOther
, attr
->value()));
75 if (r().value() < 0.0)
76 document()->accessSVGExtensions()->reportError("A negative value for radial gradient radius <r> is not allowed");
77 } else if (attr
->name() == SVGNames::fxAttr
)
78 setFxBaseValue(SVGLength(this, LengthModeWidth
, attr
->value()));
79 else if (attr
->name() == SVGNames::fyAttr
)
80 setFyBaseValue(SVGLength(this, LengthModeHeight
, attr
->value()));
82 SVGGradientElement::parseMappedAttribute(attr
);
85 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName
& attrName
)
87 SVGGradientElement::svgAttributeChanged(attrName
);
92 if (attrName
== SVGNames::cxAttr
|| attrName
== SVGNames::cyAttr
||
93 attrName
== SVGNames::fxAttr
|| attrName
== SVGNames::fyAttr
||
94 attrName
== SVGNames::rAttr
)
95 m_resource
->invalidate();
98 void SVGRadialGradientElement::buildGradient() const
100 RadialGradientAttributes attributes
= collectGradientProperties();
102 // If we didn't find any gradient containing stop elements, ignore the request.
103 if (attributes
.stops().isEmpty())
106 RefPtr
<SVGPaintServerRadialGradient
> radialGradient
= WTF::static_pointer_cast
<SVGPaintServerRadialGradient
>(m_resource
);
108 radialGradient
->setGradientStops(attributes
.stops());
109 radialGradient
->setBoundingBoxMode(attributes
.boundingBoxMode());
110 radialGradient
->setGradientSpreadMethod(attributes
.spreadMethod());
111 radialGradient
->setGradientTransform(attributes
.gradientTransform());
112 radialGradient
->setGradientCenter(FloatPoint::narrowPrecision(attributes
.cx(), attributes
.cy()));
113 radialGradient
->setGradientFocal(FloatPoint::narrowPrecision(attributes
.fx(), attributes
.fy()));
114 radialGradient
->setGradientRadius(narrowPrecisionToFloat(attributes
.r()));
117 RadialGradientAttributes
SVGRadialGradientElement::collectGradientProperties() const
119 RadialGradientAttributes attributes
;
120 HashSet
<const SVGGradientElement
*> processedGradients
;
122 bool isRadial
= true;
123 const SVGGradientElement
* current
= this;
126 if (!attributes
.hasSpreadMethod() && current
->hasAttribute(SVGNames::spreadMethodAttr
))
127 attributes
.setSpreadMethod((SVGGradientSpreadMethod
) current
->spreadMethod());
129 if (!attributes
.hasBoundingBoxMode() && current
->hasAttribute(SVGNames::gradientUnitsAttr
))
130 attributes
.setBoundingBoxMode(current
->getAttribute(SVGNames::gradientUnitsAttr
) == "objectBoundingBox");
132 if (!attributes
.hasGradientTransform() && current
->hasAttribute(SVGNames::gradientTransformAttr
))
133 attributes
.setGradientTransform(current
->gradientTransform()->consolidate().matrix());
135 if (!attributes
.hasStops()) {
136 const Vector
<SVGGradientStop
>& stops(current
->buildStops());
137 if (!stops
.isEmpty())
138 attributes
.setStops(stops
);
142 const SVGRadialGradientElement
* radial
= static_cast<const SVGRadialGradientElement
*>(current
);
144 if (!attributes
.hasCx() && current
->hasAttribute(SVGNames::cxAttr
))
145 attributes
.setCx(radial
->cx().valueAsPercentage());
147 if (!attributes
.hasCy() && current
->hasAttribute(SVGNames::cyAttr
))
148 attributes
.setCy(radial
->cy().valueAsPercentage());
150 if (!attributes
.hasR() && current
->hasAttribute(SVGNames::rAttr
))
151 attributes
.setR(radial
->r().valueAsPercentage());
153 if (!attributes
.hasFx() && current
->hasAttribute(SVGNames::fxAttr
))
154 attributes
.setFx(radial
->fx().valueAsPercentage());
156 if (!attributes
.hasFy() && current
->hasAttribute(SVGNames::fyAttr
))
157 attributes
.setFy(radial
->fy().valueAsPercentage());
160 processedGradients
.add(current
);
162 // Respect xlink:href, take attributes from referenced element
163 Node
* refNode
= ownerDocument()->getElementById(SVGURIReference::getTarget(current
->href()));
164 if (refNode
&& (refNode
->hasTagName(SVGNames::radialGradientTag
) || refNode
->hasTagName(SVGNames::linearGradientTag
))) {
165 current
= static_cast<const SVGGradientElement
*>(const_cast<const Node
*>(refNode
));
168 if (processedGradients
.contains(current
))
169 return RadialGradientAttributes();
171 isRadial
= current
->gradientType() == RadialGradientPaintServer
;
176 // Handle default values for fx/fy
177 if (!attributes
.hasFx())
178 attributes
.setFx(attributes
.cx());
180 if (!attributes
.hasFy())
181 attributes
.setFy(attributes
.cy());
186 // KHTML ElementImpl pure virtual method
187 quint32
SVGRadialGradientElement::id() const
189 return SVGNames::radialGradientTag
.id();
192 DOMString
SVGRadialGradientElement::tagName() const
194 return SVGNames::radialGradientTag
.tagName();
199 #endif // ENABLE(SVG)