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_HTMLLinkElement_h
8 #define mozilla_dom_HTMLLinkElement_h
9 
10 #include "mozilla/Attributes.h"
11 #include "mozilla/dom/HTMLDNSPrefetch.h"
12 #include "mozilla/dom/LinkStyle.h"
13 #include "mozilla/dom/Link.h"
14 #include "mozilla/WeakPtr.h"
15 #include "nsGenericHTMLElement.h"
16 #include "nsDOMTokenList.h"
17 
18 namespace mozilla {
19 class EventChainPostVisitor;
20 class EventChainPreVisitor;
21 class PreloaderBase;
22 
23 namespace dom {
24 
25 class HTMLLinkElement final : public nsGenericHTMLElement,
26                               public LinkStyle,
27                               public SupportsDNSPrefetch {
28  public:
29   explicit HTMLLinkElement(
30       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
31 
32   // nsISupports
33   NS_DECL_ISUPPORTS_INHERITED
34 
35   // CC
36   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLLinkElement,
37                                            nsGenericHTMLElement)
38 
39   NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLLinkElement, link);
40   NS_DECL_ADDSIZEOFEXCLUDINGTHIS
41 
42   void LinkAdded();
43   void LinkRemoved();
44 
45   // nsINode
46   nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
47   JSObject* WrapNode(JSContext* aCx,
48                      JS::Handle<JSObject*> aGivenProto) override;
49 
50   // nsIContent
51   nsresult BindToTree(BindContext&, nsINode& aParent) override;
52   void UnbindFromTree(bool aNullParent = true) override;
53   nsresult BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
54                          const nsAttrValueOrString* aValue,
55                          bool aNotify) override;
56   nsresult AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
57                         const nsAttrValue* aValue, const nsAttrValue* aOldValue,
58                         nsIPrincipal* aSubjectPrincipal, bool aNotify) override;
59   // Element
60   bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
61                       const nsAString& aValue,
62                       nsIPrincipal* aMaybeScriptedPrincipal,
63                       nsAttrValue& aResult) override;
64 
65   void CreateAndDispatchEvent(Document* aDoc, const nsAString& aEventName);
66 
67   // WebIDL
68   bool Disabled() const;
69   void SetDisabled(bool aDisabled, ErrorResult& aRv);
70 
GetURI()71   nsIURI* GetURI() {
72     if (!mCachedURI) {
73       GetURIAttr(nsGkAtoms::href, nullptr, getter_AddRefs(mCachedURI));
74     }
75     return mCachedURI.get();
76   }
77 
GetHref(nsAString & aValue)78   void GetHref(nsAString& aValue) {
79     GetURIAttr(nsGkAtoms::href, nullptr, aValue);
80   }
SetHref(const nsAString & aHref,nsIPrincipal * aTriggeringPrincipal,ErrorResult & aRv)81   void SetHref(const nsAString& aHref, nsIPrincipal* aTriggeringPrincipal,
82                ErrorResult& aRv) {
83     SetHTMLAttr(nsGkAtoms::href, aHref, aTriggeringPrincipal, aRv);
84   }
SetHref(const nsAString & aHref,ErrorResult & aRv)85   void SetHref(const nsAString& aHref, ErrorResult& aRv) {
86     SetHTMLAttr(nsGkAtoms::href, aHref, aRv);
87   }
GetCrossOrigin(nsAString & aResult)88   void GetCrossOrigin(nsAString& aResult) {
89     // Null for both missing and invalid defaults is ok, since we
90     // always parse to an enum value, so we don't need an invalid
91     // default, and we _want_ the missing default to be null.
92     GetEnumAttr(nsGkAtoms::crossorigin, nullptr, aResult);
93   }
SetCrossOrigin(const nsAString & aCrossOrigin,ErrorResult & aError)94   void SetCrossOrigin(const nsAString& aCrossOrigin, ErrorResult& aError) {
95     SetOrRemoveNullableStringAttr(nsGkAtoms::crossorigin, aCrossOrigin, aError);
96   }
97   // nsAString for WebBrowserPersistLocalDocument
GetRel(nsAString & aValue)98   void GetRel(nsAString& aValue) { GetHTMLAttr(nsGkAtoms::rel, aValue); }
SetRel(const nsAString & aRel,ErrorResult & aRv)99   void SetRel(const nsAString& aRel, ErrorResult& aRv) {
100     SetHTMLAttr(nsGkAtoms::rel, aRel, aRv);
101   }
102   nsDOMTokenList* RelList();
GetMedia(DOMString & aValue)103   void GetMedia(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::media, aValue); }
SetMedia(const nsAString & aMedia,ErrorResult & aRv)104   void SetMedia(const nsAString& aMedia, ErrorResult& aRv) {
105     SetHTMLAttr(nsGkAtoms::media, aMedia, aRv);
106   }
GetHreflang(DOMString & aValue)107   void GetHreflang(DOMString& aValue) {
108     GetHTMLAttr(nsGkAtoms::hreflang, aValue);
109   }
SetHreflang(const nsAString & aHreflang,ErrorResult & aRv)110   void SetHreflang(const nsAString& aHreflang, ErrorResult& aRv) {
111     SetHTMLAttr(nsGkAtoms::hreflang, aHreflang, aRv);
112   }
113   void GetAs(nsAString& aResult);
SetAs(const nsAString & aAs,ErrorResult & aRv)114   void SetAs(const nsAString& aAs, ErrorResult& aRv) {
115     SetAttr(nsGkAtoms::as, aAs, aRv);
116   }
117 
118   static void ParseAsValue(const nsAString& aValue, nsAttrValue& aResult);
119   static nsContentPolicyType AsValueToContentPolicy(const nsAttrValue& aValue);
120 
Sizes()121   nsDOMTokenList* Sizes() {
122     if (!mSizes) {
123       mSizes = new nsDOMTokenList(this, nsGkAtoms::sizes);
124     }
125     return mSizes;
126   }
GetType(nsAString & aValue)127   void GetType(nsAString& aValue) { GetHTMLAttr(nsGkAtoms::type, aValue); }
SetType(const nsAString & aType,ErrorResult & aRv)128   void SetType(const nsAString& aType, ErrorResult& aRv) {
129     SetHTMLAttr(nsGkAtoms::type, aType, aRv);
130   }
GetCharset(nsAString & aValue)131   void GetCharset(nsAString& aValue) override {
132     GetHTMLAttr(nsGkAtoms::charset, aValue);
133   }
SetCharset(const nsAString & aCharset,ErrorResult & aRv)134   void SetCharset(const nsAString& aCharset, ErrorResult& aRv) {
135     SetHTMLAttr(nsGkAtoms::charset, aCharset, aRv);
136   }
GetRev(DOMString & aValue)137   void GetRev(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::rev, aValue); }
SetRev(const nsAString & aRev,ErrorResult & aRv)138   void SetRev(const nsAString& aRev, ErrorResult& aRv) {
139     SetHTMLAttr(nsGkAtoms::rev, aRev, aRv);
140   }
GetTarget(DOMString & aValue)141   void GetTarget(DOMString& aValue) { GetHTMLAttr(nsGkAtoms::target, aValue); }
SetTarget(const nsAString & aTarget,ErrorResult & aRv)142   void SetTarget(const nsAString& aTarget, ErrorResult& aRv) {
143     SetHTMLAttr(nsGkAtoms::target, aTarget, aRv);
144   }
GetIntegrity(nsAString & aIntegrity)145   void GetIntegrity(nsAString& aIntegrity) const {
146     GetHTMLAttr(nsGkAtoms::integrity, aIntegrity);
147   }
SetIntegrity(const nsAString & aIntegrity,ErrorResult & aRv)148   void SetIntegrity(const nsAString& aIntegrity, ErrorResult& aRv) {
149     SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, aRv);
150   }
SetReferrerPolicy(const nsAString & aReferrer,ErrorResult & aError)151   void SetReferrerPolicy(const nsAString& aReferrer, ErrorResult& aError) {
152     SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrer, aError);
153   }
GetReferrerPolicy(nsAString & aReferrer)154   void GetReferrerPolicy(nsAString& aReferrer) {
155     GetEnumAttr(nsGkAtoms::referrerpolicy, "", aReferrer);
156   }
GetImageSrcset(nsAString & aImageSrcset)157   void GetImageSrcset(nsAString& aImageSrcset) {
158     GetHTMLAttr(nsGkAtoms::imagesrcset, aImageSrcset);
159   }
SetImageSrcset(const nsAString & aImageSrcset,ErrorResult & aError)160   void SetImageSrcset(const nsAString& aImageSrcset, ErrorResult& aError) {
161     SetHTMLAttr(nsGkAtoms::imagesrcset, aImageSrcset, aError);
162   }
GetImageSizes(nsAString & aImageSizes)163   void GetImageSizes(nsAString& aImageSizes) {
164     GetHTMLAttr(nsGkAtoms::imagesizes, aImageSizes);
165   }
SetImageSizes(const nsAString & aImageSizes,ErrorResult & aError)166   void SetImageSizes(const nsAString& aImageSizes, ErrorResult& aError) {
167     SetHTMLAttr(nsGkAtoms::imagesizes, aImageSizes, aError);
168   }
169 
GetCORSMode()170   CORSMode GetCORSMode() const {
171     return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
172   }
173 
NodeInfoChanged(Document * aOldDoc)174   void NodeInfoChanged(Document* aOldDoc) final {
175     mCachedURI = nullptr;
176     nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
177   }
178 
179   static bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType,
180                                 const nsAString& aMedia, Document* aDocument);
181   static void WarnIgnoredPreload(const Document&, nsIURI&);
182 
183  protected:
184   virtual ~HTMLLinkElement();
185 
186   void GetContentPolicyMimeTypeMedia(nsAttrValue& aAsAttr,
187                                      nsContentPolicyType& aPolicyType,
188                                      nsString& aMimeType, nsAString& aMedia);
189   void TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender();
190   void UpdatePreload(nsAtom* aName, const nsAttrValue* aValue,
191                      const nsAttrValue* aOldValue);
192   void CancelPrefetchOrPreload();
193 
194   void StartPreload(nsContentPolicyType policyType);
195   void CancelPreload();
196 
197   // Returns whether the type attribute specifies the text/css mime type for
198   // link elements.
199   static bool IsCSSMimeTypeAttributeForLinkElement(
200       const mozilla::dom::Element&);
201 
202   // LinkStyle
AsContent()203   nsIContent& AsContent() final { return *this; }
AsLinkStyle()204   const LinkStyle* AsLinkStyle() const final { return this; }
205   Maybe<SheetInfo> GetStyleSheetInfo() final;
206 
207   RefPtr<nsDOMTokenList> mRelList;
208   RefPtr<nsDOMTokenList> mSizes;
209 
210   // A weak reference to our preload is held only to cancel the preload when
211   // this node updates or unbounds from the tree.  We want to prevent cycles,
212   // the preload is held alive by other means.
213   WeakPtr<PreloaderBase> mPreload;
214 
215   // The cached href attribute value.
216   nsCOMPtr<nsIURI> mCachedURI;
217 
218   // The "explicitly enabled" flag. This flag is set whenever the `disabled`
219   // attribute is explicitly unset, and makes alternate stylesheets not be
220   // disabled by default anymore.
221   //
222   // See https://github.com/whatwg/html/issues/3840#issuecomment-481034206.
223   bool mExplicitlyEnabled = false;
224 };
225 
226 }  // namespace dom
227 }  // namespace mozilla
228 
229 #endif  // mozilla_dom_HTMLLinkElement_h
230