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 /* loading of CSS style sheets using the network APIs */
8 
9 #ifndef mozilla_css_Loader_h
10 #define mozilla_css_Loader_h
11 
12 #include "nsIPrincipal.h"
13 #include "nsAutoPtr.h"
14 #include "nsCompatibility.h"
15 #include "nsCycleCollectionParticipant.h"
16 #include "nsDataHashtable.h"
17 #include "nsRefPtrHashtable.h"
18 #include "nsStringFwd.h"
19 #include "nsTArray.h"
20 #include "nsTObserverArray.h"
21 #include "nsURIHashKey.h"
22 #include "mozilla/Attributes.h"
23 #include "mozilla/CORSMode.h"
24 #include "mozilla/StyleSheetInlines.h"
25 #include "mozilla/Maybe.h"
26 #include "mozilla/MemoryReporting.h"
27 #include "mozilla/StyleBackendType.h"
28 #include "mozilla/StyleSheet.h"
29 #include "mozilla/net/ReferrerPolicy.h"
30 
31 class nsICSSLoaderObserver;
32 class nsIConsoleReportCollector;
33 class nsIContent;
34 class nsIDocument;
35 class nsIStyleSheetLinkingElement;
36 
37 namespace mozilla {
38 namespace dom {
39 class DocGroup;
40 class Element;
41 }  // namespace dom
42 }  // namespace mozilla
43 
44 namespace mozilla {
45 
46 class URIPrincipalReferrerPolicyAndCORSModeHashKey : public nsURIHashKey {
47  public:
48   typedef URIPrincipalReferrerPolicyAndCORSModeHashKey* KeyType;
49   typedef const URIPrincipalReferrerPolicyAndCORSModeHashKey* KeyTypePointer;
50   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
51 
URIPrincipalReferrerPolicyAndCORSModeHashKey(const URIPrincipalReferrerPolicyAndCORSModeHashKey * aKey)52   explicit URIPrincipalReferrerPolicyAndCORSModeHashKey(
53       const URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey)
54       : nsURIHashKey(aKey->mKey),
55         mPrincipal(aKey->mPrincipal),
56         mCORSMode(aKey->mCORSMode),
57         mReferrerPolicy(aKey->mReferrerPolicy) {
58     MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
59   }
60 
URIPrincipalReferrerPolicyAndCORSModeHashKey(nsIURI * aURI,nsIPrincipal * aPrincipal,CORSMode aCORSMode,ReferrerPolicy aReferrerPolicy)61   URIPrincipalReferrerPolicyAndCORSModeHashKey(nsIURI* aURI,
62                                                nsIPrincipal* aPrincipal,
63                                                CORSMode aCORSMode,
64                                                ReferrerPolicy aReferrerPolicy)
65       : nsURIHashKey(aURI),
66         mPrincipal(aPrincipal),
67         mCORSMode(aCORSMode),
68         mReferrerPolicy(aReferrerPolicy) {
69     MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
70   }
URIPrincipalReferrerPolicyAndCORSModeHashKey(const URIPrincipalReferrerPolicyAndCORSModeHashKey & toCopy)71   URIPrincipalReferrerPolicyAndCORSModeHashKey(
72       const URIPrincipalReferrerPolicyAndCORSModeHashKey& toCopy)
73       : nsURIHashKey(toCopy),
74         mPrincipal(toCopy.mPrincipal),
75         mCORSMode(toCopy.mCORSMode),
76         mReferrerPolicy(toCopy.mReferrerPolicy) {
77     MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
78   }
~URIPrincipalReferrerPolicyAndCORSModeHashKey()79   ~URIPrincipalReferrerPolicyAndCORSModeHashKey() {
80     MOZ_COUNT_DTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
81   }
82 
GetKey()83   URIPrincipalReferrerPolicyAndCORSModeHashKey* GetKey() const {
84     return const_cast<URIPrincipalReferrerPolicyAndCORSModeHashKey*>(this);
85   }
GetKeyPointer()86   const URIPrincipalReferrerPolicyAndCORSModeHashKey* GetKeyPointer() const {
87     return this;
88   }
89 
KeyEquals(const URIPrincipalReferrerPolicyAndCORSModeHashKey * aKey)90   bool KeyEquals(
91       const URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey) const {
92     if (!nsURIHashKey::KeyEquals(aKey->mKey)) {
93       return false;
94     }
95 
96     if (!mPrincipal != !aKey->mPrincipal) {
97       // One or the other has a principal, but not both... not equal
98       return false;
99     }
100 
101     if (mCORSMode != aKey->mCORSMode) {
102       // Different CORS modes; we don't match
103       return false;
104     }
105 
106     if (mReferrerPolicy != aKey->mReferrerPolicy) {
107       // Different ReferrerPolicy; we don't match
108       return false;
109     }
110 
111     bool eq;
112     return !mPrincipal ||
113            (NS_SUCCEEDED(mPrincipal->Equals(aKey->mPrincipal, &eq)) && eq);
114   }
115 
KeyToPointer(URIPrincipalReferrerPolicyAndCORSModeHashKey * aKey)116   static const URIPrincipalReferrerPolicyAndCORSModeHashKey* KeyToPointer(
117       URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey) {
118     return aKey;
119   }
HashKey(const URIPrincipalReferrerPolicyAndCORSModeHashKey * aKey)120   static PLDHashNumber HashKey(
121       const URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey) {
122     return nsURIHashKey::HashKey(aKey->mKey);
123   }
124 
GetURI()125   nsIURI* GetURI() const { return nsURIHashKey::GetKey(); }
126 
127   enum { ALLOW_MEMMOVE = true };
128 
129  protected:
130   nsCOMPtr<nsIPrincipal> mPrincipal;
131   CORSMode mCORSMode;
132   ReferrerPolicy mReferrerPolicy;
133 };
134 
135 namespace css {
136 
137 class SheetLoadData;
138 class ImportRule;
139 
140 /*********************
141  * Style sheet reuse *
142  *********************/
143 
144 class MOZ_RAII LoaderReusableStyleSheets {
145  public:
LoaderReusableStyleSheets()146   LoaderReusableStyleSheets() {}
147 
148   /**
149    * Look for a reusable sheet (see AddReusableSheet) matching the
150    * given URL.  If found, set aResult, remove the reused sheet from
151    * the internal list, and return true.  If not found, return false;
152    * in this case, aResult is not modified.
153    *
154    * @param aURL the url to match
155    * @param aResult [out] the style sheet which can be reused
156    */
157   bool FindReusableStyleSheet(nsIURI* aURL, RefPtr<StyleSheet>& aResult);
158 
159   /**
160    * Indicate that a certain style sheet is available for reuse if its
161    * URI matches the URI of an @import.  Sheets should be added in the
162    * opposite order in which they are intended to be reused.
163    *
164    * @param aSheet the sheet which can be reused
165    */
AddReusableSheet(StyleSheet * aSheet)166   void AddReusableSheet(StyleSheet* aSheet) {
167     mReusableSheets.AppendElement(aSheet);
168   }
169 
170  private:
171   LoaderReusableStyleSheets(const LoaderReusableStyleSheets&) = delete;
172   LoaderReusableStyleSheets& operator=(const LoaderReusableStyleSheets&) =
173       delete;
174 
175   // The sheets that can be reused.
176   nsTArray<RefPtr<StyleSheet>> mReusableSheets;
177 };
178 
179 /***********************************************************************
180  * Enum that describes the state of the sheet returned by CreateSheet. *
181  ***********************************************************************/
182 enum StyleSheetState {
183   eSheetStateUnknown = 0,
184   eSheetNeedsParser,
185   eSheetPending,
186   eSheetLoading,
187   eSheetComplete
188 };
189 
190 class Loader final {
191   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
192 
193  public:
194   // aDocGroup is used for dispatching SheetLoadData in PostLoadEvent(). It
195   // can be null if you want to use this constructor, and there's no
196   // document when the Loader is constructed.
197   Loader(StyleBackendType aType, mozilla::dom::DocGroup* aDocGroup);
198 
199   explicit Loader(nsIDocument*);
200 
201  private:
202   // Private destructor, to discourage deletion outside of Release():
203   ~Loader();
204 
205  public:
206   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Loader)
207   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(Loader)
208 
209   void DropDocumentReference();  // notification that doc is going away
210 
SetCompatibilityMode(nsCompatibility aCompatMode)211   void SetCompatibilityMode(nsCompatibility aCompatMode) {
212     mCompatMode = aCompatMode;
213   }
GetCompatibilityMode()214   nsCompatibility GetCompatibilityMode() { return mCompatMode; }
215   nsresult SetPreferredSheet(const nsAString& aTitle);
216 
217   // XXXbz sort out what the deal is with events!  When should they fire?
218 
219   /**
220    * Load an inline style sheet.  If a successful result is returned and
221    * *aCompleted is false, then aObserver is guaranteed to be notified
222    * asynchronously once the sheet is marked complete.  If an error is
223    * returned, or if *aCompleted is true, aObserver will not be notified.  In
224    * addition to parsing the sheet, this method will insert it into the
225    * stylesheet list of this CSSLoader's document.
226    *
227    * @param aElement the element linking to the stylesheet.  This must not be
228    *                 null and must implement nsIStyleSheetLinkingElement.
229    * @param aBuffer the stylesheet data
230    * @param aTriggeringPrincipal The principal of the scripted caller that
231    *                             initiated the load, if available. Otherwise
232    *                             null.
233    * @param aLineNumber the line number at which the stylesheet data started.
234    * @param aTitle the title of the sheet.
235    * @param aMedia the media string for the sheet.
236    * @param aReferrerPolicy the referrer policy for loading the sheet.
237    * @param aObserver the observer to notify when the load completes.
238    *        May be null.
239    * @param [out] aCompleted whether parsing of the sheet completed.
240    * @param [out] aIsAlternate whether the stylesheet ended up being an
241    *        alternate sheet.
242    */
243   nsresult LoadInlineStyle(nsIContent* aElement, const nsAString& aBuffer,
244                            nsIPrincipal* aTriggeringPrincipal,
245                            uint32_t aLineNumber, const nsAString& aTitle,
246                            const nsAString& aMedia,
247                            ReferrerPolicy aReferrerPolicy,
248                            mozilla::dom::Element* aScopeElement,
249                            nsICSSLoaderObserver* aObserver, bool* aCompleted,
250                            bool* aIsAlternate);
251 
252   /**
253    * Load a linked (document) stylesheet.  If a successful result is returned,
254    * aObserver is guaranteed to be notified asynchronously once the sheet is
255    * loaded and marked complete.  If an error is returned, aObserver will not
256    * be notified.  In addition to loading the sheet, this method will insert it
257    * into the stylesheet list of this CSSLoader's document.
258    *
259    * @param aElement the element linking to the the stylesheet.  May be null.
260    * @param aURL the URL of the sheet.
261    * @param aTriggeringPrincipal the triggering principal for the load. May be
262    *        null, in which case the NodePrincipal() of the element (or
263    *        document if aElement is null) should be used.
264    * @param aTitle the title of the sheet.
265    * @param aMedia the media string for the sheet.
266    * @param aHasAlternateRel whether the rel for this link included
267    *        "alternate".
268    * @param aCORSMode the CORS mode for this load.
269    * @param aObserver the observer to notify when the load completes.
270    *                  May be null.
271    * @param [out] aIsAlternate whether the stylesheet actually ended up beinga
272    *        an alternate sheet.  Note that this need not match
273    *        aHasAlternateRel.
274    */
275   nsresult LoadStyleLink(nsIContent* aElement, nsIURI* aURL,
276                          nsIPrincipal* aTriggeringPrincipal,
277                          const nsAString& aTitle, const nsAString& aMedia,
278                          bool aHasAlternateRel, CORSMode aCORSMode,
279                          ReferrerPolicy aReferrerPolicy,
280                          const nsAString& aIntegrity,
281                          nsICSSLoaderObserver* aObserver, bool* aIsAlternate);
282 
283   /**
284    * Load a child (@import-ed) style sheet.  In addition to loading the sheet,
285    * this method will insert it into the child sheet list of aParentSheet.  If
286    * there is no sheet currently being parsed and the child sheet is not
287    * complete when this method returns, then when the child sheet becomes
288    * complete aParentSheet will be QIed to nsICSSLoaderObserver and
289    * asynchronously notified, just like for LoadStyleLink.  Note that if the
290    * child sheet is already complete when this method returns, no
291    * nsICSSLoaderObserver notification will be sent.
292    *
293    * @param aParentSheet the parent of this child sheet
294    * @param aParentData the SheetLoadData corresponding to the load of the
295    *                    parent sheet.
296    * @param aURL the URL of the child sheet
297    * @param aMedia the already-parsed media list for the child sheet
298    * @param aGeckoParentRule the @import rule importing this child, when using
299    *                         Gecko's style system. This is used to properly
300    *                         order the child sheet list of aParentSheet.
301    * @param aSavedSheets any saved style sheets which could be reused
302    *              for this load
303    */
304   nsresult LoadChildSheet(StyleSheet* aParentSheet, SheetLoadData* aParentData,
305                           nsIURI* aURL, dom::MediaList* aMedia,
306                           ImportRule* aGeckoParentRule,
307                           LoaderReusableStyleSheets* aSavedSheets);
308 
309   /**
310    * Synchronously load and return the stylesheet at aURL.  Any child sheets
311    * will also be loaded synchronously.  Note that synchronous loads over some
312    * protocols may involve spinning up a new event loop, so use of this method
313    * does NOT guarantee not receiving any events before the sheet loads.  This
314    * method can be used to load sheets not associated with a document.
315    *
316    * @param aURL the URL of the sheet to load
317    * @param aParsingMode the mode in which to parse the sheet
318    *        (see comments at enum SheetParsingMode, above).
319    * @param aUseSystemPrincipal if true, give the resulting sheet the system
320    * principal no matter where it's being loaded from.
321    * @param [out] aSheet the loaded, complete sheet.
322    *
323    * NOTE: At the moment, this method assumes the sheet will be UTF-8, but
324    * ideally it would allow arbitrary encodings.  Callers should NOT depend on
325    * non-UTF8 sheets being treated as UTF-8 by this method.
326    *
327    * NOTE: A successful return from this method doesn't indicate anything about
328    * whether the data could be parsed as CSS and doesn't indicate anything
329    * about the status of child sheets of the returned sheet.
330    */
331   nsresult LoadSheetSync(nsIURI* aURL, SheetParsingMode aParsingMode,
332                          bool aUseSystemPrincipal, RefPtr<StyleSheet>* aSheet);
333 
334   /**
335    * As above, but defaults aParsingMode to eAuthorSheetFeatures and
336    * aUseSystemPrincipal to false.
337    */
LoadSheetSync(nsIURI * aURL,RefPtr<StyleSheet> * aSheet)338   nsresult LoadSheetSync(nsIURI* aURL, RefPtr<StyleSheet>* aSheet) {
339     return LoadSheetSync(aURL, eAuthorSheetFeatures, false, aSheet);
340   }
341 
342   /**
343    * Asynchronously load the stylesheet at aURL.  If a successful result is
344    * returned, aObserver is guaranteed to be notified asynchronously once the
345    * sheet is loaded and marked complete.  This method can be used to load
346    * sheets not associated with a document.
347    *
348    * @param aURL the URL of the sheet to load
349    * @param aParsingMode the mode in which to parse the sheet
350    *        (see comments at enum SheetParsingMode, above).
351    * @param aUseSystemPrincipal if true, give the resulting sheet the system
352    * principal no matter where it's being loaded from.
353    * @param aObserver the observer to notify when the load completes.
354    *                  Must not be null.
355    * @param [out] aSheet the sheet to load. Note that the sheet may well
356    *              not be loaded by the time this method returns.
357    *
358    * NOTE: At the moment, this method assumes the sheet will be UTF-8, but
359    * ideally it would allow arbitrary encodings.  Callers should NOT depend on
360    * non-UTF8 sheets being treated as UTF-8 by this method.
361    */
362   nsresult LoadSheet(nsIURI* aURL, SheetParsingMode aParsingMode,
363                      bool aUseSystemPrincipal, nsICSSLoaderObserver* aObserver,
364                      RefPtr<StyleSheet>* aSheet);
365 
366   /**
367    * Asynchronously load the stylesheet at aURL.  If a successful result is
368    * returned, aObserver is guaranteed to be notified asynchronously once the
369    * sheet is loaded and marked complete.  This method can be used to load
370    * sheets not associated with a document.  This method cannot be used to
371    * load user or agent sheets.
372    *
373    * @param aURL the URL of the sheet to load
374    * @param aOriginPrincipal the principal to use for security checks.  This
375    *                         can be null to indicate that these checks should
376    *                         be skipped.
377    * @param aObserver the observer to notify when the load completes.
378    *                  Must not be null.
379    * @param [out] aSheet the sheet to load. Note that the sheet may well
380    *              not be loaded by the time this method returns.
381    */
382   nsresult LoadSheet(nsIURI* aURL, nsIPrincipal* aOriginPrincipal,
383                      nsICSSLoaderObserver* aObserver,
384                      RefPtr<StyleSheet>* aSheet);
385 
386   /**
387    * Same as above, to be used when the caller doesn't care about the
388    * not-yet-loaded sheet.
389    */
390   nsresult LoadSheet(nsIURI* aURL, bool aIsPreload,
391                      nsIPrincipal* aOriginPrincipal,
392                      const Encoding* aPreloadEncoding,
393                      nsICSSLoaderObserver* aObserver,
394                      CORSMode aCORSMode = CORS_NONE,
395                      ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Unset,
396                      const nsAString& aIntegrity = EmptyString());
397 
398   /**
399    * Stop loading all sheets.  All nsICSSLoaderObservers involved will be
400    * notified with NS_BINDING_ABORTED as the status, possibly synchronously.
401    */
402   nsresult Stop(void);
403 
404   /**
405    * nsresult Loader::StopLoadingSheet(nsIURI* aURL), which notifies the
406    * nsICSSLoaderObserver with NS_BINDING_ABORTED, was removed in Bug 556446.
407    * It can be found in revision 2c44a32052ad.
408    */
409 
410   /**
411    * Whether the loader is enabled or not.
412    * When disabled, processing of new styles is disabled and an attempt
413    * to do so will fail with a return code of
414    * NS_ERROR_NOT_AVAILABLE. Note that this DOES NOT disable
415    * currently loading styles or already processed styles.
416    */
GetEnabled()417   bool GetEnabled() { return mEnabled; }
SetEnabled(bool aEnabled)418   void SetEnabled(bool aEnabled) { mEnabled = aEnabled; }
419 
420   /**
421    * Get the document we live for. May return null.
422    */
GetDocument()423   nsIDocument* GetDocument() const { return mDocument; }
424 
425   /**
426    * Return true if this loader has pending loads (ones that would send
427    * notifications to an nsICSSLoaderObserver attached to this loader).
428    * If called from inside nsICSSLoaderObserver::StyleSheetLoaded, this will
429    * return false if and only if that is the last StyleSheetLoaded
430    * notification the CSSLoader knows it's going to send.  In other words, if
431    * two sheets load at once (via load coalescing, e.g.), HasPendingLoads()
432    * will return true during notification for the first one, and false
433    * during notification for the second one.
434    */
435   bool HasPendingLoads();
436 
437   /**
438    * Add an observer to this loader.  The observer will be notified
439    * for all loads that would have notified their own observers (even
440    * if those loads don't have observers attached to them).
441    * Load-specific observers will be notified before generic
442    * observers.  The loader holds a reference to the observer.
443    *
444    * aObserver must not be null.
445    */
446   nsresult AddObserver(nsICSSLoaderObserver* aObserver);
447 
448   /**
449    * Remove an observer added via AddObserver.
450    */
451   void RemoveObserver(nsICSSLoaderObserver* aObserver);
452 
453   // These interfaces are public only for the benefit of static functions
454   // within nsCSSLoader.cpp.
455 
456   // IsAlternate can change our currently selected style set if none
457   // is selected and aHasAlternateRel is false.
458   bool IsAlternate(const nsAString& aTitle, bool aHasAlternateRel);
459 
460   typedef nsTArray<RefPtr<SheetLoadData>> LoadDataArray;
461 
462   // Measure our size.
463   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
464 
465   // Marks all the sheets at the given URI obsolete, and removes them from the
466   // cache.
467   nsresult ObsoleteSheet(nsIURI* aURI);
468 
469  private:
470   friend class SheetLoadData;
471   friend class StreamLoader;
472 
473   // Helpers to conditionally block onload if mDocument is non-null.
474   void BlockOnload();
475   void UnblockOnload(bool aFireSync);
476 
477   // Helper to select the correct dispatch target for asynchronous events for
478   // this loader.
479   already_AddRefed<nsISerialEventTarget> DispatchTarget();
480 
481   nsresult CheckContentPolicy(nsIPrincipal* aLoadingPrincipal,
482                               nsIPrincipal* aTriggeringPrincipal,
483                               nsIURI* aTargetURI, nsISupports* aContext,
484                               bool aIsPreload);
485 
486   // For inline style, the aURI param is null, but the aLinkingContent
487   // must be non-null then.  The loader principal must never be null
488   // if aURI is not null.
489   // *aIsAlternate is set based on aTitle and aHasAlternateRel.
490   nsresult CreateSheet(nsIURI* aURI, nsIContent* aLinkingContent,
491                        nsIPrincipal* aLoaderPrincipal,
492                        css::SheetParsingMode aParsingMode, CORSMode aCORSMode,
493                        ReferrerPolicy aReferrerPolicy,
494                        const nsAString& aIntegrity, bool aSyncLoad,
495                        bool aHasAlternateRel, const nsAString& aTitle,
496                        StyleSheetState& aSheetState, bool* aIsAlternate,
497                        RefPtr<StyleSheet>* aSheet);
498 
499   // Pass in either a media string or the MediaList from the CSSParser.  Don't
500   // pass both.
501   //
502   // This method will set the sheet's enabled state based on aIsAlternate
503   void PrepareSheet(StyleSheet* aSheet, const nsAString& aTitle,
504                     const nsAString& aMediaString, dom::MediaList* aMediaList,
505                     dom::Element* aScopeElement, bool aIsAlternate);
506 
507   nsresult InsertSheetInDoc(StyleSheet* aSheet, nsIContent* aLinkingContent,
508                             nsIDocument* aDocument);
509 
510   nsresult InsertChildSheet(StyleSheet* aSheet, StyleSheet* aParentSheet,
511                             ImportRule* aGeckoParentRule);
512 
513   nsresult InternalLoadNonDocumentSheet(
514       nsIURI* aURL, bool aIsPreload, SheetParsingMode aParsingMode,
515       bool aUseSystemPrincipal, nsIPrincipal* aOriginPrincipal,
516       const Encoding* aPreloadEncoding, RefPtr<StyleSheet>* aSheet,
517       nsICSSLoaderObserver* aObserver, CORSMode aCORSMode = CORS_NONE,
518       ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Unset,
519       const nsAString& aIntegrity = EmptyString());
520 
521   // Post a load event for aObserver to be notified about aSheet.  The
522   // notification will be sent with status NS_OK unless the load event is
523   // canceled at some point (in which case it will be sent with
524   // NS_BINDING_ABORTED).  aWasAlternate indicates the state when the load was
525   // initiated, not the state at some later time.  aURI should be the URI the
526   // sheet was loaded from (may be null for inline sheets).  aElement is the
527   // owning element for this sheet.
528   nsresult PostLoadEvent(nsIURI* aURI, StyleSheet* aSheet,
529                          nsICSSLoaderObserver* aObserver, bool aWasAlternate,
530                          nsIStyleSheetLinkingElement* aElement);
531 
532   // Start the loads of all the sheets in mPendingDatas
533   void StartAlternateLoads();
534 
535   // Handle an event posted by PostLoadEvent
536   void HandleLoadEvent(SheetLoadData* aEvent);
537 
538   // Note: LoadSheet is responsible for releasing aLoadData and setting the
539   // sheet to complete on failure.
540   nsresult LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState,
541                      bool aIsPreLoad);
542 
543   // Parse the stylesheet in aLoadData. The sheet data comes from aUTF16 if
544   // UTF-16 and from aUTF8 if UTF-8.
545   // Sets aCompleted to true if the parse finished, false otherwise (e.g. if the
546   // sheet had an @import).  If aCompleted is true when this returns, then
547   // ParseSheet also called SheetComplete on aLoadData.
548   nsresult ParseSheet(const nsAString& aUTF16, Span<const uint8_t> aUTF8,
549                       SheetLoadData* aLoadData, bool aAllowAsync,
550                       bool& aCompleted);
551 
552   //
553   // Separate parsing paths for the old and new style systems, so that we can
554   // make parsing asynchronous in the new style system without touching the old
555   // one. Once we drop the old style system, this can be simplified.
556   //
557 
558 #ifdef MOZ_OLD_STYLE
559   nsresult DoParseSheetGecko(CSSStyleSheet* aSheet, const nsAString& aUTF16,
560                              Span<const uint8_t> aUTF8,
561                              SheetLoadData* aLoadData, bool& aCompleted);
562 #endif
563 
564   nsresult DoParseSheetServo(ServoStyleSheet* aSheet, const nsAString& aUTF16,
565                              Span<const uint8_t> aUTF8,
566                              SheetLoadData* aLoadData, bool aAllowAsync,
567                              bool& aCompleted);
568 
569   // The load of the sheet in aLoadData is done, one way or another.  Do final
570   // cleanup, including releasing aLoadData.
571   void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
572 
573   // The guts of SheetComplete.  This may be called recursively on parent datas
574   // or datas that had glommed on to a single load.  The array is there so load
575   // datas whose observers need to be notified can be added to it.
576   void DoSheetComplete(SheetLoadData* aLoadData, LoadDataArray& aDatasToNotify);
577 
578   // Mark the given SheetLoadData, as well as any of its siblings, parents, etc
579   // transitively, as failed.  The idea is to mark as failed any load that was
580   // directly or indirectly @importing the sheet this SheetLoadData represents.
581   void MarkLoadTreeFailed(SheetLoadData* aLoadData);
582 
583   StyleBackendType GetStyleBackendType() const;
584 
585   struct Sheets {
586     nsBaseHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey,
587                     RefPtr<StyleSheet>, StyleSheet*>
588         mCompleteSheets;
589     nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey,
590                     SheetLoadData*>
591         mLoadingDatas;  // weak refs
592     nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey,
593                     SheetLoadData*>
594         mPendingDatas;  // weak refs
595   };
596   nsAutoPtr<Sheets> mSheets;
597 
598   // The array of posted stylesheet loaded events (SheetLoadDatas) we have.
599   // Note that these are rare.
600   LoadDataArray mPostedEvents;
601 
602   // Our array of "global" observers
603   nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver>> mObservers;
604 
605   // This reference is nulled by the Document in it's destructor through
606   // DropDocumentReference().
607   nsIDocument* MOZ_NON_OWNING_REF mDocument;  // the document we live for
608 
609   // For dispatching events via DocGroup::Dispatch() when mDocument is nullptr.
610   RefPtr<mozilla::dom::DocGroup> mDocGroup;
611 
612   // Number of datas still waiting to be notified on if we're notifying on a
613   // whole bunch at once (e.g. in one of the stop methods).  This is used to
614   // make sure that HasPendingLoads() won't return false until we're notifying
615   // on the last data we're working with.
616   uint32_t mDatasToNotifyOn;
617 
618   nsCompatibility mCompatMode;
619   nsString mPreferredSheet;  // title of preferred sheet
620 
621   // Set explicitly when the Loader(StyleBackendType) constructor is used, or
622   // taken from the document when the Loader(nsIDocument*) constructor is used.
623   mozilla::Maybe<StyleBackendType> mStyleBackendType;
624 
625   bool mEnabled;  // is enabled to load new styles
626 
627   nsCOMPtr<nsIConsoleReportCollector> mReporter;
628 
629 #ifdef DEBUG
630   bool mSyncCallback;
631 #endif
632 };
633 
634 }  // namespace css
635 }  // namespace mozilla
636 
637 #endif /* mozilla_css_Loader_h */
638