Bug 1890793: Assert CallArgs::newTarget is not gray. r=spidermonkey-reviewers,sfink...
[gecko.git] / dom / svg / SVGFEImageElement.cpp
blobbc8fff7c21201109ef981b787b215738064e1233
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(UnbindContext& aContext) {
174 nsImageLoadingContent::UnbindFromTree();
175 SVGFEImageElementBase::UnbindFromTree(aContext);
178 void SVGFEImageElement::DestroyContent() {
179 nsImageLoadingContent::Destroy();
180 SVGFEImageElementBase::DestroyContent();
183 //----------------------------------------------------------------------
184 // nsINode methods
186 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEImageElement)
188 already_AddRefed<DOMSVGAnimatedString> SVGFEImageElement::Href() {
189 return mStringAttributes[HREF].IsExplicitlySet()
190 ? mStringAttributes[HREF].ToDOMAnimatedString(this)
191 : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
194 //----------------------------------------------------------------------
195 // nsImageLoadingContent methods:
197 CORSMode SVGFEImageElement::GetCORSMode() {
198 return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
201 //----------------------------------------------------------------------
202 // nsIDOMSVGFEImageElement methods
204 FilterPrimitiveDescription SVGFEImageElement::GetPrimitiveDescription(
205 SVGFilterInstance* aInstance, const IntRect& aFilterSubregion,
206 const nsTArray<bool>& aInputsAreTainted,
207 nsTArray<RefPtr<SourceSurface>>& aInputImages) {
208 nsIFrame* frame = GetPrimaryFrame();
209 if (!frame) {
210 return FilterPrimitiveDescription();
213 nsCOMPtr<imgIRequest> currentRequest;
214 GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
215 getter_AddRefs(currentRequest));
217 nsCOMPtr<imgIContainer> imageContainer;
218 if (currentRequest) {
219 currentRequest->GetImage(getter_AddRefs(imageContainer));
222 RefPtr<SourceSurface> image;
223 nsIntSize nativeSize;
224 if (imageContainer) {
225 if (NS_FAILED(imageContainer->GetWidth(&nativeSize.width))) {
226 nativeSize.width = kFallbackIntrinsicWidthInPixels;
228 if (NS_FAILED(imageContainer->GetHeight(&nativeSize.height))) {
229 nativeSize.height = kFallbackIntrinsicHeightInPixels;
231 uint32_t flags =
232 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
233 image = imageContainer->GetFrameAtSize(nativeSize,
234 imgIContainer::FRAME_CURRENT, flags);
237 if (!image) {
238 return FilterPrimitiveDescription();
241 Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(
242 aFilterSubregion.width, aFilterSubregion.height, 0, 0, nativeSize.width,
243 nativeSize.height, mPreserveAspectRatio);
244 Matrix TM = viewBoxTM;
245 TM.PostTranslate(aFilterSubregion.x, aFilterSubregion.y);
247 SamplingFilter samplingFilter =
248 nsLayoutUtils::GetSamplingFilterForFrame(frame);
250 ImageAttributes atts;
251 atts.mFilter = (uint32_t)samplingFilter;
252 atts.mTransform = TM;
254 // Append the image to aInputImages and store its index in the description.
255 size_t imageIndex = aInputImages.Length();
256 aInputImages.AppendElement(image);
257 atts.mInputIndex = (uint32_t)imageIndex;
258 return FilterPrimitiveDescription(AsVariant(std::move(atts)));
261 bool SVGFEImageElement::AttributeAffectsRendering(int32_t aNameSpaceID,
262 nsAtom* aAttribute) const {
263 // nsGkAtoms::href is deliberately omitted as the frame has special
264 // handling to load the image
265 return SVGFEImageElementBase::AttributeAffectsRendering(aNameSpaceID,
266 aAttribute) ||
267 (aNameSpaceID == kNameSpaceID_None &&
268 aAttribute == nsGkAtoms::preserveAspectRatio);
271 bool SVGFEImageElement::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
272 nsIPrincipal* aReferencePrincipal) {
273 nsresult rv;
274 nsCOMPtr<imgIRequest> currentRequest;
275 GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
276 getter_AddRefs(currentRequest));
278 if (!currentRequest) {
279 return false;
282 nsCOMPtr<nsIPrincipal> principal;
283 rv = currentRequest->GetImagePrincipal(getter_AddRefs(principal));
284 if (NS_FAILED(rv) || !principal) {
285 return true;
288 // If CORS was used to load the image, the page is allowed to read from it.
289 if (nsLayoutUtils::ImageRequestUsesCORS(currentRequest)) {
290 return false;
293 if (aReferencePrincipal->Subsumes(principal)) {
294 // The page is allowed to read from the image.
295 return false;
298 return true;
301 //----------------------------------------------------------------------
302 // SVGElement methods
304 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
305 SVGFEImageElement::PreserveAspectRatio() {
306 return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
309 SVGAnimatedPreserveAspectRatio*
310 SVGFEImageElement::GetAnimatedPreserveAspectRatio() {
311 return &mPreserveAspectRatio;
314 SVGElement::StringAttributesInfo SVGFEImageElement::GetStringInfo() {
315 return StringAttributesInfo(mStringAttributes, sStringInfo,
316 ArrayLength(sStringInfo));
319 //----------------------------------------------------------------------
320 // nsIImageLoadingContent methods
321 NS_IMETHODIMP_(void)
322 SVGFEImageElement::FrameCreated(nsIFrame* aFrame) {
323 nsImageLoadingContent::FrameCreated(aFrame);
325 uint64_t mode = aFrame->PresContext()->ImageAnimationMode();
326 if (mode == mImageAnimationMode) {
327 return;
330 mImageAnimationMode = mode;
332 if (mPendingRequest) {
333 nsCOMPtr<imgIContainer> container;
334 mPendingRequest->GetImage(getter_AddRefs(container));
335 if (container) {
336 container->SetAnimationMode(mode);
340 if (mCurrentRequest) {
341 nsCOMPtr<imgIContainer> container;
342 mCurrentRequest->GetImage(getter_AddRefs(container));
343 if (container) {
344 container->SetAnimationMode(mode);
349 //----------------------------------------------------------------------
350 // imgINotificationObserver methods
352 void SVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType,
353 const nsIntRect* aData) {
354 nsImageLoadingContent::Notify(aRequest, aType, aData);
356 if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
357 // Request a decode
358 nsCOMPtr<imgIContainer> container;
359 aRequest->GetImage(getter_AddRefs(container));
360 MOZ_ASSERT(container, "who sent the notification then?");
361 container->StartDecoding(imgIContainer::FLAG_NONE);
362 container->SetAnimationMode(mImageAnimationMode);
365 if (aType == imgINotificationObserver::LOAD_COMPLETE ||
366 aType == imgINotificationObserver::FRAME_UPDATE ||
367 aType == imgINotificationObserver::SIZE_AVAILABLE) {
368 if (auto* filter = SVGFilterElement::FromNodeOrNull(GetParent())) {
369 SVGObserverUtils::InvalidateDirectRenderingObservers(filter);
374 void SVGFEImageElement::DidAnimateString(PRUint8 aAttrEnum) {
375 auto info = GetStringInfo();
376 if ((info.mInfos[aAttrEnum].mNamespaceID == kNameSpaceID_None ||
377 info.mInfos[aAttrEnum].mNamespaceID == kNameSpaceID_XLink) &&
378 info.mInfos[aAttrEnum].mName == nsGkAtoms::href) {
379 bool hrefIsSet =
380 mStringAttributes[SVGFEImageElement::HREF].IsExplicitlySet() ||
381 mStringAttributes[SVGFEImageElement::XLINK_HREF].IsExplicitlySet();
382 if (hrefIsSet) {
383 LoadSVGImage(true, true);
384 } else {
385 CancelImageRequests(true);
388 SVGFEImageElementBase::DidAnimateString(aAttrEnum);
391 } // namespace mozilla::dom