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