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_StyleSheet_h
8 #define mozilla_StyleSheet_h
9 
10 #include "mozilla/css/SheetParsingMode.h"
11 #include "mozilla/dom/CSSStyleSheetBinding.h"
12 #include "mozilla/dom/SRIMetadata.h"
13 #include "mozilla/CORSMode.h"
14 #include "mozilla/MozPromise.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/ServoBindingTypes.h"
17 #include "mozilla/ServoUtils.h"
18 #include "mozilla/StyleSheetInfo.h"
19 #include "mozilla/URLExtraData.h"
20 #include "nsICSSLoaderObserver.h"
21 #include "nsWrapperCache.h"
22 #include "nsCompatibility.h"
23 #include "nsStringFwd.h"
24 
25 class nsINode;
26 class nsIPrincipal;
27 struct RawServoSharedMemoryBuilder;
28 class nsIReferrerInfo;
29 
30 namespace mozilla {
31 
32 class ServoCSSRuleList;
33 class ServoStyleSet;
34 
35 typedef MozPromise</* Dummy */ bool,
36                    /* Dummy */ bool,
37                    /* IsExclusive = */ true>
38     StyleSheetParsePromise;
39 
40 namespace css {
41 class GroupRule;
42 class Loader;
43 class LoaderReusableStyleSheets;
44 class Rule;
45 class SheetLoadData;
46 }  // namespace css
47 
48 namespace dom {
49 class CSSImportRule;
50 class CSSRuleList;
51 class DocumentOrShadowRoot;
52 class MediaList;
53 class ShadowRoot;
54 class SRIMetadata;
55 struct CSSStyleSheetInit;
56 }  // namespace dom
57 
58 enum class StyleSheetState : uint8_t {
59   // Whether the sheet is disabled. Sheets can be made disabled via CSSOM, or
60   // via alternate links and such.
61   Disabled = 1 << 0,
62   // Whether the sheet is complete. The sheet is complete if it's finished
63   // loading. See StyleSheet::SetComplete.
64   Complete = 1 << 1,
65   // Whether we've forced a unique inner. StyleSheet objects share an 'inner'
66   // StyleSheetInfo object if they share URL, CORS mode, etc.
67   //
68   // See the Loader's `mCompleteSheets` and `mLoadingSheets`.
69   ForcedUniqueInner = 1 << 2,
70   // Whether this stylesheet has suffered any modification to the rules via
71   // CSSOM.
72   ModifiedRules = 1 << 3,
73   // Same flag, but devtools clears it in some specific situations.
74   //
75   // Used to control whether devtools shows the rule in its authored form or
76   // not.
77   ModifiedRulesForDevtools = 1 << 4,
78   // Whether modifications to the sheet are currently disallowed.
79   // This flag is set during the async Replace() function to ensure
80   // that the sheet is not modified until the promise is resolved.
81   ModificationDisallowed = 1 << 5,
82 };
83 
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StyleSheetState)84 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StyleSheetState)
85 
86 class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache {
87   StyleSheet(const StyleSheet& aCopy, StyleSheet* aParentSheetToUse,
88              dom::CSSImportRule* aOwnerRuleToUse,
89              dom::DocumentOrShadowRoot* aDocOrShadowRootToUse,
90              dom::Document* aConstructorDocToUse, nsINode* aOwningNodeToUse);
91 
92   virtual ~StyleSheet();
93 
94   using State = StyleSheetState;
95 
96  public:
97   StyleSheet(css::SheetParsingMode aParsingMode, CORSMode aCORSMode,
98              const dom::SRIMetadata& aIntegrity);
99 
100   static already_AddRefed<StyleSheet> Constructor(const dom::GlobalObject&,
101                                                   const dom::CSSStyleSheetInit&,
102                                                   ErrorResult&);
103 
104   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
105   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheet)
106 
107   already_AddRefed<StyleSheet> CreateEmptyChildSheet(
108       already_AddRefed<dom::MediaList> aMediaList) const;
109 
110   bool HasRules() const;
111 
112   // Parses a stylesheet. The load data argument corresponds to the
113   // SheetLoadData for this stylesheet.
114   // NOTE: ParseSheet can run synchronously or asynchronously
115   //       based on the result of `AllowParallelParse`
116   RefPtr<StyleSheetParsePromise> ParseSheet(css::Loader&,
117                                             const nsACString& aBytes,
118                                             css::SheetLoadData&);
119 
120   // Common code that needs to be called after servo finishes parsing. This is
121   // shared between the parallel and sequential paths.
122   void FinishAsyncParse(
123       already_AddRefed<RawServoStyleSheetContents> aSheetContents);
124 
125   // Similar to `ParseSheet`, but guarantees that
126   // parsing will be performed synchronously.
127   // NOTE: ParseSheet can still run synchronously.
128   //       This is not a strict alternative.
129   //
130   // The load data may be null sometimes.
131   void ParseSheetSync(
132       css::Loader* aLoader, const nsACString& aBytes,
133       css::SheetLoadData* aLoadData, uint32_t aLineNumber,
134       css::LoaderReusableStyleSheets* aReusableSheets = nullptr);
135 
136   void ReparseSheet(const nsACString& aInput, ErrorResult& aRv);
137 
138   const RawServoStyleSheetContents* RawContents() const {
139     return Inner().mContents;
140   }
141 
142   void SetContentsForImport(const RawServoStyleSheetContents* aContents) {
143     MOZ_ASSERT(!Inner().mContents);
144     Inner().mContents = aContents;
145   }
146 
147   URLExtraData* URLData() const { return Inner().mURLData; }
148 
149   // nsICSSLoaderObserver interface
150   NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
151                               nsresult aStatus) final;
152 
153   // Internal GetCssRules methods which do not have security check and
154   // completeness check.
155   ServoCSSRuleList* GetCssRulesInternal();
156 
157   // Returns the stylesheet's Servo origin as a StyleOrigin value.
158   StyleOrigin GetOrigin() const;
159 
160   /**
161    * The different changes that a stylesheet may go through.
162    *
163    * Used by the StyleSets in order to handle more efficiently some kinds of
164    * changes.
165    */
166   enum class ChangeType {
167     Added,
168     Removed,
169     ApplicableStateChanged,
170     RuleAdded,
171     RuleRemoved,
172     RuleChanged,
173   };
174 
175   void SetOwningNode(nsINode* aOwningNode) { mOwningNode = aOwningNode; }
176 
177   css::SheetParsingMode ParsingMode() const { return mParsingMode; }
178   dom::CSSStyleSheetParsingMode ParsingModeDOM();
179 
180   /**
181    * Whether the sheet is complete.
182    */
183   bool IsComplete() const { return bool(mState & State::Complete); }
184 
185   void SetComplete();
186 
187   void SetEnabled(bool aEnabled) { SetDisabled(!aEnabled); }
188 
189   // Whether the sheet is for an inline <style> element.
190   bool IsInline() const { return !GetOriginalURI(); }
191 
192   nsIURI* GetSheetURI() const { return Inner().mSheetURI; }
193 
194   /**
195    * Get the URI this sheet was originally loaded from, if any. Can return null.
196    */
197   nsIURI* GetOriginalURI() const { return Inner().mOriginalSheetURI; }
198 
199   nsIURI* GetBaseURI() const { return Inner().mBaseURI; }
200 
201   /**
202    * SetURIs must be called on all sheets before parsing into them.
203    * SetURIs may only be called while the sheet is 1) incomplete and 2)
204    * has no rules in it.
205    *
206    * FIXME(emilio): Can we pass this down when constructing the sheet instead?
207    */
208   inline void SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
209                       nsIURI* aBaseURI);
210 
211   /**
212    * Whether the sheet is applicable.  A sheet that is not applicable
213    * should never be inserted into a style set.  A sheet may not be
214    * applicable for a variety of reasons including being disabled and
215    * being incomplete.
216    */
217   bool IsApplicable() const { return !Disabled() && IsComplete(); }
218 
219   already_AddRefed<StyleSheet> Clone(
220       StyleSheet* aCloneParent, dom::CSSImportRule* aCloneOwnerRule,
221       dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot,
222       nsINode* aCloneOwningNode) const;
223 
224   /**
225    * Creates a clone of the adopted style sheet as though it were constructed
226    * by aConstructorDocument. This should only be used for printing.
227    */
228   already_AddRefed<StyleSheet> CloneAdoptedSheet(
229       dom::Document& aConstructorDocument) const;
230 
231   bool HasForcedUniqueInner() const {
232     return bool(mState & State::ForcedUniqueInner);
233   }
234 
235   bool HasModifiedRules() const { return bool(mState & State::ModifiedRules); }
236 
237   bool HasModifiedRulesForDevtools() const {
238     return bool(mState & State::ModifiedRulesForDevtools);
239   }
240 
241   bool HasUniqueInner() const { return Inner().mSheets.Length() == 1; }
242 
243   void AssertHasUniqueInner() const { MOZ_ASSERT(HasUniqueInner()); }
244 
245   void EnsureUniqueInner();
246 
247   // Returns the DocumentOrShadowRoot* that owns us, if any.
248   //
249   // TODO(emilio): Maybe rename to GetOwner*() or such? Might be
250   // confusing with nsINode::OwnerDoc and such.
251   dom::DocumentOrShadowRoot* GetAssociatedDocumentOrShadowRoot() const;
252 
253   // Whether this stylesheet is kept alive by the associated or constructor
254   // document somehow, and thus at least has the same lifetime as
255   // GetAssociatedDocument().
256   dom::Document* GetKeptAliveByDocument() const;
257 
258   // If this is a constructed style sheet, return mConstructorDocument.
259   // Otherwise return the document we're associated to,
260   // via mDocumentOrShadowRoot.
261   //
262   // Non-null iff GetAssociatedDocumentOrShadowRoot is non-null.
263   dom::Document* GetAssociatedDocument() const;
264 
265   void SetAssociatedDocumentOrShadowRoot(dom::DocumentOrShadowRoot*);
266   void ClearAssociatedDocumentOrShadowRoot() {
267     SetAssociatedDocumentOrShadowRoot(nullptr);
268   }
269 
270   nsINode* GetOwnerNode() const { return mOwningNode; }
271 
272   StyleSheet* GetParentSheet() const { return mParentSheet; }
273 
274   void SetOwnerRule(dom::CSSImportRule* aOwnerRule) {
275     mOwnerRule = aOwnerRule; /* Not ref counted */
276   }
277   dom::CSSImportRule* GetOwnerRule() const { return mOwnerRule; }
278 
279   void AppendStyleSheet(StyleSheet&);
280 
281   // Append a stylesheet to the child list without calling WillDirty.
282   void AppendStyleSheetSilently(StyleSheet&);
283 
284   const nsTArray<RefPtr<StyleSheet>>& ChildSheets() const {
285 #ifdef DEBUG
286     for (StyleSheet* child : Inner().mChildren) {
287       MOZ_ASSERT(child->GetParentSheet());
288       MOZ_ASSERT(child->GetParentSheet()->mInner == mInner);
289     }
290 #endif
291     return Inner().mChildren;
292   }
293 
294   // Principal() never returns a null pointer.
295   nsIPrincipal* Principal() const { return Inner().mPrincipal; }
296 
297   /**
298    * SetPrincipal should be called on all sheets before parsing into them.
299    * This can only be called once with a non-null principal.
300    *
301    * Calling this with a null pointer is allowed and is treated as a no-op.
302    *
303    * FIXME(emilio): Can we get this at construction time instead?
304    */
305   void SetPrincipal(nsIPrincipal* aPrincipal) {
306     StyleSheetInfo& info = Inner();
307     MOZ_ASSERT(!info.mPrincipalSet, "Should only set principal once");
308     if (aPrincipal) {
309       info.mPrincipal = aPrincipal;
310 #ifdef DEBUG
311       info.mPrincipalSet = true;
312 #endif
313     }
314   }
315 
316   void SetTitle(const nsAString& aTitle) { mTitle = aTitle; }
317   void SetMedia(already_AddRefed<dom::MediaList> aMedia);
318 
319   // Get this style sheet's CORS mode
320   CORSMode GetCORSMode() const { return Inner().mCORSMode; }
321 
322   // Get this style sheet's ReferrerInfo
323   nsIReferrerInfo* GetReferrerInfo() const { return Inner().mReferrerInfo; }
324 
325   // Set this style sheet's ReferrerInfo
326   void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
327     Inner().mReferrerInfo = aReferrerInfo;
328   }
329 
330   // Get this style sheet's integrity metadata
331   void GetIntegrity(dom::SRIMetadata& aResult) const {
332     aResult = Inner().mIntegrity;
333   }
334 
335   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
336 #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
337   void List(FILE* aOut = stdout, int32_t aIndex = 0);
338 #endif
339 
340   // WebIDL StyleSheet API
341   void GetType(nsAString& aType);
342   void GetHref(nsAString& aHref, ErrorResult& aRv);
343   // GetOwnerNode is defined above.
344   StyleSheet* GetParentStyleSheet() const { return GetParentSheet(); }
345   void GetTitle(nsAString& aTitle);
346   dom::MediaList* Media();
347   bool Disabled() const { return bool(mState & State::Disabled); }
348   void SetDisabled(bool aDisabled);
349   void GetSourceMapURL(nsAString& aTitle);
350   void SetSourceMapURL(const nsAString& aSourceMapURL);
351   void SetSourceMapURLFromComment(const nsAString& aSourceMapURLFromComment);
352   void GetSourceURL(nsAString& aSourceURL);
353   void SetSourceURL(const nsAString& aSourceURL);
354 
355   // WebIDL CSSStyleSheet API
356   // Can't be inline because we can't include ImportRule here.  And can't be
357   // called GetOwnerRule because that would be ambiguous with the ImportRule
358   // version.
359   css::Rule* GetDOMOwnerRule() const;
360   dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal, ErrorResult&);
361   uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
362                       nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
363   void DeleteRule(uint32_t aIndex, nsIPrincipal& aSubjectPrincipal,
364                   ErrorResult& aRv);
365   int32_t AddRule(const nsAString& aSelector, const nsAString& aBlock,
366                   const dom::Optional<uint32_t>& aIndex,
367                   nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
368   already_AddRefed<dom::Promise> Replace(const nsACString& aText, ErrorResult&);
369   void ReplaceSync(const nsACString& aText, ErrorResult&);
370   bool ModificationDisallowed() const {
371     return bool(mState & State::ModificationDisallowed);
372   }
373 
374   // Called before and after the asynchronous Replace() function
375   // to disable/re-enable modification while there is a pending promise.
376   void SetModificationDisallowed(bool aDisallowed) {
377     MOZ_ASSERT(IsConstructed());
378     MOZ_ASSERT(!IsReadOnly());
379     if (aDisallowed) {
380       mState |= State::ModificationDisallowed;
381       // Sheet will be re-set to complete when its rules are replaced
382       mState &= ~State::Complete;
383       if (!Disabled()) {
384         ApplicableStateChanged(false);
385       }
386     } else {
387       mState &= ~State::ModificationDisallowed;
388     }
389   }
390 
391   // True if the sheet was created through the Constructable StyleSheets API
392   bool IsConstructed() const { return !!mConstructorDocument; }
393 
394   // True if any of this sheet's ancestors were created through the
395   // Constructable StyleSheets API
396   bool SelfOrAncestorIsConstructed() const {
397     return OutermostSheet().IsConstructed();
398   }
399 
400   // Ture if the sheet's constructor document matches the given document
401   bool ConstructorDocumentMatches(const dom::Document& aDocument) const {
402     return mConstructorDocument == &aDocument;
403   }
404 
405   // Add a document or shadow root to the list of adopters.
406   // Adopters will be notified when styles are changed.
407   void AddAdopter(dom::DocumentOrShadowRoot& aAdopter) {
408     MOZ_ASSERT(IsConstructed());
409     MOZ_ASSERT(!mAdopters.Contains(&aAdopter));
410     mAdopters.AppendElement(&aAdopter);
411   }
412 
413   // Remove a document or shadow root from the list of adopters.
414   void RemoveAdopter(dom::DocumentOrShadowRoot& aAdopter) {
415     // Cannot assert IsConstructed() because this can run after unlink.
416     mAdopters.RemoveElement(&aAdopter);
417   }
418 
419   // WebIDL miscellaneous bits
420   inline dom::ParentObject GetParentObject() const;
421   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
422 
423   // Changes to sheets should be after a WillDirty call.
424   void WillDirty();
425 
426   // Called when a rule changes from CSSOM.
427   //
428   // FIXME(emilio): This shouldn't allow null, but MediaList doesn't know about
429   // it's owning media rule, plus it's used for the stylesheet media itself.
430   void RuleChanged(css::Rule*);
431 
432   void AddStyleSet(ServoStyleSet* aStyleSet);
433   void DropStyleSet(ServoStyleSet* aStyleSet);
434 
435   nsresult DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex);
436   nsresult InsertRuleIntoGroup(const nsAString& aRule, css::GroupRule* aGroup,
437                                uint32_t aIndex);
438 
439   // Find the ID of the owner inner window.
440   uint64_t FindOwningWindowInnerID() const;
441 
442   // Copy the contents of this style sheet into the shared memory buffer managed
443   // by aBuilder.  Returns the pointer into the buffer that the sheet contents
444   // were stored at.  (The returned pointer is to an Arc<Locked<Rules>> value,
445   // or null, with a filled in aErrorMessage, on failure.)
446   const ServoCssRules* ToShared(RawServoSharedMemoryBuilder* aBuilder,
447                                 nsCString& aErrorMessage);
448 
449   // Sets the contents of this style sheet to the specified aSharedRules
450   // pointer, which must be a pointer somewhere in the aSharedMemory buffer
451   // as previously returned by a ToShared() call.
452   void SetSharedContents(const ServoCssRules* aSharedRules);
453 
454   // Whether this style sheet should not allow any modifications.
455   //
456   // This is true for any User Agent sheets once they are complete.
457   bool IsReadOnly() const;
458 
459   // Removes a stylesheet from its parent sheet child list, if any.
460   void RemoveFromParent();
461 
462   // Resolves mReplacePromise with this sheet.
463   void MaybeResolveReplacePromise();
464 
465   // Rejects mReplacePromise with a NetworkError.
466   void MaybeRejectReplacePromise();
467 
468  private:
469   void SetModifiedRules() {
470     mState |= State::ModifiedRules | State::ModifiedRulesForDevtools;
471   }
472 
473   const StyleSheet& OutermostSheet() const {
474     auto* current = this;
475     while (current->mParentSheet) {
476       MOZ_ASSERT(!current->mDocumentOrShadowRoot,
477                  "Shouldn't be set on child sheets");
478       MOZ_ASSERT(!current->mConstructorDocument,
479                  "Shouldn't be set on child sheets");
480       current = current->mParentSheet;
481     }
482     return *current;
483   }
484 
485   StyleSheetInfo& Inner() {
486     MOZ_ASSERT(mInner);
487     return *mInner;
488   }
489 
490   const StyleSheetInfo& Inner() const {
491     MOZ_ASSERT(mInner);
492     return *mInner;
493   }
494 
495   // Check if the rules are available for read and write.
496   // It does the security check as well as whether the rules have been
497   // completely loaded. aRv will have an exception set if this function
498   // returns false.
499   bool AreRulesAvailable(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
500 
501   void SetURLExtraData();
502 
503  protected:
504   // Internal methods which do not have security check and completeness check.
505   uint32_t InsertRuleInternal(const nsAString& aRule, uint32_t aIndex,
506                               ErrorResult&);
507   void DeleteRuleInternal(uint32_t aIndex, ErrorResult&);
508   nsresult InsertRuleIntoGroupInternal(const nsAString& aRule,
509                                        css::GroupRule* aGroup, uint32_t aIndex);
510 
511   // Common tail routine for the synchronous and asynchronous parsing paths.
512   void FinishParse();
513 
514   // Take the recently cloned sheets from the `@import` rules, and reparent them
515   // correctly to `aPrimarySheet`.
516   void BuildChildListAfterInnerClone();
517 
518   void DropRuleList();
519 
520   // Called when a rule is removed from the sheet from CSSOM.
521   void RuleAdded(css::Rule&);
522 
523   // Called when a rule is added to the sheet from CSSOM.
524   void RuleRemoved(css::Rule&);
525 
526   // Called when a stylesheet is cloned.
527   void StyleSheetCloned(StyleSheet&);
528 
529   // Notifies that the applicable state changed.
530   // aApplicable is the value that we expect to get from IsApplicable().
531   // assertion will fail if the expectation does not match reality.
532   void ApplicableStateChanged(bool aApplicable);
533 
534   void UnparentChildren();
535 
536   void LastRelease();
537 
538   // Return success if the subject principal subsumes the principal of our
539   // inner, error otherwise.  This will also succeed if access is allowed by
540   // CORS.  In that case, it will set the principal of the inner to the
541   // subject principal.
542   void SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
543                                      ErrorResult& aRv);
544 
545   // Drop our reference to mMedia
546   void DropMedia();
547 
548   // Unlink our inner, if needed, for cycle collection.
549   void UnlinkInner();
550   // Traverse our inner, if needed, for cycle collection
551   void TraverseInner(nsCycleCollectionTraversalCallback&);
552 
553   // Return whether the given @import rule has pending child sheet.
554   static bool RuleHasPendingChildSheet(css::Rule* aRule);
555 
556   StyleSheet* mParentSheet;  // weak ref
557 
558   // A pointer to the sheets relevant global object.
559   // This is populated when the sheet gets an associated document.
560   // This is required for the sheet to be able to create a promise.
561   // https://html.spec.whatwg.org/#concept-relevant-everything
562   nsCOMPtr<nsIGlobalObject> mRelevantGlobal;
563 
564   RefPtr<dom::Document> mConstructorDocument;
565 
566   // Will be set in the Replace() function and resolved/rejected by the
567   // sheet once its rules have been replaced and the sheet is complete again.
568   RefPtr<dom::Promise> mReplacePromise;
569 
570   nsString mTitle;
571 
572   // weak ref; parents maintain this for their children
573   dom::DocumentOrShadowRoot* mDocumentOrShadowRoot;
574   nsINode* mOwningNode;            // weak ref
575   dom::CSSImportRule* mOwnerRule;  // weak ref
576 
577   RefPtr<dom::MediaList> mMedia;
578 
579   // mParsingMode controls access to nonstandard style constructs that
580   // are not safe for use on the public Web but necessary in UA sheets
581   // and/or useful in user sheets.
582   //
583   // FIXME(emilio): Given we store the parsed contents in the Inner, this should
584   // probably also move there.
585   css::SheetParsingMode mParsingMode;
586 
587   State mState;
588 
589   // Core information we get from parsed sheets, which are shared amongst
590   // StyleSheet clones.
591   //
592   // Always nonnull until LastRelease().
593   StyleSheetInfo* mInner;
594 
595   nsTArray<ServoStyleSet*> mStyleSets;
596 
597   RefPtr<ServoCSSRuleList> mRuleList;
598 
599   MozPromiseHolder<StyleSheetParsePromise> mParsePromise;
600 
601   nsTArray<dom::DocumentOrShadowRoot*> mAdopters;
602 
603   // Make StyleSheetInfo and subclasses into friends so they can use
604   // ChildSheetListBuilder.
605   friend struct StyleSheetInfo;
606 };
607 
608 }  // namespace mozilla
609 
610 #endif  // mozilla_StyleSheet_h
611