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) Research In Motion Limited 2010. All rights reserved.
5 * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
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 "config.h"
24#include "SVGGradientElement.h"
25
26#include "ElementIterator.h"
27#include "RenderSVGHiddenContainer.h"
28#include "RenderSVGResourceLinearGradient.h"
29#include "RenderSVGResourceRadialGradient.h"
30#include "SVGNames.h"
31#include "SVGStopElement.h"
32#include "SVGTransformable.h"
33#include "StyleResolver.h"
34#include <wtf/IsoMallocInlines.h>
35#include <wtf/NeverDestroyed.h>
36
37namespace WebCore {
38
39WTF_MAKE_ISO_ALLOCATED_IMPL(SVGGradientElement);
40
41SVGGradientElement::SVGGradientElement(const QualifiedName& tagName, Document& document)
42 : SVGElement(tagName, document)
43 , SVGExternalResourcesRequired(this)
44 , SVGURIReference(this)
45{
46 static std::once_flag onceFlag;
47 std::call_once(onceFlag, [] {
48 PropertyRegistry::registerProperty<SVGNames::spreadMethodAttr, SVGSpreadMethodType, &SVGGradientElement::m_spreadMethod>();
49 PropertyRegistry::registerProperty<SVGNames::gradientUnitsAttr, SVGUnitTypes::SVGUnitType, &SVGGradientElement::m_gradientUnits>();
50 PropertyRegistry::registerProperty<SVGNames::gradientTransformAttr, &SVGGradientElement::m_gradientTransform>();
51 });
52}
53
54void SVGGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
55{
56 if (name == SVGNames::gradientUnitsAttr) {
57 auto propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
58 if (propertyValue > 0)
59 m_gradientUnits->setBaseValInternal<SVGUnitTypes::SVGUnitType>(propertyValue);
60 return;
61 }
62
63 if (name == SVGNames::gradientTransformAttr) {
64 m_gradientTransform->baseVal()->parse(value);
65 return;
66 }
67
68 if (name == SVGNames::spreadMethodAttr) {
69 auto propertyValue = SVGPropertyTraits<SVGSpreadMethodType>::fromString(value);
70 if (propertyValue > 0)
71 m_spreadMethod->setBaseValInternal<SVGSpreadMethodType>(propertyValue);
72 return;
73 }
74
75 SVGElement::parseAttribute(name, value);
76 SVGURIReference::parseAttribute(name, value);
77 SVGExternalResourcesRequired::parseAttribute(name, value);
78}
79
80void SVGGradientElement::svgAttributeChanged(const QualifiedName& attrName)
81{
82 if (PropertyRegistry::isKnownAttribute(attrName) || SVGURIReference::isKnownAttribute(attrName)) {
83 InstanceInvalidationGuard guard(*this);
84 if (RenderObject* object = renderer())
85 object->setNeedsLayout();
86 return;
87 }
88
89 SVGElement::svgAttributeChanged(attrName);
90}
91
92void SVGGradientElement::childrenChanged(const ChildChange& change)
93{
94 SVGElement::childrenChanged(change);
95
96 if (change.source == ChildChangeSource::Parser)
97 return;
98
99 if (RenderObject* object = renderer())
100 object->setNeedsLayout();
101}
102
103Vector<Gradient::ColorStop> SVGGradientElement::buildStops()
104{
105 Vector<Gradient::ColorStop> stops;
106 float previousOffset = 0.0f;
107
108 for (auto& stop : childrenOfType<SVGStopElement>(*this)) {
109 const Color& color = stop.stopColorIncludingOpacity();
110
111 // Figure out right monotonic offset.
112 float offset = stop.offset();
113 offset = std::min(std::max(previousOffset, offset), 1.0f);
114 previousOffset = offset;
115
116 stops.append(Gradient::ColorStop(offset, color));
117 }
118
119 return stops;
120}
121
122}
123