Bug 1834993 - Fix nursery allocatable flag for objects with foreground finalizers...
[gecko.git] / dom / svg / SVGFEImageElement.cpp
blob733c66835f10f47992b1e359b592583343bc41af
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/SVGFEImageElement.h"
9 #include "mozilla/SVGObserverUtils.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/BindContext.h"
12 #include "mozilla/dom/SVGFEImageElementBinding.h"
13 #include "mozilla/dom/SVGFilterElement.h"
14 #include "mozilla/dom/UserActivation.h"
15 #include "mozilla/gfx/2D.h"
16 #include "mozilla/RefPtr.h"
17 #include "nsContentUtils.h"
18 #include "nsLayoutUtils.h"
19 #include "nsNetUtil.h"
20 #include "imgIContainer.h"
21 #include "gfx2DGlue.h"
23 NS_IMPL_NS_NEW_SVG_ELEMENT(FEImage)
25 using namespace mozilla::gfx;
27 namespace mozilla::dom {
29 JSObject* SVGFEImageElement::WrapNode(JSContext* aCx,
30 JS::Handle<JSObject*> aGivenProto) {
31 return SVGFEImageElement_Binding::Wrap(aCx, this, aGivenProto);
34 SVGElement::StringInfo SVGFEImageElement::sStringInfo[3] = {
35 {nsGkAtoms::result, kNameSpaceID_None, true},
36 {nsGkAtoms::href, kNameSpaceID_None, true},
37 {nsGkAtoms::href, kNameSpaceID_XLink, true}};
39 //----------------------------------------------------------------------
40 // nsISupports methods
42 NS_IMPL_ISUPPORTS_INHERITED(SVGFEImageElement, SVGFEImageElementBase,
43 imgINotificationObserver, nsIImageLoadingContent)
45 //----------------------------------------------------------------------
46 // Implementation
48 SVGFEImageElement::SVGFEImageElement(
49 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
50 : SVGFEImageElementBase(std::move(aNodeInfo)), mImageAnimationMode(0) {
51 // We start out broken
52 AddStatesSilently(ElementState::BROKEN);
55 SVGFEImageElement::~SVGFEImageElement() { nsImageLoadingContent::Destroy(); }
57 //----------------------------------------------------------------------
59 nsresult SVGFEImageElement::LoadSVGImage(bool aForce, bool aNotify) {
60 // resolve href attribute
61 nsIURI* baseURI = GetBaseURI();
63 nsAutoString href;
64 if (mStringAttributes[HREF].IsExplicitlySet()) {
65 mStringAttributes[HREF].GetAnimValue(href, this);
66 } else {
67 mStringAttributes[XLINK_HREF].GetAnimValue(href, this);
69 href.Trim(" \t\n\r");
71 if (baseURI && !href.IsEmpty()) NS_MakeAbsoluteURI(href, href, baseURI);
73 // Make sure we don't get in a recursive death-spiral
74 Document* doc = OwnerDoc();
75 nsCOMPtr<nsIURI> hrefAsURI;
76 if (NS_SUCCEEDED(StringToURI(href, doc, getter_AddRefs(hrefAsURI)))) {
77 bool isEqual;
78 if (NS_SUCCEEDED(hrefAsURI->Equals(baseURI, &isEqual)) && isEqual) {
79 // Image URI matches our URI exactly! Bail out.
80 return NS_OK;
84 // Mark channel as urgent-start before load image if the image load is
85 // initaiated by a user interaction.
86 mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput();
87 return LoadImage(href, aForce, aNotify, eImageLoadType_Normal);
90 bool SVGFEImageElement::ShouldLoadImage() const {
91 return LoadingEnabled() && OwnerDoc()->ShouldLoadImages();
94 //----------------------------------------------------------------------
95 // EventTarget methods:
97 void SVGFEImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
98 nsImageLoadingContent::AsyncEventRunning(aEvent);
101 //----------------------------------------------------------------------
102 // nsIContent methods:
104 bool SVGFEImageElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
105 const nsAString& aValue,
106 nsIPrincipal* aMaybeScriptedPrincipal,
107 nsAttrValue& aResult) {
108 if (aNamespaceID == kNameSpaceID_None &&
109 aAttribute == nsGkAtoms::crossorigin) {
110 ParseCORSValue(aValue, aResult);
111 return true;
113 return SVGFEImageElementBase::ParseAttribute(
114 aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult);
117 void SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
118 const nsAttrValue* aValue,
119 const nsAttrValue* aOldValue,
120 nsIPrincipal* aSubjectPrincipal,
121 bool aNotify) {
122 if (aName == nsGkAtoms::href && (aNamespaceID == kNameSpaceID_XLink ||
123 aNamespaceID == kNameSpaceID_None)) {
124 if (aValue) {
125 if (ShouldLoadImage()) {
126 LoadSVGImage(true, aNotify);
128 } else {
129 CancelImageRequests(aNotify);
131 } else if (aNamespaceID == kNameSpaceID_None &&
132 aName == nsGkAtoms::crossorigin) {
133 if (aNotify && GetCORSMode() != AttrValueToCORSMode(aOldValue) &&
134 ShouldLoadImage()) {
135 ForceReload(aNotify, IgnoreErrors());
139 return SVGFEImageElementBase::AfterSetAttr(
140 aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
143 void SVGFEImageElement::MaybeLoadSVGImage() {
144 if ((mStringAttributes[HREF].IsExplicitlySet() ||
145 mStringAttributes[XLINK_HREF].IsExplicitlySet()) &&
146 (NS_FAILED(LoadSVGImage(false, true)) || !LoadingEnabled())) {
147 CancelImageRequests(true);
151 nsresult SVGFEImageElement::BindToTree(BindContext& aContext,
152 nsINode& aParent) {
153 nsresult rv = SVGFEImageElementBase::BindToTree(aContext, aParent);
154 NS_ENSURE_SUCCESS(rv, rv);
156 nsImageLoadingContent::BindToTree(aContext, aParent);
158 if ((mStringAttributes[HREF].IsExplicitlySet() ||
159 mStringAttributes[XLINK_HREF].IsExplicitlySet()) &&
160 ShouldLoadImage()) {
161 nsContentUtils::AddScriptRunner(
162 NewRunnableMethod("dom::SVGFEImageElement::MaybeLoadSVGImage", this,
163 &SVGFEImageElement::MaybeLoadSVGImage));
166 if (aContext.InComposedDoc()) {
167 aContext.OwnerDoc().SetUseCounter(eUseCounter_custom_feImage);
170 return rv;
173 void SVGFEImageElement::UnbindFromTree(bool aNullParent) {
174 nsImageLoadingContent::UnbindFromTree(aNullParent);
175 SVGFEImageElementBase::UnbindFromTree(aNullParent);
178 ElementState SVGFEImageElement::IntrinsicState() const {
179 return SVGFEImageElementBase::IntrinsicState() |
180 nsImageLoadingContent::ImageState();
183 void SVGFEImageElement::DestroyContent() {
184 nsImageLoadingContent::Destroy();
185 SVGFEImageElementBase::DestroyContent();
188 //----------------------------------------------------------------------
189 // nsINode methods
191 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEImageElement)
193 already_AddRefed<DOMSVGAnimatedString> SVGFEImageElement::Href() {
194 return mStringAttributes[HREF].IsExplicitlySet()
195 ? mStringAttributes[HREF].ToDOMAnimatedString(this)
196 : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
199 //----------------------------------------------------------------------
200 // nsImageLoadingContent methods:
202 CORSMode SVGFEImageElement::GetCORSMode() {
203 return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
206 //----------------------------------------------------------------------
207 // nsIDOMSVGFEImageElement methods
209 FilterPrimitiveDescription SVGFEImageElement::GetPrimitiveDescription(
210 SVGFilterInstance* aInstance, const IntRect& aFilterSubregion,
211 const nsTArray<bool>& aInputsAreTainted,
212 nsTArray<RefPtr<SourceSurface>>& aInputImages) {
213 nsIFrame* frame = GetPrimaryFrame();
214 if (!frame) {
215 return FilterPrimitiveDescription();
218 nsCOMPtr<imgIRequest> currentRequest;
219 GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
220 getter_AddRefs(currentRequest));
222 nsCOMPtr<imgIContainer> imageContainer;
223 if (currentRequest) {
224 currentRequest->GetImage(getter_AddRefs(imageContainer));
227 RefPtr<SourceSurface> image;
228 if (imageContainer) {
229 uint32_t flags =
230 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
231 image = imageContainer->GetFrame(imgIContainer::FRAME_CURRENT, flags);
234 if (!image) {
235 return FilterPrimitiveDescription();
238 IntSize nativeSize;
239 imageContainer->GetWidth(&nativeSize.width);
240 imageContainer->GetHeight(&nativeSize.height);
242 Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(
243 aFilterSubregion.width, aFilterSubregion.height, 0, 0, nativeSize.width,
244 nativeSize.height, mPreserveAspectRatio);
245 Matrix TM = viewBoxTM;
246 TM.PostTranslate(aFilterSubregion.x, aFilterSubregion.y);
248 SamplingFilter samplingFilter =
249 nsLayoutUtils::GetSamplingFilterForFrame(frame);
251 ImageAttributes atts;
252 atts.mFilter = (uint32_t)samplingFilter;
253 atts.mTransform = TM;
255 // Append the image to aInputImages and store its index in the description.
256 size_t imageIndex = aInputImages.Length();
257 aInputImages.AppendElement(image);
258 atts.mInputIndex = (uint32_t)imageIndex;
259 return FilterPrimitiveDescription(AsVariant(std::move(atts)));
262 bool SVGFEImageElement::AttributeAffectsRendering(int32_t aNameSpaceID,
263 nsAtom* aAttribute) const {
264 // nsGkAtoms::href is deliberately omitted as the frame has special
265 // handling to load the image
266 return SVGFEImageElementBase::AttributeAffectsRendering(aNameSpaceID,
267 aAttribute) ||
268 (aNameSpaceID == kNameSpaceID_None &&
269 aAttribute == nsGkAtoms::preserveAspectRatio);
272 bool SVGFEImageElement::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
273 nsIPrincipal* aReferencePrincipal) {
274 nsresult rv;
275 nsCOMPtr<imgIRequest> currentRequest;
276 GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
277 getter_AddRefs(currentRequest));
279 if (!currentRequest) {
280 return false;
283 nsCOMPtr<nsIPrincipal> principal;
284 rv = currentRequest->GetImagePrincipal(getter_AddRefs(principal));
285 if (NS_FAILED(rv) || !principal) {
286 return true;
289 // If CORS was used to load the image, the page is allowed to read from it.
290 if (nsLayoutUtils::ImageRequestUsesCORS(currentRequest)) {
291 return false;
294 if (aReferencePrincipal->Subsumes(principal)) {
295 // The page is allowed to read from the image.
296 return false;
299 return true;
302 //----------------------------------------------------------------------
303 // SVGElement methods
305 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
306 SVGFEImageElement::PreserveAspectRatio() {
307 return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
310 SVGAnimatedPreserveAspectRatio*
311 SVGFEImageElement::GetAnimatedPreserveAspectRatio() {
312 return &mPreserveAspectRatio;
315 SVGElement::StringAttributesInfo SVGFEImageElement::GetStringInfo() {
316 return StringAttributesInfo(mStringAttributes, sStringInfo,
317 ArrayLength(sStringInfo));
320 //----------------------------------------------------------------------
321 // nsIImageLoadingContent methods
322 NS_IMETHODIMP_(void)
323 SVGFEImageElement::FrameCreated(nsIFrame* aFrame) {
324 nsImageLoadingContent::FrameCreated(aFrame);
326 uint64_t mode = aFrame->PresContext()->ImageAnimationMode();
327 if (mode == mImageAnimationMode) {
328 return;
331 mImageAnimationMode = mode;
333 if (mPendingRequest) {
334 nsCOMPtr<imgIContainer> container;
335 mPendingRequest->GetImage(getter_AddRefs(container));
336 if (container) {
337 container->SetAnimationMode(mode);
341 if (mCurrentRequest) {
342 nsCOMPtr<imgIContainer> container;
343 mCurrentRequest->GetImage(getter_AddRefs(container));
344 if (container) {
345 container->SetAnimationMode(mode);
350 //----------------------------------------------------------------------
351 // imgINotificationObserver methods
353 void SVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType,
354 const nsIntRect* aData) {
355 nsImageLoadingContent::Notify(aRequest, aType, aData);
357 if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
358 // Request a decode
359 nsCOMPtr<imgIContainer> container;
360 aRequest->GetImage(getter_AddRefs(container));
361 MOZ_ASSERT(container, "who sent the notification then?");
362 container->StartDecoding(imgIContainer::FLAG_NONE);
363 container->SetAnimationMode(mImageAnimationMode);
366 if (aType == imgINotificationObserver::LOAD_COMPLETE ||
367 aType == imgINotificationObserver::FRAME_UPDATE ||
368 aType == imgINotificationObserver::SIZE_AVAILABLE) {
369 if (auto* filter = SVGFilterElement::FromNodeOrNull(GetParent())) {
370 SVGObserverUtils::InvalidateDirectRenderingObservers(filter);
375 } // namespace mozilla::dom