1/*
2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved.
8 * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26#include "config.h"
27#include "SVGFilterElement.h"
28
29#include "RenderSVGResourceFilter.h"
30#include "SVGFilterBuilder.h"
31#include "SVGFilterPrimitiveStandardAttributes.h"
32#include "SVGNames.h"
33#include "SVGParserUtilities.h"
34#include <wtf/IsoMallocInlines.h>
35#include <wtf/NeverDestroyed.h>
36
37namespace WebCore {
38
39WTF_MAKE_ISO_ALLOCATED_IMPL(SVGFilterElement);
40
41inline SVGFilterElement::SVGFilterElement(const QualifiedName& tagName, Document& document)
42 : SVGElement(tagName, document)
43 , SVGExternalResourcesRequired(this)
44 , SVGURIReference(this)
45{
46 // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
47 // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
48 ASSERT(hasTagName(SVGNames::filterTag));
49
50 static std::once_flag onceFlag;
51 std::call_once(onceFlag, [] {
52 PropertyRegistry::registerProperty<SVGNames::filterUnitsAttr, SVGUnitTypes::SVGUnitType, &SVGFilterElement::m_filterUnits>();
53 PropertyRegistry::registerProperty<SVGNames::primitiveUnitsAttr, SVGUnitTypes::SVGUnitType, &SVGFilterElement::m_primitiveUnits>();
54 PropertyRegistry::registerProperty<SVGNames::xAttr, &SVGFilterElement::m_x>();
55 PropertyRegistry::registerProperty<SVGNames::yAttr, &SVGFilterElement::m_y>();
56 PropertyRegistry::registerProperty<SVGNames::widthAttr, &SVGFilterElement::m_width>();
57 PropertyRegistry::registerProperty<SVGNames::heightAttr, &SVGFilterElement::m_height>();
58 });
59}
60
61Ref<SVGFilterElement> SVGFilterElement::create(const QualifiedName& tagName, Document& document)
62{
63 return adoptRef(*new SVGFilterElement(tagName, document));
64}
65
66void SVGFilterElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
67{
68 SVGParsingError parseError = NoError;
69
70 if (name == SVGNames::filterUnitsAttr) {
71 SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
72 if (propertyValue > 0)
73 m_filterUnits->setBaseValInternal<SVGUnitTypes::SVGUnitType>(propertyValue);
74 } else if (name == SVGNames::primitiveUnitsAttr) {
75 SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
76 if (propertyValue > 0)
77 m_primitiveUnits->setBaseValInternal<SVGUnitTypes::SVGUnitType>(propertyValue);
78 } else if (name == SVGNames::xAttr)
79 m_x->setBaseValInternal(SVGLengthValue::construct(LengthModeWidth, value, parseError));
80 else if (name == SVGNames::yAttr)
81 m_y->setBaseValInternal(SVGLengthValue::construct(LengthModeHeight, value, parseError));
82 else if (name == SVGNames::widthAttr)
83 m_width->setBaseValInternal(SVGLengthValue::construct(LengthModeWidth, value, parseError));
84 else if (name == SVGNames::heightAttr)
85 m_height->setBaseValInternal(SVGLengthValue::construct(LengthModeHeight, value, parseError));
86
87 reportAttributeParsingError(parseError, name, value);
88
89 SVGElement::parseAttribute(name, value);
90 SVGURIReference::parseAttribute(name, value);
91 SVGExternalResourcesRequired::parseAttribute(name, value);
92}
93
94void SVGFilterElement::svgAttributeChanged(const QualifiedName& attrName)
95{
96 if (PropertyRegistry::isAnimatedLengthAttribute(attrName)) {
97 InstanceInvalidationGuard guard(*this);
98 invalidateSVGPresentationAttributeStyle();
99 return;
100 }
101
102 if (PropertyRegistry::isKnownAttribute(attrName) || SVGURIReference::isKnownAttribute(attrName)) {
103 if (auto* renderer = this->renderer())
104 renderer->setNeedsLayout();
105 return;
106 }
107
108 SVGElement::svgAttributeChanged(attrName);
109 SVGExternalResourcesRequired::svgAttributeChanged(attrName);
110}
111
112void SVGFilterElement::childrenChanged(const ChildChange& change)
113{
114 SVGElement::childrenChanged(change);
115
116 if (change.source == ChildChangeSource::Parser)
117 return;
118
119 if (RenderObject* object = renderer())
120 object->setNeedsLayout();
121}
122
123RenderPtr<RenderElement> SVGFilterElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
124{
125 return createRenderer<RenderSVGResourceFilter>(*this, WTFMove(style));
126}
127
128bool SVGFilterElement::childShouldCreateRenderer(const Node& child) const
129{
130 if (!child.isSVGElement())
131 return false;
132
133 const SVGElement& svgElement = downcast<SVGElement>(child);
134
135 static NeverDestroyed<HashSet<QualifiedName>> allowedChildElementTags;
136 if (allowedChildElementTags.get().isEmpty()) {
137 allowedChildElementTags.get().add(SVGNames::feBlendTag);
138 allowedChildElementTags.get().add(SVGNames::feColorMatrixTag);
139 allowedChildElementTags.get().add(SVGNames::feComponentTransferTag);
140 allowedChildElementTags.get().add(SVGNames::feCompositeTag);
141 allowedChildElementTags.get().add(SVGNames::feConvolveMatrixTag);
142 allowedChildElementTags.get().add(SVGNames::feDiffuseLightingTag);
143 allowedChildElementTags.get().add(SVGNames::feDisplacementMapTag);
144 allowedChildElementTags.get().add(SVGNames::feDistantLightTag);
145 allowedChildElementTags.get().add(SVGNames::feDropShadowTag);
146 allowedChildElementTags.get().add(SVGNames::feFloodTag);
147 allowedChildElementTags.get().add(SVGNames::feFuncATag);
148 allowedChildElementTags.get().add(SVGNames::feFuncBTag);
149 allowedChildElementTags.get().add(SVGNames::feFuncGTag);
150 allowedChildElementTags.get().add(SVGNames::feFuncRTag);
151 allowedChildElementTags.get().add(SVGNames::feGaussianBlurTag);
152 allowedChildElementTags.get().add(SVGNames::feImageTag);
153 allowedChildElementTags.get().add(SVGNames::feMergeTag);
154 allowedChildElementTags.get().add(SVGNames::feMergeNodeTag);
155 allowedChildElementTags.get().add(SVGNames::feMorphologyTag);
156 allowedChildElementTags.get().add(SVGNames::feOffsetTag);
157 allowedChildElementTags.get().add(SVGNames::fePointLightTag);
158 allowedChildElementTags.get().add(SVGNames::feSpecularLightingTag);
159 allowedChildElementTags.get().add(SVGNames::feSpotLightTag);
160 allowedChildElementTags.get().add(SVGNames::feTileTag);
161 allowedChildElementTags.get().add(SVGNames::feTurbulenceTag);
162 }
163
164 return allowedChildElementTags.get().contains<SVGAttributeHashTranslator>(svgElement.tagQName());
165}
166
167}
168