KHtml

SVGLinearGradientElement.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 "SVGLinearGradientElement.h"
27 
28 #include "FloatPoint.h"
29 #include "LinearGradientAttributes.h"
30 #include "SVGLength.h"
31 #include "SVGNames.h"
32 #include "SVGPaintServerLinearGradient.h"
33 #include "SVGTransform.h"
34 #include "SVGTransformList.h"
35 #include "SVGUnitTypes.h"
36 
37 namespace WebCore
38 {
39 
40 SVGLinearGradientElement::SVGLinearGradientElement(const QualifiedName &tagName, Document *doc)
41  : SVGGradientElement(tagName, doc)
42  , m_x1(this, LengthModeWidth)
43  , m_y1(this, LengthModeHeight)
44  , m_x2(this, LengthModeWidth)
45  , m_y2(this, LengthModeHeight)
46 {
47  // Spec: If the attribute is not specified, the effect is as if a value of "100%" were specified.
48  setX2BaseValue(SVGLength(this, LengthModeWidth, "100%"));
49 }
50 
51 SVGLinearGradientElement::~SVGLinearGradientElement()
52 {
53 }
54 
55 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, X1, x1, SVGNames::x1Attr, m_x1)
56 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, Y1, y1, SVGNames::y1Attr, m_y1)
57 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, X2, x2, SVGNames::x2Attr, m_x2)
58 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, Y2, y2, SVGNames::y2Attr, m_y2)
59 
60 void SVGLinearGradientElement::parseMappedAttribute(MappedAttribute *attr)
61 {
62  if (attr->name() == SVGNames::x1Attr) {
63  setX1BaseValue(SVGLength(this, LengthModeWidth, attr->value()));
64  } else if (attr->name() == SVGNames::y1Attr) {
65  setY1BaseValue(SVGLength(this, LengthModeHeight, attr->value()));
66  } else if (attr->name() == SVGNames::x2Attr) {
67  setX2BaseValue(SVGLength(this, LengthModeWidth, attr->value()));
68  } else if (attr->name() == SVGNames::y2Attr) {
69  setY2BaseValue(SVGLength(this, LengthModeHeight, attr->value()));
70  } else {
71  SVGGradientElement::parseMappedAttribute(attr);
72  }
73 }
74 
75 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName &attrName)
76 {
77  SVGGradientElement::svgAttributeChanged(attrName);
78 
79  if (!m_resource) {
80  return;
81  }
82 
83  if (attrName == SVGNames::x1Attr || attrName == SVGNames::y1Attr ||
84  attrName == SVGNames::x2Attr || attrName == SVGNames::y2Attr) {
85  m_resource->invalidate();
86  }
87 }
88 
89 void SVGLinearGradientElement::buildGradient() const
90 {
91  LinearGradientAttributes attributes = collectGradientProperties();
92 
93  // If we didn't find any gradient containing stop elements, ignore the request.
94  if (attributes.stops().isEmpty()) {
95  return;
96  }
97 
98  RefPtr<SVGPaintServerLinearGradient> linearGradient = WTF::static_pointer_cast<SVGPaintServerLinearGradient>(m_resource);
99 
100  linearGradient->setGradientStops(attributes.stops());
101  linearGradient->setBoundingBoxMode(attributes.boundingBoxMode());
102  linearGradient->setGradientSpreadMethod(attributes.spreadMethod());
103  linearGradient->setGradientTransform(attributes.gradientTransform());
104  linearGradient->setGradientStart(FloatPoint::narrowPrecision(attributes.x1(), attributes.y1()));
105  linearGradient->setGradientEnd(FloatPoint::narrowPrecision(attributes.x2(), attributes.y2()));
106 }
107 
108 LinearGradientAttributes SVGLinearGradientElement::collectGradientProperties() const
109 {
110  LinearGradientAttributes attributes;
111  HashSet<const SVGGradientElement *> processedGradients;
112 
113  bool isLinear = true;
114  const SVGGradientElement *current = this;
115 
116  while (current) {
117  if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr)) {
118  attributes.setSpreadMethod((SVGGradientSpreadMethod) current->spreadMethod());
119  }
120 
121  if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr)) {
122  attributes.setBoundingBoxMode(current->getAttribute(SVGNames::gradientUnitsAttr) == "objectBoundingBox");
123  }
124 
125  if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) {
126  attributes.setGradientTransform(current->gradientTransform()->consolidate().matrix());
127  }
128 
129  if (!attributes.hasStops()) {
130  const Vector<SVGGradientStop> &stops(current->buildStops());
131  // qCDebug(KHTML_LOG) << "stops.isEmpty()" << stops.isEmpty();
132  if (!stops.isEmpty()) {
133  attributes.setStops(stops);
134  }
135  }
136 
137  if (isLinear) {
138  const SVGLinearGradientElement *linear = static_cast<const SVGLinearGradientElement *>(current);
139 
140  if (!attributes.hasX1() && current->hasAttribute(SVGNames::x1Attr)) {
141  attributes.setX1(linear->x1().valueAsPercentage());
142  }
143 
144  if (!attributes.hasY1() && current->hasAttribute(SVGNames::y1Attr)) {
145  attributes.setY1(linear->y1().valueAsPercentage());
146  }
147 
148  if (!attributes.hasX2() && current->hasAttribute(SVGNames::x2Attr)) {
149  attributes.setX2(linear->x2().valueAsPercentage());
150  }
151 
152  if (!attributes.hasY2() && current->hasAttribute(SVGNames::y2Attr)) {
153  attributes.setY2(linear->y2().valueAsPercentage());
154  }
155  }
156 
157  processedGradients.add(current);
158 
159  // Respect xlink:href, take attributes from referenced element
160  Node *refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
161  if (refNode && (refNode->hasTagName(SVGNames::linearGradientTag) || refNode->hasTagName(SVGNames::radialGradientTag))) {
162  current = static_cast<const SVGGradientElement *>(const_cast<const Node *>(refNode));
163  // int ec;
164  // qCDebug(KHTML_LOG) << "take attributes from" << current->getAttributeNS("", "id", ec);
165 
166  // Cycle detection
167  if (processedGradients.contains(current)) {
168  return LinearGradientAttributes();
169  }
170 
171  isLinear = current->gradientType() == LinearGradientPaintServer;
172  } else {
173  current = nullptr;
174  }
175  }
176 
177  return attributes;
178 }
179 
180 // KHTML ElementImpl pure virtual method
181 quint32 SVGLinearGradientElement::id() const
182 {
183  return SVGNames::linearGradientTag.id();
184 }
185 
186 }
187 
188 #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.