KHtml

SVGRadialGradientElement.cpp
1 /*
2  Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <[email protected]>
3  2004, 2005, 2006, 2007 Rob Buis <[email protected]>
4 
5  This file is part of the KDE project
6 
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.
11 
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.
16 
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.
21 */
22 
23 #include "wtf/Platform.h"
24 
25 #if ENABLE(SVG)
26 #include "SVGRadialGradientElement.h"
27 
28 #include "FloatConversion.h"
29 #include "FloatPoint.h"
30 #include "RadialGradientAttributes.h"
31 #include "RenderObject.h"
32 #include "SVGLength.h"
33 #include "SVGNames.h"
34 #include "SVGPaintServerRadialGradient.h"
35 #include "SVGStopElement.h"
36 #include "SVGTransform.h"
37 #include "SVGTransformList.h"
38 #include "SVGUnitTypes.h"
39 
40 namespace WebCore
41 {
42 
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)
50 {
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%"));
55 }
56 
57 SVGRadialGradientElement::~SVGRadialGradientElement()
58 {
59 }
60 
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)
66 
67 void SVGRadialGradientElement::parseMappedAttribute(MappedAttribute *attr)
68 {
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  }
78  } else if (attr->name() == SVGNames::fxAttr) {
79  setFxBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
80  } else if (attr->name() == SVGNames::fyAttr) {
81  setFyBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
82  } else {
83  SVGGradientElement::parseMappedAttribute(attr);
84  }
85 }
86 
87 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName &attrName)
88 {
89  SVGGradientElement::svgAttributeChanged(attrName);
90 
91  if (!m_resource) {
92  return;
93  }
94 
95  if (attrName == SVGNames::cxAttr || attrName == SVGNames::cyAttr ||
96  attrName == SVGNames::fxAttr || attrName == SVGNames::fyAttr ||
97  attrName == SVGNames::rAttr) {
98  m_resource->invalidate();
99  }
100 }
101 
102 void SVGRadialGradientElement::buildGradient() const
103 {
104  RadialGradientAttributes attributes = collectGradientProperties();
105 
106  // If we didn't find any gradient containing stop elements, ignore the request.
107  if (attributes.stops().isEmpty()) {
108  return;
109  }
110 
111  RefPtr<SVGPaintServerRadialGradient> radialGradient = WTF::static_pointer_cast<SVGPaintServerRadialGradient>(m_resource);
112 
113  radialGradient->setGradientStops(attributes.stops());
114  radialGradient->setBoundingBoxMode(attributes.boundingBoxMode());
115  radialGradient->setGradientSpreadMethod(attributes.spreadMethod());
116  radialGradient->setGradientTransform(attributes.gradientTransform());
117  radialGradient->setGradientCenter(FloatPoint::narrowPrecision(attributes.cx(), attributes.cy()));
118  radialGradient->setGradientFocal(FloatPoint::narrowPrecision(attributes.fx(), attributes.fy()));
119  radialGradient->setGradientRadius(narrowPrecisionToFloat(attributes.r()));
120 }
121 
122 RadialGradientAttributes SVGRadialGradientElement::collectGradientProperties() const
123 {
124  RadialGradientAttributes attributes;
125  HashSet<const SVGGradientElement *> processedGradients;
126 
127  bool isRadial = true;
128  const SVGGradientElement *current = this;
129 
130  while (current) {
131  if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr)) {
132  attributes.setSpreadMethod((SVGGradientSpreadMethod) current->spreadMethod());
133  }
134 
135  if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr)) {
136  attributes.setBoundingBoxMode(current->getAttribute(SVGNames::gradientUnitsAttr) == "objectBoundingBox");
137  }
138 
139  if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) {
140  attributes.setGradientTransform(current->gradientTransform()->consolidate().matrix());
141  }
142 
143  if (!attributes.hasStops()) {
144  const Vector<SVGGradientStop> &stops(current->buildStops());
145  if (!stops.isEmpty()) {
146  attributes.setStops(stops);
147  }
148  }
149 
150  if (isRadial) {
151  const SVGRadialGradientElement *radial = static_cast<const SVGRadialGradientElement *>(current);
152 
153  if (!attributes.hasCx() && current->hasAttribute(SVGNames::cxAttr)) {
154  attributes.setCx(radial->cx().valueAsPercentage());
155  }
156 
157  if (!attributes.hasCy() && current->hasAttribute(SVGNames::cyAttr)) {
158  attributes.setCy(radial->cy().valueAsPercentage());
159  }
160 
161  if (!attributes.hasR() && current->hasAttribute(SVGNames::rAttr)) {
162  attributes.setR(radial->r().valueAsPercentage());
163  }
164 
165  if (!attributes.hasFx() && current->hasAttribute(SVGNames::fxAttr)) {
166  attributes.setFx(radial->fx().valueAsPercentage());
167  }
168 
169  if (!attributes.hasFy() && current->hasAttribute(SVGNames::fyAttr)) {
170  attributes.setFy(radial->fy().valueAsPercentage());
171  }
172  }
173 
174  processedGradients.add(current);
175 
176  // Respect xlink:href, take attributes from referenced element
177  Node *refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
178  if (refNode && (refNode->hasTagName(SVGNames::radialGradientTag) || refNode->hasTagName(SVGNames::linearGradientTag))) {
179  current = static_cast<const SVGGradientElement *>(const_cast<const Node *>(refNode));
180 
181  // Cycle detection
182  if (processedGradients.contains(current)) {
183  return RadialGradientAttributes();
184  }
185 
186  isRadial = current->gradientType() == RadialGradientPaintServer;
187  } else {
188  current = nullptr;
189  }
190  }
191 
192  // Handle default values for fx/fy
193  if (!attributes.hasFx()) {
194  attributes.setFx(attributes.cx());
195  }
196 
197  if (!attributes.hasFy()) {
198  attributes.setFy(attributes.cy());
199  }
200 
201  return attributes;
202 }
203 
204 // KHTML ElementImpl pure virtual method
205 quint32 SVGRadialGradientElement::id() const
206 {
207  return SVGNames::radialGradientTag.id();
208 }
209 
210 }
211 
212 #endif // ENABLE(SVG)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:10 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.