LinkStyle.h (9927B)
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 #ifndef mozilla_dom_LinkStyle_h 7 #define mozilla_dom_LinkStyle_h 8 9 #include "mozilla/Attributes.h" 10 #include "mozilla/Result.h" 11 #include "mozilla/StyleSheet.h" 12 #include "nsINode.h" 13 #include "nsTArray.h" 14 15 class nsIContent; 16 class nsICSSLoaderObserver; 17 class nsIPrincipal; 18 class nsIURI; 19 20 namespace mozilla::dom { 21 22 class Document; 23 enum class FetchPriority : uint8_t; 24 class ShadowRoot; 25 26 // https://drafts.csswg.org/cssom/#the-linkstyle-interface 27 class LinkStyle { 28 public: 29 enum class ForceUpdate : uint8_t { 30 No, 31 Yes, 32 }; 33 34 enum class Completed : uint8_t { 35 No, 36 Yes, 37 }; 38 39 enum class HasAlternateRel : uint8_t { 40 No, 41 Yes, 42 }; 43 44 enum class IsAlternate : uint8_t { 45 No, 46 Yes, 47 }; 48 49 enum class IsInline : uint8_t { 50 No, 51 Yes, 52 }; 53 54 enum class IsExplicitlyEnabled : uint8_t { 55 No, 56 Yes, 57 }; 58 59 enum class MediaMatched : uint8_t { 60 Yes, 61 No, 62 }; 63 64 struct Update { 65 private: 66 bool mWillNotify; 67 bool mIsAlternate; 68 bool mMediaMatched; 69 70 public: 71 Update() : mWillNotify(false), mIsAlternate(false), mMediaMatched(false) {} 72 73 Update(Completed aCompleted, IsAlternate aIsAlternate, 74 MediaMatched aMediaMatched) 75 : mWillNotify(aCompleted == Completed::No), 76 mIsAlternate(aIsAlternate == IsAlternate::Yes), 77 mMediaMatched(aMediaMatched == MediaMatched::Yes) {} 78 79 bool WillNotify() const { return mWillNotify; } 80 81 bool ShouldBlock() const { 82 if (!mWillNotify) { 83 return false; 84 } 85 86 return !mIsAlternate && mMediaMatched; 87 } 88 }; 89 90 static LinkStyle* FromNode(nsINode& aNode) { return aNode.AsLinkStyle(); } 91 static const LinkStyle* FromNode(const nsINode& aNode) { 92 return aNode.AsLinkStyle(); 93 } 94 95 static LinkStyle* FromNode(Element&); 96 static const LinkStyle* FromNode(const Element& aElement) { 97 return FromNode(const_cast<Element&>(aElement)); 98 } 99 100 template <typename T> 101 static LinkStyle* FromNodeOrNull(T* aNode) { 102 return aNode ? FromNode(*aNode) : nullptr; 103 } 104 105 template <typename T> 106 static const LinkStyle* FromNodeOrNull(const T* aNode) { 107 return aNode ? FromNode(*aNode) : nullptr; 108 } 109 110 enum RelValue { 111 ePREFETCH = 0x00000001, 112 eDNS_PREFETCH = 0x00000002, 113 eSTYLESHEET = 0x00000004, 114 eNEXT = 0x00000008, 115 eALTERNATE = 0x00000010, 116 ePRECONNECT = 0x00000020, 117 // NOTE: 0x40 is unused 118 ePRELOAD = 0x00000080, 119 eMODULE_PRELOAD = 0x00000100, 120 eCOMPRESSION_DICTIONARY = 0x00000200 121 }; 122 123 // The return value is a bitwise or of 0 or more RelValues. 124 static uint32_t ParseLinkTypes(const nsAString& aTypes); 125 126 void UpdateStyleSheetInternal() { 127 (void)UpdateStyleSheetInternal(nullptr, nullptr); 128 } 129 130 struct MOZ_STACK_CLASS SheetInfo { 131 nsIContent* mContent; 132 // FIXME(emilio): do these really need to be strong refs? 133 nsCOMPtr<nsIURI> mURI; 134 135 // The principal of the scripted caller that initiated the load, if 136 // available. Otherwise null. 137 nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; 138 nsCOMPtr<nsIReferrerInfo> mReferrerInfo; 139 mozilla::CORSMode mCORSMode; 140 nsString mTitle; 141 nsString mMedia; 142 nsString mIntegrity; 143 nsString mNonce; 144 const FetchPriority mFetchPriority; 145 146 bool mHasAlternateRel; 147 bool mIsInline; 148 IsExplicitlyEnabled mIsExplicitlyEnabled; 149 150 SheetInfo(const mozilla::dom::Document&, nsIContent*, 151 already_AddRefed<nsIURI> aURI, 152 already_AddRefed<nsIPrincipal> aTriggeringPrincipal, 153 already_AddRefed<nsIReferrerInfo> aReferrerInfo, 154 mozilla::CORSMode, const nsAString& aTitle, 155 const nsAString& aMedia, const nsAString& aIntegrity, 156 const nsAString& aNonce, HasAlternateRel, IsInline, 157 IsExplicitlyEnabled, FetchPriority aFetchPriority); 158 159 ~SheetInfo(); 160 }; 161 162 virtual nsIContent& AsContent() = 0; 163 virtual Maybe<SheetInfo> GetStyleSheetInfo() = 0; 164 165 /** 166 * Used to make the association between a style sheet and 167 * the element that linked it to the document. 168 * 169 * @param aStyleSheet the style sheet associated with this 170 * element. 171 */ 172 void SetStyleSheet(StyleSheet* aStyleSheet); 173 174 /** 175 * Tells this element whether to update the stylesheet when the element's 176 * properties change. This is used by the parser until it has all content etc, 177 * and to guarantee that the right observer is used. 178 */ 179 void DisableUpdates() { mUpdatesEnabled = false; } 180 Result<Update, nsresult> EnableUpdatesAndUpdateStyleSheet( 181 nsICSSLoaderObserver* aObserver) { 182 MOZ_ASSERT(!mUpdatesEnabled); 183 mUpdatesEnabled = true; 184 return DoUpdateStyleSheet(nullptr, nullptr, aObserver, ForceUpdate::No); 185 } 186 187 /** 188 * Gets the charset that the element claims the style sheet is in. 189 * Can return empty string to indicate that we have no charset 190 * information. 191 * 192 * @param aCharset the charset 193 */ 194 virtual void GetCharset(nsAString& aCharset); 195 196 // This doesn't entirely belong here since they only make sense for 197 // some types of linking elements, but it's a better place than 198 // anywhere else. 199 void SetLineNumber(uint32_t aLineNumber) { mLineNumber = aLineNumber; } 200 201 /** 202 * Get the line number, as previously set by SetLineNumber. 203 * 204 * @return the line number of this element; or 1 if no line number 205 * was set 206 */ 207 uint32_t GetLineNumber() const { return mLineNumber; } 208 209 // This doesn't entirely belong here since they only make sense for 210 // some types of linking elements, but it's a better place than 211 // anywhere else. 212 void SetColumnNumber(uint32_t aColumnNumber) { 213 mColumnNumber = aColumnNumber; 214 } 215 216 /** 217 * Get the column number, as previously set by SetColumnNumber. 218 * 219 * @return the column number of this element; or 1 if no column number 220 * was set 221 */ 222 uint32_t GetColumnNumber() const { return mColumnNumber; } 223 224 StyleSheet* GetSheet() const { return mStyleSheet; } 225 226 /** JS can only observe the sheet once fully loaded */ 227 StyleSheet* GetSheetForBindings() const; 228 229 protected: 230 LinkStyle(); 231 virtual ~LinkStyle(); 232 233 // Gets a suitable title and media for SheetInfo out of an element, which 234 // needs to be `this`. 235 // 236 // NOTE(emilio): Needs nsString instead of nsAString because of 237 // CompressWhitespace. 238 static void GetTitleAndMediaForElement(const mozilla::dom::Element&, 239 nsString& aTitle, nsString& aMedia); 240 241 // Returns whether the type attribute specifies the text/css type for style 242 // elements. 243 static bool IsCSSMimeTypeAttributeForStyleElement(const Element&); 244 245 // CC methods 246 void Unlink(); 247 void Traverse(nsCycleCollectionTraversalCallback& cb); 248 249 /** 250 * @param aOldDocument should be non-null only if we're updating because we 251 * removed the node from the document. 252 * @param aOldShadowRoot should be non-null only if we're updating because we 253 * removed the node from a shadow tree. 254 * @param aForceUpdate true will force the update even if the URI has not 255 * changed. This should be used in cases when something 256 * about the content that affects the resulting sheet 257 * changed but the URI may not have changed. 258 * 259 * TODO(emilio): Should probably pass a single DocumentOrShadowRoot. 260 */ 261 Result<Update, nsresult> UpdateStyleSheetInternal( 262 Document* aOldDocument, ShadowRoot* aOldShadowRoot, 263 ForceUpdate = ForceUpdate::No); 264 265 /** 266 * @param aOldDocument should be non-null only if we're updating because we 267 * removed the node from the document. 268 * @param aOldShadowRoot The ShadowRoot that used to contain the style. 269 * Passed as a parameter because on an update, the node 270 * is removed from the tree before the sheet is removed 271 * from the ShadowRoot. 272 * @param aForceUpdate true will force the update even if the URI has not 273 * changed. This should be used in cases when something 274 * about the content that affects the resulting sheet 275 * changed but the URI may not have changed. 276 */ 277 Result<Update, nsresult> DoUpdateStyleSheet(Document* aOldDocument, 278 ShadowRoot* aOldShadowRoot, 279 nsICSSLoaderObserver*, 280 ForceUpdate); 281 282 /** 283 * If the node is being copied into a static document, we need to clone the 284 * associated stylesheet over as well, preserving the relationship between 285 * the node and the stylesheet (See bug 1930618 as to why this is required). 286 * Nodes inheriting from this class should ensure that this is called on 287 * clone, usually by implementing CopyInnerTo. Because we generally don't have 288 * the knowledge of being in shadow root, the actual copying happens later. 289 */ 290 void MaybeStartCopyStyleSheetTo(LinkStyle* aDest, Document* aDoc) const; 291 292 /** 293 * Continuation of MaybeStartCopyStyleSheetTo, called in 294 * LinkStyle::DoUpdateStyleSheet. Unlike MaybeStartCopyStyleSheetTo, this is 295 * called from LinkStyle being copied into. 296 */ 297 void MaybeFinishCopyStyleSheet(Document* aDocument); 298 299 void BindToTree(); 300 301 RefPtr<mozilla::StyleSheet> mStyleSheet; 302 nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; 303 bool mUpdatesEnabled = true; 304 uint32_t mLineNumber = 1; 305 uint32_t mColumnNumber = 1; 306 }; 307 308 } // namespace mozilla::dom 309 310 #endif // mozilla_dom_LinkStyle_h