Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / html / HTMLImageElement.h
blobbf41c68d40e9286de09fe70681c7058a70298ecd
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 #ifndef mozilla_dom_HTMLImageElement_h
8 #define mozilla_dom_HTMLImageElement_h
10 #include "mozilla/Attributes.h"
11 #include "nsGenericHTMLElement.h"
12 #include "nsImageLoadingContent.h"
13 #include "Units.h"
14 #include "nsCycleCollectionParticipant.h"
16 namespace mozilla {
17 class EventChainPreVisitor;
18 namespace dom {
20 class ImageLoadTask;
22 class ResponsiveImageSelector;
23 class HTMLImageElement final : public nsGenericHTMLElement,
24 public nsImageLoadingContent {
25 friend class HTMLSourceElement;
26 friend class HTMLPictureElement;
27 friend class ImageLoadTask;
29 public:
30 explicit HTMLImageElement(
31 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
33 static already_AddRefed<HTMLImageElement> Image(
34 const GlobalObject& aGlobal, const Optional<uint32_t>& aWidth,
35 const Optional<uint32_t>& aHeight, ErrorResult& aError);
37 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLImageElement,
38 nsGenericHTMLElement)
40 // nsISupports
41 NS_DECL_ISUPPORTS_INHERITED
43 bool Draggable() const override;
45 ResponsiveImageSelector* GetResponsiveImageSelector() {
46 return mResponsiveSelector.get();
49 // Element
50 bool IsInteractiveHTMLContent() const override;
52 // EventTarget
53 void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
55 NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLImageElement, img)
57 // override from nsImageLoadingContent
58 CORSMode GetCORSMode() override;
60 // nsIContent
61 bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
62 const nsAString& aValue,
63 nsIPrincipal* aMaybeScriptedPrincipal,
64 nsAttrValue& aResult) override;
65 nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
66 int32_t aModType) const override;
67 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
68 nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
70 void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
71 nsINode* GetScopeChainParent() const override;
73 bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
74 int32_t* aTabIndex) override;
76 nsresult BindToTree(BindContext&, nsINode& aParent) override;
77 void UnbindFromTree(UnbindContext&) override;
79 nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
81 void NodeInfoChanged(Document* aOldDoc) override;
83 nsresult CopyInnerTo(HTMLImageElement* aDest);
85 void MaybeLoadImage(bool aAlwaysForceLoad);
87 bool IsMap() { return GetBoolAttr(nsGkAtoms::ismap); }
88 void SetIsMap(bool aIsMap, ErrorResult& aError) {
89 SetHTMLBoolAttr(nsGkAtoms::ismap, aIsMap, aError);
91 MOZ_CAN_RUN_SCRIPT uint32_t Width();
92 void SetWidth(uint32_t aWidth, ErrorResult& aError) {
93 SetUnsignedIntAttr(nsGkAtoms::width, aWidth, 0, aError);
95 MOZ_CAN_RUN_SCRIPT uint32_t Height();
96 void SetHeight(uint32_t aHeight, ErrorResult& aError) {
97 SetUnsignedIntAttr(nsGkAtoms::height, aHeight, 0, aError);
100 nsIntSize NaturalSize();
101 uint32_t NaturalHeight() { return NaturalSize().height; }
102 uint32_t NaturalWidth() { return NaturalSize().width; }
104 bool Complete();
105 uint32_t Hspace() {
106 return GetDimensionAttrAsUnsignedInt(nsGkAtoms::hspace, 0);
108 void SetHspace(uint32_t aHspace, ErrorResult& aError) {
109 SetUnsignedIntAttr(nsGkAtoms::hspace, aHspace, 0, aError);
111 uint32_t Vspace() {
112 return GetDimensionAttrAsUnsignedInt(nsGkAtoms::vspace, 0);
114 void SetVspace(uint32_t aVspace, ErrorResult& aError) {
115 SetUnsignedIntAttr(nsGkAtoms::vspace, aVspace, 0, aError);
118 void GetAlt(nsAString& aAlt) { GetHTMLAttr(nsGkAtoms::alt, aAlt); }
119 void SetAlt(const nsAString& aAlt, ErrorResult& aError) {
120 SetHTMLAttr(nsGkAtoms::alt, aAlt, aError);
122 void GetSrc(nsAString& aSrc) { GetURIAttr(nsGkAtoms::src, nullptr, aSrc); }
123 void SetSrc(const nsAString& aSrc, ErrorResult& aError) {
124 SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
126 void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal,
127 ErrorResult& aError) {
128 SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
130 void GetSrcset(nsAString& aSrcset) {
131 GetHTMLAttr(nsGkAtoms::srcset, aSrcset);
133 void SetSrcset(const nsAString& aSrcset, nsIPrincipal* aTriggeringPrincipal,
134 ErrorResult& aError) {
135 SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, aError);
137 void GetCrossOrigin(nsAString& aResult) {
138 // Null for both missing and invalid defaults is ok, since we
139 // always parse to an enum value, so we don't need an invalid
140 // default, and we _want_ the missing default to be null.
141 GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
143 void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError) {
144 SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
146 void GetUseMap(nsAString& aUseMap) {
147 GetHTMLAttr(nsGkAtoms::usemap, aUseMap);
149 void SetUseMap(const nsAString& aUseMap, ErrorResult& aError) {
150 SetHTMLAttr(nsGkAtoms::usemap, aUseMap, aError);
152 void GetName(nsAString& aName) { GetHTMLAttr(nsGkAtoms::name, aName); }
153 void SetName(const nsAString& aName, ErrorResult& aError) {
154 SetHTMLAttr(nsGkAtoms::name, aName, aError);
156 void GetAlign(nsAString& aAlign) { GetHTMLAttr(nsGkAtoms::align, aAlign); }
157 void SetAlign(const nsAString& aAlign, ErrorResult& aError) {
158 SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
160 void GetLongDesc(nsAString& aLongDesc) {
161 GetURIAttr(nsGkAtoms::longdesc, nullptr, aLongDesc);
163 void SetLongDesc(const nsAString& aLongDesc, ErrorResult& aError) {
164 SetHTMLAttr(nsGkAtoms::longdesc, aLongDesc, aError);
166 void GetSizes(nsAString& aSizes) { GetHTMLAttr(nsGkAtoms::sizes, aSizes); }
167 void SetSizes(const nsAString& aSizes, ErrorResult& aError) {
168 SetHTMLAttr(nsGkAtoms::sizes, aSizes, aError);
170 void GetCurrentSrc(nsAString& aValue);
171 void GetBorder(nsAString& aBorder) {
172 GetHTMLAttr(nsGkAtoms::border, aBorder);
174 void SetBorder(const nsAString& aBorder, ErrorResult& aError) {
175 SetHTMLAttr(nsGkAtoms::border, aBorder, aError);
177 void SetReferrerPolicy(const nsAString& aReferrer, ErrorResult& aError) {
178 SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrer, aError);
180 void GetReferrerPolicy(nsAString& aReferrer) {
181 GetEnumAttr(nsGkAtoms::referrerpolicy, "", aReferrer);
183 void SetDecoding(const nsAString& aDecoding, ErrorResult& aError) {
184 SetHTMLAttr(nsGkAtoms::decoding, aDecoding, aError);
186 void GetDecoding(nsAString& aValue);
188 void SetLoading(const nsAString& aLoading, ErrorResult& aError) {
189 SetHTMLAttr(nsGkAtoms::loading, aLoading, aError);
192 bool IsAwaitingLoadOrLazyLoading() const {
193 return mLazyLoading || mPendingImageLoadTask;
196 bool IsLazyLoading() const { return mLazyLoading; }
198 already_AddRefed<Promise> Decode(ErrorResult& aRv);
200 MOZ_CAN_RUN_SCRIPT int32_t X();
201 MOZ_CAN_RUN_SCRIPT int32_t Y();
202 void GetLowsrc(nsAString& aLowsrc) {
203 GetURIAttr(nsGkAtoms::lowsrc, nullptr, aLowsrc);
205 void SetLowsrc(const nsAString& aLowsrc, ErrorResult& aError) {
206 SetHTMLAttr(nsGkAtoms::lowsrc, aLowsrc, aError);
209 #ifdef DEBUG
210 HTMLFormElement* GetForm() const;
211 #endif
212 void SetForm(HTMLFormElement* aForm);
213 void ClearForm(bool aRemoveFromForm);
215 void DestroyContent() override;
217 void MediaFeatureValuesChanged();
220 * Given a hypothetical <img> or <source> tag with the given parameters,
221 * return what URI we would attempt to use, if any. Used by the preloader to
222 * resolve sources prior to DOM creation.
224 * @param aDocument The document this image would be for, for referencing
225 * viewport width and DPI/zoom
226 * @param aIsSourceTag If these parameters are for a <source> tag (as in a
227 * <picture>) rather than an <img> tag. Note that some attrs are unused
228 * when this is true an vice versa
229 * @param aSrcAttr [ignored if aIsSourceTag] The src attr for this image.
230 * @param aSrcsetAttr The srcset attr for this image/source
231 * @param aSizesAttr The sizes attr for this image/source
232 * @param aTypeAttr [ignored if !aIsSourceTag] The type attr for this source.
233 * Should be a void string to differentiate no type attribute
234 * from an empty one.
235 * @param aMediaAttr [ignored if !aIsSourceTag] The media attr for this
236 * source. Should be a void string to differentiate no
237 * media attribute from an empty one.
238 * @param aResult A reference to store the resulting URL spec in if we
239 * selected a source. This value is not guaranteed to parse to
240 * a valid URL, merely the URL that the tag would attempt to
241 * resolve and load (which may be the empty string). This
242 * parameter is not modified if return value is false.
243 * @return True if we were able to select a final source, false if further
244 * sources would be considered. It follows that this always returns
245 * true if !aIsSourceTag.
247 * Note that the return value may be true with an empty string as the result,
248 * which implies that the parameters provided describe a tag that would select
249 * no source. This is distinct from a return of false which implies that
250 * further <source> or <img> tags would be considered.
252 static bool SelectSourceForTagWithAttrs(
253 Document* aDocument, bool aIsSourceTag, const nsAString& aSrcAttr,
254 const nsAString& aSrcsetAttr, const nsAString& aSizesAttr,
255 const nsAString& aTypeAttr, const nsAString& aMediaAttr,
256 nsAString& aResult);
258 enum class FromIntersectionObserver : bool { No, Yes };
259 enum class StartLoading : bool { No, Yes };
260 void StopLazyLoading(StartLoading);
262 // This is used when restyling, for retrieving the extra style from the source
263 // element.
264 const StyleLockedDeclarationBlock* GetMappedAttributesFromSource() const;
266 FetchPriority GetFetchPriorityForImage() const override;
268 protected:
269 virtual ~HTMLImageElement();
271 // Update the responsive source synchronously and queues a task to run
272 // LoadSelectedImage pending stable state.
274 // Pending Bug 1076583 this is only used by the responsive image
275 // algorithm (InResponsiveMode()) -- synchronous actions when just
276 // using img.src will bypass this, and update source and kick off
277 // image load synchronously.
278 void UpdateSourceSyncAndQueueImageTask(
279 bool aAlwaysLoad, const HTMLSourceElement* aSkippedSource = nullptr);
281 // True if we have a srcset attribute or a <picture> parent, regardless of if
282 // any valid responsive sources were parsed from either.
283 bool HaveSrcsetOrInPicture();
285 // True if we are using the newer image loading algorithm. This will be the
286 // only mode after Bug 1076583
287 bool InResponsiveMode();
289 // True if the given URL equals the last URL that was loaded by this element.
290 bool SelectedSourceMatchesLast(nsIURI* aSelectedSource);
292 // Load the current mResponsiveSelector (responsive mode) or src attr image.
293 // Note: This doesn't run the full selection for the responsive selector.
294 nsresult LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad);
296 // True if this string represents a type we would support on <source type>
297 static bool SupportedPictureSourceType(const nsAString& aType);
299 // Update/create/destroy mResponsiveSelector
300 void PictureSourceSrcsetChanged(nsIContent* aSourceNode,
301 const nsAString& aNewValue, bool aNotify);
302 void PictureSourceSizesChanged(nsIContent* aSourceNode,
303 const nsAString& aNewValue, bool aNotify);
304 // As we re-run the source selection on these mutations regardless,
305 // we don't actually care which changed or to what
306 void PictureSourceMediaOrTypeChanged(nsIContent* aSourceNode, bool aNotify);
308 // This is called when we update "width" or "height" attribute of source
309 // element.
310 void PictureSourceDimensionChanged(HTMLSourceElement* aSourceNode,
311 bool aNotify);
313 void PictureSourceAdded(HTMLSourceElement* aSourceNode = nullptr);
314 // This should be called prior to the unbind, such that nextsibling works
315 void PictureSourceRemoved(HTMLSourceElement* aSourceNode = nullptr);
317 // Re-evaluates all source nodes (picture <source>,<img>) and finds
318 // the best source set for mResponsiveSelector. If a better source
319 // is found, creates a new selector and feeds the source to it. If
320 // the current ResponsiveSelector is not changed, runs
321 // SelectImage(true) to re-evaluate its candidates.
323 // Because keeping the existing selector is the common case (and we
324 // often do no-op reselections), this does not re-parse values for
325 // the existing mResponsiveSelector, meaning you need to update its
326 // parameters as appropriate before calling (or null it out to force
327 // recreation)
329 // if |aSkippedSource| is non-null, we will skip it when running the
330 // algorithm. This is used when we need to update the source when we are
331 // removing the source element.
333 // Returns true if the source has changed, and false otherwise.
334 bool UpdateResponsiveSource(
335 const HTMLSourceElement* aSkippedSource = nullptr);
337 // Given a <source> node that is a previous sibling *or* ourselves, try to
338 // create a ResponsiveSelector.
340 // If the node's srcset/sizes make for an invalid selector, returns
341 // nullptr. This does not guarantee the resulting selector matches an image,
342 // only that it is valid.
343 already_AddRefed<ResponsiveImageSelector> TryCreateResponsiveSelector(
344 Element* aSourceElement);
346 MOZ_CAN_RUN_SCRIPT CSSIntPoint GetXY();
347 JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
348 void UpdateFormOwner();
350 void BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
351 const nsAttrValue* aValue, bool aNotify) override;
353 void AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
354 const nsAttrValue* aValue, const nsAttrValue* aOldValue,
355 nsIPrincipal* aMaybeScriptedPrincipal,
356 bool aNotify) override;
357 void OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
358 const nsAttrValueOrString& aValue,
359 bool aNotify) override;
361 // Override for nsImageLoadingContent.
362 nsIContent* AsContent() override { return this; }
364 // Created when we're tracking responsive image state
365 RefPtr<ResponsiveImageSelector> mResponsiveSelector;
367 // This is a weak reference that this element and the HTMLFormElement
368 // cooperate in maintaining.
369 HTMLFormElement* mForm = nullptr;
371 private:
372 bool SourceElementMatches(Element* aSourceElement);
374 static void MapAttributesIntoRule(MappedDeclarationsBuilder&);
376 * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
377 * It will not be called if the value is being unset.
379 * @param aNamespaceID the namespace of the attr being set
380 * @param aName the localname of the attribute being set
381 * @param aValue the value it's being set to represented as either a string or
382 * a parsed nsAttrValue.
383 * @param aOldValue the value previously set. Will be null if no value was
384 * previously set. This value should only be used when
385 * aValueMaybeChanged is true; when aValueMaybeChanged is false,
386 * aOldValue should be considered unreliable.
387 * @param aNotify Whether we plan to notify document observers.
389 void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName,
390 const nsAttrValueOrString& aValue,
391 const nsAttrValue* aOldValue,
392 nsIPrincipal* aMaybeScriptedPrincipal,
393 bool aNotify);
395 bool ShouldLoadImage() const;
397 // Set this image as a lazy load image due to loading="lazy".
398 void SetLazyLoading();
400 void StartLoadingIfNeeded();
402 bool IsInPicture() const {
403 return GetParentElement() &&
404 GetParentElement()->IsHTMLElement(nsGkAtoms::picture);
407 void InvalidateAttributeMapping();
409 void SetResponsiveSelector(RefPtr<ResponsiveImageSelector>&& aSource);
410 void SetDensity(double aDensity);
412 // Queue an image load task (via microtask).
413 void QueueImageLoadTask(bool aAlwaysLoad);
415 RefPtr<ImageLoadTask> mPendingImageLoadTask;
416 nsCOMPtr<nsIURI> mSrcURI;
417 nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
418 nsCOMPtr<nsIPrincipal> mSrcsetTriggeringPrincipal;
420 // Last URL that was attempted to load by this element.
421 nsCOMPtr<nsIURI> mLastSelectedSource;
422 // Last pixel density that was selected.
423 double mCurrentDensity = 1.0;
424 bool mInDocResponsiveContent = false;
427 } // namespace dom
428 } // namespace mozilla
430 #endif /* mozilla_dom_HTMLImageElement_h */