Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / svg / SVGFEImageElement.cpp
blob664e4d42acd74b853c98190a3623f4fdff55a605
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 (aNamespaceID == kNameSpaceID_XLink &&
125 mStringAttributes[HREF].IsExplicitlySet()) {
126 // href overrides xlink:href
127 return;
129 if (aValue || (aNamespaceID == kNameSpaceID_None &&
130 mStringAttributes[XLINK_HREF].IsExplicitlySet())) {
131 if (ShouldLoadImage()) {
132 LoadSVGImage(true, aNotify);
134 } else {
135 CancelImageRequests(aNotify);
137 } else if (aNamespaceID == kNameSpaceID_None &&
138 aName == nsGkAtoms::crossorigin) {
139 if (aNotify && GetCORSMode() != AttrValueToCORSMode(aOldValue) &&
140 ShouldLoadImage()) {
141 ForceReload(aNotify, IgnoreErrors());
145 return SVGFEImageElementBase::AfterSetAttr(
146 aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
149 void SVGFEImageElement::MaybeLoadSVGImage() {
150 if ((mStringAttributes[HREF].IsExplicitlySet() ||
151 mStringAttributes[XLINK_HREF].IsExplicitlySet()) &&
152 (NS_FAILED(LoadSVGImage(false, true)) || !LoadingEnabled())) {
153 CancelImageRequests(true);
157 nsresult SVGFEImageElement::BindToTree(BindContext& aContext,
158 nsINode& aParent) {
159 nsresult rv = SVGFEImageElementBase::BindToTree(aContext, aParent);
160 NS_ENSURE_SUCCESS(rv, rv);
162 nsImageLoadingContent::BindToTree(aContext, aParent);
164 if ((mStringAttributes[HREF].IsExplicitlySet() ||
165 mStringAttributes[XLINK_HREF].IsExplicitlySet()) &&
166 ShouldLoadImage()) {
167 nsContentUtils::AddScriptRunner(
168 NewRunnableMethod("dom::SVGFEImageElement::MaybeLoadSVGImage", this,
169 &SVGFEImageElement::MaybeLoadSVGImage));
172 if (aContext.InComposedDoc()) {
173 aContext.OwnerDoc().SetUseCounter(eUseCounter_custom_feImage);
176 return rv;
179 void SVGFEImageElement::UnbindFromTree(UnbindContext& aContext) {
180 nsImageLoadingContent::UnbindFromTree();
181 SVGFEImageElementBase::UnbindFromTree(aContext);
184 void SVGFEImageElement::DestroyContent() {
185 nsImageLoadingContent::Destroy();
186 SVGFEImageElementBase::DestroyContent();
189 //----------------------------------------------------------------------
190 // nsINode methods
192 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEImageElement)
194 already_AddRefed<DOMSVGAnimatedString> SVGFEImageElement::Href() {
195 return mStringAttributes[HREF].IsExplicitlySet()
196 ? mStringAttributes[HREF].ToDOMAnimatedString(this)
197 : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
200 //----------------------------------------------------------------------
201 // nsImageLoadingContent methods:
203 CORSMode SVGFEImageElement::GetCORSMode() {
204 return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
207 //----------------------------------------------------------------------
208 // nsIDOMSVGFEImageElement methods
210 FilterPrimitiveDescription SVGFEImageElement::GetPrimitiveDescription(
211 SVGFilterInstance* aInstance, const IntRect& aFilterSubregion,
212 const nsTArray<bool>& aInputsAreTainted,
213 nsTArray<RefPtr<SourceSurface>>& aInputImages) {
214 nsIFrame* frame = GetPrimaryFrame();
215 if (!frame) {
216 return FilterPrimitiveDescription();
219 nsCOMPtr<imgIRequest> currentRequest;
220 GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
221 getter_AddRefs(currentRequest));
223 nsCOMPtr<imgIContainer> imageContainer;
224 if (currentRequest) {
225 currentRequest->GetImage(getter_AddRefs(imageContainer));
228 RefPtr<SourceSurface> image;
229 nsIntSize nativeSize;
230 if (imageContainer) {
231 if (NS_FAILED(imageContainer->GetWidth(&nativeSize.width))) {
232 nativeSize.width = kFallbackIntrinsicWidthInPixels;
234 if (NS_FAILED(imageContainer->GetHeight(&nativeSize.height))) {
235 nativeSize.height = kFallbackIntrinsicHeightInPixels;
237 uint32_t flags =
238 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
239 image = imageContainer->GetFrameAtSize(nativeSize,
240 imgIContainer::FRAME_CURRENT, flags);
243 if (!image) {
244 return FilterPrimitiveDescription();
247 Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(
248 aFilterSubregion.width, aFilterSubregion.height, 0, 0, nativeSize.width,
249 nativeSize.height, mPreserveAspectRatio);
250 Matrix TM = viewBoxTM;
251 TM.PostTranslate(aFilterSubregion.x, aFilterSubregion.y);
253 SamplingFilter samplingFilter =
254 nsLayoutUtils::GetSamplingFilterForFrame(frame);
256 ImageAttributes atts;
257 atts.mFilter = (uint32_t)samplingFilter;
258 atts.mTransform = TM;
260 // Append the image to aInputImages and store its index in the description.
261 size_t imageIndex = aInputImages.Length();
262 aInputImages.AppendElement(image);
263 atts.mInputIndex = (uint32_t)imageIndex;
264 return FilterPrimitiveDescription(AsVariant(std::move(atts)));
267 bool SVGFEImageElement::AttributeAffectsRendering(int32_t aNameSpaceID,
268 nsAtom* aAttribute) const {
269 // nsGkAtoms::href is deliberately omitted as the frame has special
270 // handling to load the image
271 return SVGFEImageElementBase::AttributeAffectsRendering(aNameSpaceID,
272 aAttribute) ||
273 (aNameSpaceID == kNameSpaceID_None &&
274 aAttribute == nsGkAtoms::preserveAspectRatio);
277 bool SVGFEImageElement::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
278 nsIPrincipal* aReferencePrincipal) {
279 nsresult rv;
280 nsCOMPtr<imgIRequest> currentRequest;
281 GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
282 getter_AddRefs(currentRequest));
284 if (!currentRequest) {
285 return false;
288 nsCOMPtr<nsIPrincipal> principal;
289 rv = currentRequest->GetImagePrincipal(getter_AddRefs(principal));
290 if (NS_FAILED(rv) || !principal) {
291 return true;
294 // If CORS was used to load the image, the page is allowed to read from it.
295 if (nsLayoutUtils::ImageRequestUsesCORS(currentRequest)) {
296 return false;
299 if (aReferencePrincipal->Subsumes(principal)) {
300 // The page is allowed to read from the image.
301 return false;
304 return true;
307 //----------------------------------------------------------------------
308 // SVGElement methods
310 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
311 SVGFEImageElement::PreserveAspectRatio() {
312 return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
315 SVGAnimatedPreserveAspectRatio*
316 SVGFEImageElement::GetAnimatedPreserveAspectRatio() {
317 return &mPreserveAspectRatio;
320 SVGElement::StringAttributesInfo SVGFEImageElement::GetStringInfo() {
321 return StringAttributesInfo(mStringAttributes, sStringInfo,
322 std::size(sStringInfo));
325 //----------------------------------------------------------------------
326 // nsIImageLoadingContent methods
327 NS_IMETHODIMP_(void)
328 SVGFEImageElement::FrameCreated(nsIFrame* aFrame) {
329 nsImageLoadingContent::FrameCreated(aFrame);
331 uint64_t mode = aFrame->PresContext()->ImageAnimationMode();
332 if (mode == mImageAnimationMode) {
333 return;
336 mImageAnimationMode = mode;
338 if (mPendingRequest) {
339 nsCOMPtr<imgIContainer> container;
340 mPendingRequest->GetImage(getter_AddRefs(container));
341 if (container) {
342 container->SetAnimationMode(mode);
346 if (mCurrentRequest) {
347 nsCOMPtr<imgIContainer> container;
348 mCurrentRequest->GetImage(getter_AddRefs(container));
349 if (container) {
350 container->SetAnimationMode(mode);
355 //----------------------------------------------------------------------
356 // imgINotificationObserver methods
358 void SVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType,
359 const nsIntRect* aData) {
360 nsImageLoadingContent::Notify(aRequest, aType, aData);
362 if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
363 // Request a decode
364 nsCOMPtr<imgIContainer> container;
365 aRequest->GetImage(getter_AddRefs(container));
366 MOZ_ASSERT(container, "who sent the notification then?");
367 container->StartDecoding(imgIContainer::FLAG_NONE);
368 container->SetAnimationMode(mImageAnimationMode);
371 if (aType == imgINotificationObserver::LOAD_COMPLETE ||
372 aType == imgINotificationObserver::FRAME_UPDATE ||
373 aType == imgINotificationObserver::SIZE_AVAILABLE) {
374 if (auto* filter = SVGFilterElement::FromNodeOrNull(GetParent())) {
375 SVGObserverUtils::InvalidateDirectRenderingObservers(filter);
380 void SVGFEImageElement::DidAnimateAttribute(int32_t aNameSpaceID,
381 nsAtom* aAttribute) {
382 if ((aNameSpaceID == kNameSpaceID_None ||
383 aNameSpaceID == kNameSpaceID_XLink) &&
384 aAttribute == nsGkAtoms::href) {
385 bool hrefIsSet =
386 mStringAttributes[SVGFEImageElement::HREF].IsExplicitlySet() ||
387 mStringAttributes[SVGFEImageElement::XLINK_HREF].IsExplicitlySet();
388 if (hrefIsSet) {
389 LoadSVGImage(true, true);
390 } else {
391 CancelImageRequests(true);
394 SVGFEImageElementBase::DidAnimateAttribute(aNameSpaceID, aAttribute);
397 } // namespace mozilla::dom