1 | /* |
2 | * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> |
3 | * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> |
4 | * Copyright (C) 2010 Dirk Schulze <krit@webkit.org> |
5 | * Copyright (C) 2018 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 "SVGFEImageElement.h" |
25 | |
26 | #include "CachedImage.h" |
27 | #include "CachedResourceLoader.h" |
28 | #include "CachedResourceRequest.h" |
29 | #include "Document.h" |
30 | #include "Image.h" |
31 | #include "RenderObject.h" |
32 | #include "RenderSVGResource.h" |
33 | #include "SVGNames.h" |
34 | #include "SVGPreserveAspectRatioValue.h" |
35 | #include <wtf/IsoMallocInlines.h> |
36 | |
37 | namespace WebCore { |
38 | |
39 | WTF_MAKE_ISO_ALLOCATED_IMPL(SVGFEImageElement); |
40 | |
41 | inline SVGFEImageElement::SVGFEImageElement(const QualifiedName& tagName, Document& document) |
42 | : SVGFilterPrimitiveStandardAttributes(tagName, document) |
43 | , SVGExternalResourcesRequired(this) |
44 | , SVGURIReference(this) |
45 | { |
46 | ASSERT(hasTagName(SVGNames::feImageTag)); |
47 | |
48 | static std::once_flag onceFlag; |
49 | std::call_once(onceFlag, [] { |
50 | PropertyRegistry::registerProperty<SVGNames::preserveAspectRatioAttr, &SVGFEImageElement::m_preserveAspectRatio>(); |
51 | }); |
52 | } |
53 | |
54 | Ref<SVGFEImageElement> SVGFEImageElement::create(const QualifiedName& tagName, Document& document) |
55 | { |
56 | return adoptRef(*new SVGFEImageElement(tagName, document)); |
57 | } |
58 | |
59 | SVGFEImageElement::~SVGFEImageElement() |
60 | { |
61 | clearResourceReferences(); |
62 | } |
63 | |
64 | bool SVGFEImageElement::hasSingleSecurityOrigin() const |
65 | { |
66 | if (!m_cachedImage) |
67 | return true; |
68 | auto* image = m_cachedImage->image(); |
69 | return !image || image->hasSingleSecurityOrigin(); |
70 | } |
71 | |
72 | void SVGFEImageElement::clearResourceReferences() |
73 | { |
74 | if (m_cachedImage) { |
75 | m_cachedImage->removeClient(*this); |
76 | m_cachedImage = nullptr; |
77 | } |
78 | |
79 | document().accessSVGExtensions().removeAllTargetReferencesForElement(*this); |
80 | } |
81 | |
82 | void SVGFEImageElement::requestImageResource() |
83 | { |
84 | ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); |
85 | options.contentSecurityPolicyImposition = isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck; |
86 | |
87 | CachedResourceRequest request(ResourceRequest(document().completeURL(href())), options); |
88 | request.setInitiator(*this); |
89 | m_cachedImage = document().cachedResourceLoader().requestImage(WTFMove(request)).value_or(nullptr); |
90 | |
91 | if (m_cachedImage) |
92 | m_cachedImage->addClient(*this); |
93 | } |
94 | |
95 | void SVGFEImageElement::buildPendingResource() |
96 | { |
97 | clearResourceReferences(); |
98 | if (!isConnected()) |
99 | return; |
100 | |
101 | auto target = SVGURIReference::targetElementFromIRIString(href(), treeScope()); |
102 | if (!target.element) { |
103 | if (target.identifier.isEmpty()) |
104 | requestImageResource(); |
105 | else { |
106 | document().accessSVGExtensions().addPendingResource(target.identifier, *this); |
107 | ASSERT(hasPendingResources()); |
108 | } |
109 | } else if (is<SVGElement>(*target.element)) { |
110 | // Register us with the target in the dependencies map. Any change of hrefElement |
111 | // that leads to relayout/repainting now informs us, so we can react to it. |
112 | document().accessSVGExtensions().addElementReferencingTarget(*this, downcast<SVGElement>(*target.element)); |
113 | } |
114 | |
115 | invalidate(); |
116 | } |
117 | |
118 | void SVGFEImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value) |
119 | { |
120 | if (name == SVGNames::preserveAspectRatioAttr) { |
121 | SVGPreserveAspectRatioValue preserveAspectRatio; |
122 | preserveAspectRatio.parse(value); |
123 | m_preserveAspectRatio->setBaseValInternal(preserveAspectRatio); |
124 | return; |
125 | } |
126 | |
127 | SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value); |
128 | SVGURIReference::parseAttribute(name, value); |
129 | SVGExternalResourcesRequired::parseAttribute(name, value); |
130 | } |
131 | |
132 | void SVGFEImageElement::svgAttributeChanged(const QualifiedName& attrName) |
133 | { |
134 | if (attrName == SVGNames::preserveAspectRatioAttr) { |
135 | InstanceInvalidationGuard guard(*this); |
136 | invalidate(); |
137 | return; |
138 | } |
139 | |
140 | if (SVGURIReference::isKnownAttribute(attrName)) { |
141 | InstanceInvalidationGuard guard(*this); |
142 | buildPendingResource(); |
143 | return; |
144 | } |
145 | |
146 | SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName); |
147 | } |
148 | |
149 | Node::InsertedIntoAncestorResult SVGFEImageElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree) |
150 | { |
151 | SVGFilterPrimitiveStandardAttributes::insertedIntoAncestor(insertionType, parentOfInsertedTree); |
152 | return InsertedIntoAncestorResult::NeedsPostInsertionCallback; |
153 | } |
154 | |
155 | void SVGFEImageElement::didFinishInsertingNode() |
156 | { |
157 | buildPendingResource(); |
158 | } |
159 | |
160 | void SVGFEImageElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree) |
161 | { |
162 | SVGFilterPrimitiveStandardAttributes::removedFromAncestor(removalType, oldParentOfRemovedTree); |
163 | if (removalType.disconnectedFromDocument) |
164 | clearResourceReferences(); |
165 | } |
166 | |
167 | void SVGFEImageElement::notifyFinished(CachedResource&) |
168 | { |
169 | if (!isConnected()) |
170 | return; |
171 | |
172 | auto parent = makeRefPtr(parentElement()); |
173 | |
174 | if (!parent || !parent->hasTagName(SVGNames::filterTag)) |
175 | return; |
176 | |
177 | RenderElement* parentRenderer = parent->renderer(); |
178 | if (!parentRenderer) |
179 | return; |
180 | |
181 | RenderSVGResource::markForLayoutAndParentResourceInvalidation(*parentRenderer); |
182 | } |
183 | |
184 | RefPtr<FilterEffect> SVGFEImageElement::build(SVGFilterBuilder*, Filter& filter) const |
185 | { |
186 | if (m_cachedImage) |
187 | return FEImage::createWithImage(filter, m_cachedImage->imageForRenderer(renderer()), preserveAspectRatio()); |
188 | return FEImage::createWithIRIReference(filter, treeScope(), href(), preserveAspectRatio()); |
189 | } |
190 | |
191 | void SVGFEImageElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const |
192 | { |
193 | SVGFilterPrimitiveStandardAttributes::addSubresourceAttributeURLs(urls); |
194 | |
195 | addSubresourceURL(urls, document().completeURL(href())); |
196 | } |
197 | |
198 | } |
199 | |