tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */