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 <tuple>
13 #include <utility>
14 
15 #include "mozilla/Attributes.h"
16 #include "mozilla/CORSMode.h"
17 #include "mozilla/css/StylePreloadKind.h"
18 #include "mozilla/dom/LinkStyle.h"
19 #include "mozilla/MemoryReporting.h"
20 #include "mozilla/UniquePtr.h"
21 #include "nsCompatibility.h"
22 #include "nsCycleCollectionParticipant.h"
23 #include "nsStringFwd.h"
24 #include "nsTArray.h"
25 #include "nsTObserverArray.h"
26 #include "nsURIHashKey.h"
27 #include "nsRefPtrHashtable.h"
28 
29 class nsICSSLoaderObserver;
30 class nsIConsoleReportCollector;
31 class nsIContent;
32 class nsIPrincipal;
33 
34 namespace mozilla {
35 
36 class PreloadHashKey;
37 class SharedStyleSheetCache;
38 class SheetLoadDataHashKey;
39 class StyleSheet;
40 
41 namespace dom {
42 class DocGroup;
43 class Element;
44 }  // namespace dom
45 
46 // The load data for a <link> or @import style-sheet.
47 //
48 // This must contain all the state that affects CSS parsing.
49 class SheetLoadDataHashKey : public PLDHashEntryHdr {
50  public:
51   using KeyType = const SheetLoadDataHashKey&;
52   using KeyTypePointer = const SheetLoadDataHashKey*;
53 
SheetLoadDataHashKey(const SheetLoadDataHashKey * aKey)54   explicit SheetLoadDataHashKey(const SheetLoadDataHashKey* aKey)
55       : mURI(aKey->mURI),
56         mPrincipal(aKey->mPrincipal),
57         mLoaderPrincipal(aKey->mLoaderPrincipal),
58         mPartitionPrincipal(aKey->mPartitionPrincipal),
59         mEncodingGuess(aKey->mEncodingGuess),
60         mCORSMode(aKey->mCORSMode),
61         mParsingMode(aKey->mParsingMode),
62         mCompatMode(aKey->mCompatMode),
63         mSRIMetadata(aKey->mSRIMetadata),
64         mIsLinkRelPreload(aKey->mIsLinkRelPreload) {
65     MOZ_COUNT_CTOR(SheetLoadDataHashKey);
66   }
67 
SheetLoadDataHashKey(nsIURI * aURI,nsIPrincipal * aPrincipal,nsIPrincipal * aLoaderPrincipal,nsIPrincipal * aPartitionPrincipal,NotNull<const Encoding * > aEncodingGuess,CORSMode aCORSMode,css::SheetParsingMode aParsingMode,nsCompatibility aCompatMode,const dom::SRIMetadata & aSRIMetadata,css::StylePreloadKind aPreloadKind)68   SheetLoadDataHashKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
69                        nsIPrincipal* aLoaderPrincipal,
70                        nsIPrincipal* aPartitionPrincipal,
71                        NotNull<const Encoding*> aEncodingGuess,
72                        CORSMode aCORSMode, css::SheetParsingMode aParsingMode,
73                        nsCompatibility aCompatMode,
74                        const dom::SRIMetadata& aSRIMetadata,
75                        css::StylePreloadKind aPreloadKind)
76       : mURI(aURI),
77         mPrincipal(aPrincipal),
78         mLoaderPrincipal(aLoaderPrincipal),
79         mPartitionPrincipal(aPartitionPrincipal),
80         mEncodingGuess(aEncodingGuess),
81         mCORSMode(aCORSMode),
82         mParsingMode(aParsingMode),
83         mCompatMode(aCompatMode),
84         mSRIMetadata(aSRIMetadata),
85         mIsLinkRelPreload(IsLinkRelPreload(aPreloadKind)) {
86     MOZ_ASSERT(aURI);
87     MOZ_ASSERT(aPrincipal);
88     MOZ_ASSERT(aLoaderPrincipal);
89     MOZ_COUNT_CTOR(SheetLoadDataHashKey);
90   }
91 
SheetLoadDataHashKey(SheetLoadDataHashKey && toMove)92   SheetLoadDataHashKey(SheetLoadDataHashKey&& toMove)
93       : mURI(std::move(toMove.mURI)),
94         mPrincipal(std::move(toMove.mPrincipal)),
95         mLoaderPrincipal(std::move(toMove.mLoaderPrincipal)),
96         mPartitionPrincipal(std::move(toMove.mPartitionPrincipal)),
97         mEncodingGuess(std::move(toMove.mEncodingGuess)),
98         mCORSMode(std::move(toMove.mCORSMode)),
99         mParsingMode(std::move(toMove.mParsingMode)),
100         mCompatMode(std::move(toMove.mCompatMode)),
101         mSRIMetadata(std::move(toMove.mSRIMetadata)),
102         mIsLinkRelPreload(std::move(toMove.mIsLinkRelPreload)) {
103     MOZ_COUNT_CTOR(SheetLoadDataHashKey);
104   }
105 
106   explicit SheetLoadDataHashKey(const css::SheetLoadData&);
107 
MOZ_COUNTED_DTOR(SheetLoadDataHashKey)108   MOZ_COUNTED_DTOR(SheetLoadDataHashKey)
109 
110   const SheetLoadDataHashKey& GetKey() const { return *this; }
GetKeyPointer()111   const SheetLoadDataHashKey* GetKeyPointer() const { return this; }
112 
KeyEquals(const SheetLoadDataHashKey * aKey)113   bool KeyEquals(const SheetLoadDataHashKey* aKey) const {
114     return KeyEquals(*aKey);
115   }
116 
117   bool KeyEquals(const SheetLoadDataHashKey&) const;
118 
KeyToPointer(const SheetLoadDataHashKey & aKey)119   static const SheetLoadDataHashKey* KeyToPointer(
120       const SheetLoadDataHashKey& aKey) {
121     return &aKey;
122   }
HashKey(const SheetLoadDataHashKey * aKey)123   static PLDHashNumber HashKey(const SheetLoadDataHashKey* aKey) {
124     return nsURIHashKey::HashKey(aKey->mURI);
125   }
126 
URI()127   nsIURI* URI() const { return mURI; }
128 
Principal()129   nsIPrincipal* Principal() const { return mPrincipal; }
130 
LoaderPrincipal()131   nsIPrincipal* LoaderPrincipal() const { return mLoaderPrincipal; }
132 
PartitionPrincipal()133   nsIPrincipal* PartitionPrincipal() const { return mPartitionPrincipal; }
134 
ParsingMode()135   css::SheetParsingMode ParsingMode() const { return mParsingMode; }
136 
137   enum { ALLOW_MEMMOVE = true };
138 
139  protected:
140   const nsCOMPtr<nsIURI> mURI;
141   const nsCOMPtr<nsIPrincipal> mPrincipal;
142   const nsCOMPtr<nsIPrincipal> mLoaderPrincipal;
143   const nsCOMPtr<nsIPrincipal> mPartitionPrincipal;
144   // The encoding guess is the encoding the sheet would get if the request
145   // didn't have any encoding information like @charset or a Content-Encoding
146   // header.
147   const NotNull<const Encoding*> mEncodingGuess;
148   const CORSMode mCORSMode;
149   const css::SheetParsingMode mParsingMode;
150   const nsCompatibility mCompatMode;
151   dom::SRIMetadata mSRIMetadata;
152   const bool mIsLinkRelPreload;
153 };
154 
155 namespace css {
156 
157 class SheetLoadData;
158 class ImportRule;
159 
160 /*********************
161  * Style sheet reuse *
162  *********************/
163 
164 class MOZ_RAII LoaderReusableStyleSheets {
165  public:
166   LoaderReusableStyleSheets() = default;
167 
168   /**
169    * Look for a reusable sheet (see AddReusableSheet) matching the
170    * given URL.  If found, set aResult, remove the reused sheet from
171    * the internal list, and return true.  If not found, return false;
172    * in this case, aResult is not modified.
173    *
174    * @param aURL the url to match
175    * @param aResult [out] the style sheet which can be reused
176    */
177   bool FindReusableStyleSheet(nsIURI* aURL, RefPtr<StyleSheet>& aResult);
178 
179   /**
180    * Indicate that a certain style sheet is available for reuse if its
181    * URI matches the URI of an @import.  Sheets should be added in the
182    * opposite order in which they are intended to be reused.
183    *
184    * @param aSheet the sheet which can be reused
185    */
AddReusableSheet(StyleSheet * aSheet)186   void AddReusableSheet(StyleSheet* aSheet) {
187     mReusableSheets.AppendElement(aSheet);
188   }
189 
190  private:
191   LoaderReusableStyleSheets(const LoaderReusableStyleSheets&) = delete;
192   LoaderReusableStyleSheets& operator=(const LoaderReusableStyleSheets&) =
193       delete;
194 
195   // The sheets that can be reused.
196   nsTArray<RefPtr<StyleSheet>> mReusableSheets;
197 };
198 
199 class Loader final {
200   using ReferrerPolicy = dom::ReferrerPolicy;
201 
202  public:
203   using Completed = dom::LinkStyle::Completed;
204   using HasAlternateRel = dom::LinkStyle::HasAlternateRel;
205   using IsAlternate = dom::LinkStyle::IsAlternate;
206   using IsInline = dom::LinkStyle::IsInline;
207   using IsExplicitlyEnabled = dom::LinkStyle::IsExplicitlyEnabled;
208   using MediaMatched = dom::LinkStyle::MediaMatched;
209   using LoadSheetResult = dom::LinkStyle::Update;
210   using SheetInfo = dom::LinkStyle::SheetInfo;
211 
212   Loader();
213   // aDocGroup is used for dispatching SheetLoadData in PostLoadEvent(). It
214   // can be null if you want to use this constructor, and there's no
215   // document when the Loader is constructed.
216   explicit Loader(dom::DocGroup*);
217   explicit Loader(dom::Document*);
218 
219  private:
220   // Private destructor, to discourage deletion outside of Release():
221   ~Loader();
222 
223  public:
224   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Loader)
225   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(Loader)
226 
227   void DropDocumentReference();  // notification that doc is going away
228 
229   void DeregisterFromSheetCache();
230   void RegisterInSheetCache();
231 
SetCompatibilityMode(nsCompatibility aCompatMode)232   void SetCompatibilityMode(nsCompatibility aCompatMode) {
233     mDocumentCompatMode = aCompatMode;
234   }
235 
236   using StylePreloadKind = css::StylePreloadKind;
237 
CompatMode(StylePreloadKind aPreloadKind)238   nsCompatibility CompatMode(StylePreloadKind aPreloadKind) const {
239     // For Link header preload, we guess non-quirks, because otherwise it is
240     // useless for modern pages.
241     //
242     // Link element preload is generally good because the speculative html
243     // parser deals with quirks mode properly.
244     if (aPreloadKind == StylePreloadKind::FromLinkRelPreloadHeader) {
245       return eCompatibility_FullStandards;
246     }
247     return mDocumentCompatMode;
248   }
249 
250   // TODO(emilio): Is the complexity of this method and carrying the titles
251   // around worth it? The alternate sheets will load anyhow eventually...
252   void DocumentStyleSheetSetChanged();
253 
254   // XXXbz sort out what the deal is with events!  When should they fire?
255 
256   /**
257    * Load an inline style sheet.  If a successful result is returned and
258    * result.WillNotify() is true, then aObserver is guaranteed to be notified
259    * asynchronously once the sheet is marked complete.  If an error is
260    * returned, or if result.WillNotify() is false, aObserver will not be
261    * notified.  In addition to parsing the sheet, this method will insert it
262    * into the stylesheet list of this CSSLoader's document.
263    * @param aObserver the observer to notify when the load completes.
264    *        May be null.
265    * @param aBuffer the stylesheet data
266    * @param aLineNumber the line number at which the stylesheet data started.
267    */
268   Result<LoadSheetResult, nsresult> LoadInlineStyle(
269       const SheetInfo&, const nsAString& aBuffer, uint32_t aLineNumber,
270       nsICSSLoaderObserver* aObserver);
271 
272   /**
273    * Load a linked (document) stylesheet.  If a successful result is returned,
274    * aObserver is guaranteed to be notified asynchronously once the sheet is
275    * loaded and marked complete, i.e., result.WillNotify() will always return
276    * true.  If an error is returned, aObserver will not be notified.  In
277    * addition to loading the sheet, this method will insert it into the
278    * stylesheet list of this CSSLoader's document.
279    * @param aObserver the observer to notify when the load completes.
280    *                  May be null.
281    */
282   Result<LoadSheetResult, nsresult> LoadStyleLink(
283       const SheetInfo&, nsICSSLoaderObserver* aObserver);
284 
285   /**
286    * Load a child (@import-ed) style sheet.  In addition to loading the sheet,
287    * this method will insert it into the child sheet list of aParentSheet.  If
288    * there is no sheet currently being parsed and the child sheet is not
289    * complete when this method returns, then when the child sheet becomes
290    * complete aParentSheet will be QIed to nsICSSLoaderObserver and
291    * asynchronously notified, just like for LoadStyleLink.  Note that if the
292    * child sheet is already complete when this method returns, no
293    * nsICSSLoaderObserver notification will be sent.
294    *
295    * @param aParentSheet the parent of this child sheet
296    * @param aParentData the SheetLoadData corresponding to the load of the
297    *                    parent sheet. May be null for @import rules inserted via
298    *                    CSSOM.
299    * @param aURL the URL of the child sheet
300    * @param aMedia the already-parsed media list for the child sheet
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                           LoaderReusableStyleSheets* aSavedSheets);
307 
308   /**
309    * Called when we hit the internal memory cache with a complete stylesheet.
310    */
311   void DidHitCompleteSheetCache(const SheetLoadDataHashKey&,
312                                 const StyleUseCounters* aCounters);
313 
314   enum class UseSystemPrincipal { No, Yes };
315 
316   /**
317    * Synchronously load and return the stylesheet at aURL.  Any child sheets
318    * will also be loaded synchronously.  Note that synchronous loads over some
319    * protocols may involve spinning up a new event loop, so use of this method
320    * does NOT guarantee not receiving any events before the sheet loads.  This
321    * method can be used to load sheets not associated with a document.
322    *
323    * @param aURL the URL of the sheet to load
324    * @param aParsingMode the mode in which to parse the sheet
325    *        (see comments at enum SheetParsingMode, above).
326    * @param aUseSystemPrincipal if true, give the resulting sheet the system
327    * principal no matter where it's being loaded from.
328    *
329    * NOTE: At the moment, this method assumes the sheet will be UTF-8, but
330    * ideally it would allow arbitrary encodings.  Callers should NOT depend on
331    * non-UTF8 sheets being treated as UTF-8 by this method.
332    *
333    * NOTE: A successful return from this method doesn't indicate anything about
334    * whether the data could be parsed as CSS and doesn't indicate anything
335    * about the status of child sheets of the returned sheet.
336    */
337   Result<RefPtr<StyleSheet>, nsresult> LoadSheetSync(
338       nsIURI*, SheetParsingMode = eAuthorSheetFeatures,
339       UseSystemPrincipal = UseSystemPrincipal::No);
340 
341   /**
342    * Asynchronously load the stylesheet at aURL.  If a successful result is
343    * returned, aObserver is guaranteed to be notified asynchronously once the
344    * sheet is loaded and marked complete.  This method can be used to load
345    * sheets not associated with a document.
346    *
347    * @param aURL the URL of the sheet to load
348    * @param aParsingMode the mode in which to parse the sheet
349    *        (see comments at enum SheetParsingMode, above).
350    * @param aUseSystemPrincipal if true, give the resulting sheet the system
351    * principal no matter where it's being loaded from.
352    * @param aReferrerInfo referrer information of the sheet.
353    * @param aObserver the observer to notify when the load completes.
354    *                  Must not be null.
355    * @return the sheet to load. Note that the sheet may well not be loaded by
356    * 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   Result<RefPtr<StyleSheet>, nsresult> LoadSheet(
363       nsIURI* aURI, StylePreloadKind, const Encoding* aPreloadEncoding,
364       nsIReferrerInfo* aReferrerInfo, nsICSSLoaderObserver* aObserver,
365       CORSMode = CORS_NONE, const nsAString& aIntegrity = u""_ns);
366 
367   /**
368    * As above, but without caring for a couple things.
369    */
370   Result<RefPtr<StyleSheet>, nsresult> LoadSheet(nsIURI*, SheetParsingMode,
371                                                  UseSystemPrincipal,
372                                                  nsICSSLoaderObserver*);
373 
374   /**
375    * Stop loading all sheets.  All nsICSSLoaderObservers involved will be
376    * notified with NS_BINDING_ABORTED as the status, possibly synchronously.
377    */
378   void Stop();
379 
380   /**
381    * nsresult Loader::StopLoadingSheet(nsIURI* aURL), which notifies the
382    * nsICSSLoaderObserver with NS_BINDING_ABORTED, was removed in Bug 556446.
383    * It can be found in revision 2c44a32052ad.
384    */
385 
386   /**
387    * Whether the loader is enabled or not.
388    * When disabled, processing of new styles is disabled and an attempt
389    * to do so will fail with a return code of
390    * NS_ERROR_NOT_AVAILABLE. Note that this DOES NOT disable
391    * currently loading styles or already processed styles.
392    */
GetEnabled()393   bool GetEnabled() { return mEnabled; }
SetEnabled(bool aEnabled)394   void SetEnabled(bool aEnabled) { mEnabled = aEnabled; }
395 
ParsedSheetCount()396   uint32_t ParsedSheetCount() const { return mParsedSheetCount; }
397 
398   /**
399    * Get the document we live for. May return null.
400    */
GetDocument()401   dom::Document* GetDocument() const { return mDocument; }
402 
403   /**
404    * Return true if this loader has pending loads (ones that would send
405    * notifications to an nsICSSLoaderObserver attached to this loader).
406    * If called from inside nsICSSLoaderObserver::StyleSheetLoaded, this will
407    * return false if and only if that is the last StyleSheetLoaded
408    * notification the CSSLoader knows it's going to send.  In other words, if
409    * two sheets load at once (via load coalescing, e.g.), HasPendingLoads()
410    * will return true during notification for the first one, and false
411    * during notification for the second one.
412    */
413   bool HasPendingLoads();
414 
415   /**
416    * Add an observer to this loader.  The observer will be notified
417    * for all loads that would have notified their own observers (even
418    * if those loads don't have observers attached to them).
419    * Load-specific observers will be notified before generic
420    * observers.  The loader holds a reference to the observer.
421    *
422    * aObserver must not be null.
423    */
424   void AddObserver(nsICSSLoaderObserver* aObserver);
425 
426   /**
427    * Remove an observer added via AddObserver.
428    */
429   void RemoveObserver(nsICSSLoaderObserver* aObserver);
430 
431   // These interfaces are public only for the benefit of static functions
432   // within nsCSSLoader.cpp.
433 
434   // IsAlternateSheet can change our currently selected style set if none is
435   // selected and aHasAlternateRel is false.
436   IsAlternate IsAlternateSheet(const nsAString& aTitle, bool aHasAlternateRel);
437 
438   typedef nsTArray<RefPtr<SheetLoadData>> LoadDataArray;
439 
440   // Measure our size.
441   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
442 
443   enum class SheetState : uint8_t {
444     NeedsParser = 0,
445     Pending,
446     Loading,
447     Complete
448   };
449 
450   // The loader principal is the document's node principal, if this loader is
451   // owned by a document, or the system principal otherwise.
452   nsIPrincipal* LoaderPrincipal() const;
453 
454   // The partitioned principal is the document's partitioned principal, if this
455   // loader is owned by a document, or the system principal otherwise.
456   nsIPrincipal* PartitionedPrincipal() const;
457 
458   bool ShouldBypassCache() const;
459 
460  private:
461   friend class mozilla::SharedStyleSheetCache;
462   friend class SheetLoadData;
463   friend class StreamLoader;
464 
465   // Helpers to conditionally block onload if mDocument is non-null.
IncrementOngoingLoadCount()466   void IncrementOngoingLoadCount() {
467     if (!mOngoingLoadCount++) {
468       BlockOnload();
469     }
470   }
471 
DecrementOngoingLoadCount()472   void DecrementOngoingLoadCount() {
473     MOZ_DIAGNOSTIC_ASSERT(mOngoingLoadCount);
474     MOZ_DIAGNOSTIC_ASSERT(mOngoingLoadCount > mPendingLoadCount);
475     if (!--mOngoingLoadCount) {
476       UnblockOnload(false);
477     }
478   }
479 
480   void BlockOnload();
481   void UnblockOnload(bool aFireSync);
482 
483   // Helper to select the correct dispatch target for asynchronous events for
484   // this loader.
485   already_AddRefed<nsISerialEventTarget> DispatchTarget();
486 
487   nsresult CheckContentPolicy(nsIPrincipal* aLoadingPrincipal,
488                               nsIPrincipal* aTriggeringPrincipal,
489                               nsIURI* aTargetURI, nsINode* aRequestingNode,
490                               const nsAString& aNonce, StylePreloadKind);
491 
CreateSheet(const SheetInfo & aInfo,css::SheetParsingMode aParsingMode,bool aSyncLoad,css::StylePreloadKind aPreloadKind)492   std::tuple<RefPtr<StyleSheet>, SheetState> CreateSheet(
493       const SheetInfo& aInfo, css::SheetParsingMode aParsingMode,
494       bool aSyncLoad, css::StylePreloadKind aPreloadKind) {
495     nsIPrincipal* triggeringPrincipal = aInfo.mTriggeringPrincipal
496                                             ? aInfo.mTriggeringPrincipal.get()
497                                             : LoaderPrincipal();
498     return CreateSheet(aInfo.mURI, aInfo.mContent, triggeringPrincipal,
499                        aParsingMode, aInfo.mCORSMode,
500                        /* aPreloadOrParentDataEncoding = */ nullptr,
501                        aInfo.mIntegrity, aSyncLoad, aPreloadKind);
502   }
503 
504   // For inline style, the aURI param is null, but the aLinkingContent
505   // must be non-null then.  The loader principal must never be null
506   // if aURI is not null.
507   std::tuple<RefPtr<StyleSheet>, SheetState> CreateSheet(
508       nsIURI* aURI, nsIContent* aLinkingContent,
509       nsIPrincipal* aTriggeringPrincipal, css::SheetParsingMode, CORSMode,
510       const Encoding* aPreloadOrParentDataEncoding, const nsAString& aIntegrity,
511       bool aSyncLoad, StylePreloadKind);
512 
513   // Pass in either a media string or the MediaList from the CSSParser.  Don't
514   // pass both.
515   //
516   // This method will set the sheet's enabled state based on IsAlternate and co.
517   MediaMatched PrepareSheet(StyleSheet&, const nsAString& aTitle,
518                             const nsAString& aMediaString, dom::MediaList*,
519                             IsAlternate, IsExplicitlyEnabled);
520 
521   // Inserts a style sheet in a document or a ShadowRoot.
522   void InsertSheetInTree(StyleSheet& aSheet, nsINode* aOwningNode);
523   // Inserts a style sheet into a parent style sheet.
524   void InsertChildSheet(StyleSheet& aSheet, StyleSheet& aParentSheet);
525 
526   Result<RefPtr<StyleSheet>, nsresult> InternalLoadNonDocumentSheet(
527       nsIURI* aURL, StylePreloadKind, SheetParsingMode aParsingMode,
528       UseSystemPrincipal, const Encoding* aPreloadEncoding,
529       nsIReferrerInfo* aReferrerInfo, nsICSSLoaderObserver* aObserver,
530       CORSMode aCORSMode, const nsAString& aIntegrity);
531 
532   RefPtr<StyleSheet> LookupInlineSheetInCache(const nsAString&);
533 
534   // Post a load event for aObserver to be notified about aSheet.  The
535   // notification will be sent with status NS_OK unless the load event is
536   // canceled at some point (in which case it will be sent with
537   // NS_BINDING_ABORTED).
538   nsresult PostLoadEvent(RefPtr<SheetLoadData>);
539 
540   // Start the loads of all the sheets in mPendingDatas
541   void StartDeferredLoads();
542 
543   void HandleLoadEvent(SheetLoadData&);
544 
545   // Note: LoadSheet is responsible for setting the sheet to complete on
546   // failure.
547   enum class PendingLoad { No, Yes };
548   nsresult LoadSheet(SheetLoadData&, SheetState, PendingLoad = PendingLoad::No);
549 
550   enum class AllowAsyncParse {
551     Yes,
552     No,
553   };
554 
555   // Parse the stylesheet in the load data.
556   //
557   // Returns whether the parse finished. It may not finish e.g. if the sheet had
558   // an @import.
559   //
560   // If this function returns Completed::Yes, then ParseSheet also called
561   // SheetComplete on aLoadData.
562   Completed ParseSheet(const nsACString&, SheetLoadData&, AllowAsyncParse);
563 
564   // The load of the sheet in the load data is done, one way or another.
565   // Do final cleanup.
566   void SheetComplete(SheetLoadData&, nsresult);
567 
568   // Notify observers on an individual data. This is different from
569   // SheetComplete for loads that are shared.
570   void NotifyObservers(SheetLoadData&, nsresult);
571 
572   // Mark the given SheetLoadData, as well as any of its siblings, parents, etc
573   // transitively, as failed.  The idea is to mark as failed any load that was
574   // directly or indirectly @importing the sheet this SheetLoadData represents.
575   //
576   // if aOnlyForLoader is non-null, then only loads for a given loader will be
577   // marked as failing. This is useful to only cancel loads associated to a
578   // given loader, in case they were marked as canceled.
579   static void MarkLoadTreeFailed(SheetLoadData&,
580                                  Loader* aOnlyForLoader = nullptr);
581 
582   // A shorthand to mark a possible link preload as used to supress "unused"
583   // warning in the console.
584   void MaybeNotifyPreloadUsed(SheetLoadData&);
585 
586   nsRefPtrHashtable<nsStringHashKey, StyleSheet> mInlineSheets;
587 
588   // A set with all the different loads we've done in a given document, for the
589   // purpose of not posting duplicate performance entries for them.
590   nsTHashtable<const SheetLoadDataHashKey> mLoadsPerformed;
591 
592   RefPtr<SharedStyleSheetCache> mSheets;
593 
594   // The array of posted stylesheet loaded events (SheetLoadDatas) we have.
595   // Note that these are rare.
596   LoadDataArray mPostedEvents;
597 
598   // Our array of "global" observers
599   nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver>> mObservers;
600 
601   // This reference is nulled by the Document in it's destructor through
602   // DropDocumentReference().
603   dom::Document* MOZ_NON_OWNING_REF mDocument;  // the document we live for
604 
605   // For dispatching events via DocGroup::Dispatch() when mDocument is nullptr.
606   RefPtr<dom::DocGroup> mDocGroup;
607 
608   nsCompatibility mDocumentCompatMode;
609 
610   nsCOMPtr<nsIConsoleReportCollector> mReporter;
611 
612   // Number of datas for asynchronous sheet loads still waiting to be notified.
613   // This includes pending stylesheets whose load hasn't started yet but which
614   // we need to, but not inline or constructable stylesheets, though the
615   // constructable stylesheets bit may change, see bug 1642227.
616   uint32_t mOngoingLoadCount = 0;
617 
618   // The number of sheets that have been deferred / are in a pending state.
619   uint32_t mPendingLoadCount = 0;
620 
621   // The number of stylesheets that we have parsed, for testing purposes.
622   uint32_t mParsedSheetCount = 0;
623 
624   bool mEnabled = true;
625 
626 #ifdef DEBUG
627   // Whether we're in a necko callback atm.
628   bool mSyncCallback = false;
629 #endif
630 };
631 
632 }  // namespace css
633 }  // namespace mozilla
634 
635 #endif /* mozilla_css_Loader_h */
636